Mercurial > repos > rhope
annotate parser.c @ 75:0083b2f7b3c7
Partially working implementation of List. Modified build scripts to allow use of other compilers. Fixed some bugs involving method implementations on different types returning different numbers of outputs. Added Fold to the 'builtins' in the comipler.
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 06 Jul 2010 07:52:59 -0400 |
parents | 9749109b3198 |
children |
rev | line source |
---|---|
0 | 1 #include "structs.h" |
2 #include "visuality.h" | |
3 #include "debugmacros.h" | |
4 #ifdef WIN32 | |
5 #include "windows.h" | |
6 #endif | |
7 #include <stdio.h> | |
8 #include "interp.h" | |
9 #include "parser.h" | |
10 #include <string.h> | |
11 #include <stdlib.h> | |
12 | |
13 extern int num_workers; | |
14 extern int num_wires; | |
15 | |
16 /*#ifdef SEGA | |
17 #define NUM_WORKERS_START 40 | |
18 #define NUM_WIRES_START 80 | |
19 #else | |
20 #define NUM_WORKERS_START 1024 | |
21 #define NUM_WIRES_START 2048 | |
22 #endif*/ | |
23 #define NUM_WORKERS_START 20 | |
24 #define NUM_WIRES_START 40 | |
25 //TODO: Figure out why setting those defines to 16 and 32 respectively causes problems | |
26 | |
27 BOOL is_whitespace(char c) | |
28 { | |
29 if(c == ' ' || c == '\t' || c == '\n' || c == '\r') | |
30 return TRUE; | |
31 return FALSE; | |
32 } | |
33 | |
34 company * create_company(program * prog, char * name, int num_workers, int num_rooms, BOOL buildable) | |
35 { | |
36 company * this_comp = &(prog->companylist[prog->num_companies]); | |
37 DEBUGPRINTF("create_company %s with %d workers and %d rooms\n", name, num_workers, num_rooms); | |
38 this_comp->type_id = prog->num_companies++; | |
39 strncpy(this_comp->name, name, 256); | |
40 this_comp->name[255] = '\0'; | |
41 if(num_workers) | |
42 this_comp->methodlist = MALLOC(sizeof(worker_def *) * num_workers, "company methodlist"); | |
43 else | |
44 this_comp->methodlist = NULL; | |
45 this_comp->num_methods = 0;//num_workers; | |
46 this_comp->method_storage = num_workers; | |
47 if(num_rooms) | |
48 { | |
49 this_comp->room_list = MALLOC(sizeof(company_room) * num_rooms, "company roomlist"); | |
50 DEBUGPRINTF("Allocated %d bytes at %X for room_list\n", sizeof(company_room) * num_rooms, this_comp->room_list); | |
51 } | |
52 else | |
53 this_comp->room_list = NULL; | |
54 this_comp->num_rooms = 0;//num_rooms; | |
55 this_comp->room_storage = num_rooms; | |
56 if(buildable) | |
57 this_comp->build_size = 0; | |
58 else | |
59 this_comp->build_size = -1; | |
60 VIS_InitializeCriticalSection(this_comp->lock); | |
61 return this_comp; | |
62 } | |
63 | |
64 int add_method(company * this_comp, worker_def * def) | |
65 { | |
66 worker_def ** temp; | |
67 int i; | |
68 DEBUGPUTS("add_method: "); | |
69 DEBUGPRINTF("%s\n", def->name); | |
70 VIS_EnterCriticalSection(this_comp->lock); | |
71 if(this_comp->method_storage - this_comp->num_methods <= 0) | |
72 { | |
73 if(this_comp->method_storage < 2) | |
74 this_comp->method_storage = 4; | |
75 else | |
76 this_comp->method_storage = this_comp->method_storage + ((this_comp->method_storage) >> 1); | |
77 temp = MALLOC(sizeof(worker_def *) * this_comp->method_storage, "company method storage"); | |
78 for(i = 0; i < this_comp->num_methods; ++i) | |
79 temp[i] = this_comp->methodlist[i]; | |
80 VIS_FREE(this_comp->methodlist, "company methodlist"); | |
81 this_comp->methodlist = temp; | |
82 } | |
83 i = this_comp->num_methods; | |
84 this_comp->methodlist[this_comp->num_methods++] = def; | |
85 DEBUGPRINTF("%s now has %d methods\n", this_comp->name, this_comp->num_methods); | |
86 VIS_LeaveCriticalSection(this_comp->lock); | |
87 return i; | |
88 } | |
89 int room_build_sizes[] = {0, sizeof(char), sizeof(short), sizeof(long), sizeof(float), sizeof(double), -1, -1, -1, -1, -1, sizeof(datum *), 0}; | |
90 int add_comp_room(company * this_comp, char * name, int set_func, int get_func, short set_func_type, short get_func_type) | |
91 { | |
92 company_room * temp; | |
93 int i; | |
94 int min_build_size; | |
95 VIS_EnterCriticalSection(this_comp->lock); | |
96 DEBUGPRINTF("add_comp_room: %s", name); | |
97 DEBUGPRINTF(", num_rooms: %d, room_storage: %d\n", this_comp->num_rooms, this_comp->room_storage); | |
98 if(this_comp->room_storage - this_comp->num_rooms <= 0) | |
99 { | |
100 if(this_comp->room_storage < 2) | |
101 this_comp->room_storage = 4; | |
102 else | |
103 this_comp->room_storage = this_comp->room_storage + ((this_comp->room_storage) >> 1); | |
104 temp = MALLOC(sizeof(company_room) * this_comp->room_storage, "company room storage"); | |
105 memcpy(temp, this_comp->room_list, sizeof(company_room)*this_comp->num_rooms); | |
106 VIS_FREE(this_comp->room_list, "company room list"); | |
107 this_comp->room_list = temp; | |
108 } | |
109 if(this_comp->build_size >= 0) | |
110 { | |
111 DEBUGPRINTF("get_func_type: %d, room_build_sizes[%d] = %d\n", get_func_type, get_func_type, room_build_sizes[get_func_type]); | |
112 if(get_func_type && get_func_type != ROOM_WORKER && get_func == -1) | |
113 get_func = this_comp->build_size; | |
114 if(set_func_type && set_func_type != ROOM_WORKER && set_func == -1) | |
115 set_func = this_comp->build_size; | |
116 if(room_build_sizes[set_func_type]) | |
117 if(room_build_sizes[set_func_type] > room_build_sizes[get_func_type]) | |
118 min_build_size = room_build_sizes[set_func_type] + set_func; | |
119 else | |
120 min_build_size = room_build_sizes[get_func_type] + get_func; | |
121 else if(room_build_sizes[get_func_type]) | |
122 min_build_size = room_build_sizes[get_func_type] + get_func; | |
123 if(min_build_size > this_comp->build_size) | |
124 this_comp->build_size = min_build_size; | |
125 } | |
126 i = this_comp->num_rooms; | |
127 DEBUGPUTS("Copying name\n"); | |
128 this_comp->room_list[this_comp->num_rooms++].name = MALLOC(strlen(name) + 1, "company room name"); | |
129 strcpy(this_comp->room_list[i].name, name); | |
130 DEBUGPUTS("Setting func types\n"); | |
131 this_comp->room_list[i].set_func_type = set_func_type; | |
132 this_comp->room_list[i].get_func_type = get_func_type; | |
133 DEBUGPRINTF("Setting funcs: get = %d, set = %d\n", get_func, set_func); | |
134 //TODO: Change the signature of this function so that get_func and set_func are void * so we can safely pass in pointers for future get_func types | |
135 this_comp->room_list[i].get_func = (void *)get_func; | |
136 this_comp->room_list[i].set_func = (void *)set_func; | |
137 DEBUGPRINTF("Build size is now: %d\n", this_comp->build_size); | |
138 DEBUGPUTS("before return\n"); | |
139 VIS_LeaveCriticalSection(this_comp->lock); | |
140 return i; | |
141 } | |
142 | |
143 worker_def * create_worker(program * prog, char * name, int num_inputs, int num_outputs, short type) | |
144 { | |
145 custom_worker * aworker; | |
146 int i, j; | |
147 int thisdef; | |
148 worker_def * deflist; | |
149 DEBUGPRINTF("create_worker: %s with %d inputs and %d outputs\n", name, num_inputs, num_outputs); | |
150 if(!strcmp(name, "Main")) | |
151 { | |
152 thisdef = 0; | |
153 deflist = prog->defs->deflist; | |
154 } | |
155 else | |
156 { | |
157 if(prog->current->num_defs >= prog->current->defs_storage) { | |
158 prog->current->next = MALLOC(sizeof(defchunk) + (START_DEF_STORAGE - 1) * sizeof(worker_def), "worker def storage"); | |
159 prog->current = prog->current->next; | |
160 prog->current->defs_storage = START_DEF_STORAGE; | |
161 prog->current->num_defs = 0; | |
162 prog->current->next = NULL; | |
163 } | |
164 if(prog->current == prog->defs && prog->current->num_defs == 0) | |
165 prog->current->num_defs = 1; | |
166 thisdef = prog->current->num_defs; | |
167 deflist = prog->current->deflist; | |
168 } | |
169 DEBUGPRINTF("new deflist index: %d\n", thisdef); | |
170 if(type & USER_FLAG && (type & TYPE_MASK) == WORKER_TYPE) | |
171 { | |
172 //puts("Creating custom worker."); | |
173 aworker = MALLOC(sizeof(custom_worker), "custom worker implementation"); | |
174 aworker->num_workers = 0; | |
175 aworker->num_wires = 0; | |
176 aworker->workerlist = MALLOC(sizeof(worker)*NUM_WORKERS_START, "custom worker workerlist"); | |
177 aworker->worker_storage = NUM_WORKERS_START; | |
178 aworker->wirelist = MALLOC(sizeof(wire)*NUM_WIRES_START, "custom worker wirelist"); | |
179 aworker->wire_storage = NUM_WIRES_START; | |
180 aworker->workers_to_wires_up = MALLOC(sizeof(int)*(NUM_WIRES_START+1),"custom worker workers to wires up"); | |
181 aworker->workers_to_wires_down = MALLOC(sizeof(int)*(NUM_WIRES_START+1),"custom worker workers to wires down"); | |
182 aworker->dirty = TRUE; | |
183 VIS_InitializeCriticalSection(aworker->lock); | |
184 deflist[thisdef].implement_func = aworker; | |
185 } | |
186 DEBUGPUTS("Setting properties\n"); | |
187 deflist[thisdef].num_inputs = num_inputs; | |
188 deflist[thisdef].num_outputs = num_outputs; | |
189 deflist[thisdef].type = type; | |
190 DEBUGPUTS("Calling malloc\n"); | |
191 deflist[thisdef].name = MALLOC(strlen(name)+1, "worker def name"); | |
192 DEBUGPRINTF("malloc return: %X, calling strcpy\n", deflist[thisdef].name); | |
193 strcpy(deflist[thisdef].name, name); | |
194 DEBUGPUTS("strcpy done\n"); | |
195 | |
196 if(num_inputs) | |
197 deflist[thisdef].input_types = MALLOC(sizeof(short) * num_inputs, "worker def input types"); | |
198 else | |
199 deflist[thisdef].input_types = NULL; | |
200 if(num_outputs) | |
201 deflist[thisdef].output_types = MALLOC(sizeof(short) * num_outputs, "worker def output types"); | |
202 else | |
203 deflist[thisdef].output_types = NULL; | |
204 for(i = 0; i < num_inputs; ++i) | |
205 deflist[thisdef].input_types[i] = ANY_TYPE; | |
206 deflist[thisdef].num_stores = 0; | |
207 deflist[thisdef].uses_stores = NULL; | |
208 deflist[thisdef].transaction_flags = TRANSACTION_RETRY; | |
209 if(thisdef >= prog->current->num_defs) | |
210 prog->current->num_defs = thisdef+1; | |
211 for(i = 0; name[i] != '\0'; ++i) | |
212 { | |
213 if(name[i] == '@') | |
214 { | |
215 DEBUGPRINTF("Name ends in %s\n", name+i); | |
216 for(j = 0; j < prog->num_companies; ++j) | |
217 { | |
218 if(!strcmp(name+i+1, prog->companylist[j].name)) | |
219 { | |
220 DEBUGPRINTF("Worker is a method of company %d, ", j); | |
221 DEBUGPRINTF("%s\n", prog->companylist[j].name); | |
222 add_method(prog->companylist+j, deflist+thisdef); | |
223 break; | |
224 } | |
225 } | |
226 break; | |
227 } | |
228 } | |
229 deflist[thisdef].program = prog; | |
230 return deflist + thisdef; | |
231 } | |
232 | |
233 int find_worker(char * name, int * num_inputs, int * num_outputs, program * prog, worker_def ** def) | |
234 { | |
235 int i; | |
236 int term; | |
237 int len; | |
238 defchunk * current; | |
239 worker_def * temp; | |
240 DEBUGPRINTF("Calling strlen on name: %X\n", name); | |
241 len = strlen(name); | |
242 DEBUGPRINTF("find_worker: %s\n", name); | |
243 if(len >= 2 && !strcmp(name+len-2, ">>")) | |
244 { | |
245 DEBUGPUTS("Get property\n"); | |
246 term = len-2; | |
247 for(i = term-1; i > 0; --i) | |
248 { | |
249 if(name[i] == ' ') | |
250 term = i; | |
251 else | |
252 break; | |
253 } | |
254 DEBUGPRINTF("term: %d\n", term); | |
255 name[term] = '\0'; | |
256 DEBUGPRINTF("name: %s\n", name); | |
257 if(num_inputs); | |
258 *num_inputs = 1; | |
259 if(num_outputs) | |
260 *num_outputs = 1; | |
261 return -1; | |
262 } | |
263 if(len >= 2 && !strcmp(name+len-2, "<<")) | |
264 { | |
265 DEBUGPUTS("Set property\n"); | |
266 term = len-2; | |
267 for(i = term-1; i > 0; --i) | |
268 { | |
269 if(name[i] == ' ') | |
270 term = i; | |
271 else | |
272 break; | |
273 } | |
274 DEBUGPRINTF("term: %d\n", term); | |
275 name[term] = '\0'; | |
276 DEBUGPRINTF("name: %s\n", name); | |
277 if(num_inputs); | |
278 *num_inputs = 2; | |
279 if(num_outputs) | |
280 *num_outputs = 1; | |
281 return -2; | |
282 } | |
283 current = prog->defs; | |
284 while(current) | |
285 { | |
286 for(i = 0; i < current->num_defs; ++i) | |
287 { | |
288 if(current->deflist[i].name && !strcmp(current->deflist[i].name, name)) | |
289 { | |
290 DEBUGPRINTF("Found worker #%d\n", i); | |
291 if(num_inputs) | |
292 *num_inputs = current->deflist[i].num_inputs; | |
293 if(num_outputs) | |
294 *num_outputs = current->deflist[i].num_outputs; | |
295 if(def) | |
296 *def = current->deflist + i; | |
297 return i; | |
298 } | |
299 } | |
300 current = current->next; | |
301 } | |
302 if(num_inputs && num_outputs) | |
303 { | |
304 for(i = 1; i < prog->num_companies; ++i) | |
305 { | |
306 temp = find_method(i, name, *num_inputs, prog); | |
307 if(temp && temp->num_outputs >= *num_outputs) | |
308 { | |
309 *def = create_worker(prog, name, temp->num_inputs, temp->num_outputs, MAGIC_TYPE); | |
310 return 1; | |
311 } | |
312 } | |
313 } | |
314 else | |
315 { | |
316 for(i = 1; i < prog->num_companies; ++i) | |
317 { | |
318 temp = find_method_noinputcheck(i, name, prog); | |
319 if(temp) | |
320 { | |
321 *def = create_worker(prog, name, temp->num_inputs, temp->num_outputs, MAGIC_TYPE); | |
322 return 1; | |
323 } | |
324 } | |
325 } | |
326 DEBUGPUTS("Could not find worker\n"); | |
327 return -3; | |
328 } | |
329 | |
330 int generic_add_to_def(worker_def * parent, char * name,int display_type, int type, int num_inputs, int num_outputs, double xpos, double ypos) | |
331 { | |
332 int returnval; | |
333 worker * temp; | |
334 VIS_EnterCriticalSection(parent->implement_func->lock); | |
335 if(parent->implement_func->num_workers >= parent->implement_func->worker_storage) { | |
336 parent->implement_func->worker_storage = parent->implement_func->num_workers + (parent->implement_func->num_workers >> 1); | |
337 parent->implement_func->workerlist = realloc(parent->implement_func->workerlist, parent->implement_func->worker_storage * sizeof(worker)); | |
338 } | |
339 strcpy(parent->implement_func->workerlist[parent->implement_func->num_workers].name, name); | |
340 parent->implement_func->workerlist[parent->implement_func->num_workers].type=type; | |
341 parent->implement_func->workerlist[parent->implement_func->num_workers].num_inputs = num_inputs; | |
342 parent->implement_func->workerlist[parent->implement_func->num_workers].num_outputs = num_outputs; | |
343 parent->implement_func->workerlist[parent->implement_func->num_workers].null_input = FALSE; | |
344 parent->implement_func->workerlist[parent->implement_func->num_workers].magic_cache_implement = NULL; | |
345 parent->implement_func->workerlist[parent->implement_func->num_workers].magic_cache_type = 0; | |
346 VIS_InitializeCriticalSection(parent->implement_func->workerlist[parent->implement_func->num_workers].lock); | |
347 parent->implement_func->dirty = TRUE; | |
348 //puts("end generic_add_to_def"); | |
349 DEBUGPRINTF("generic_add_to_def: %s with type %d and num_inputs %d and num_outputs %d returned %d\n", name, type, num_inputs, num_outputs, parent->implement_func->num_workers); | |
350 returnval = parent->implement_func->num_workers++; | |
351 VIS_LeaveCriticalSection(parent->implement_func->lock); | |
352 return returnval; | |
353 } | |
354 | |
355 int add_worker_to_def(worker_def * parent, worker_def * worker, double xpos, double ypos) | |
356 { | |
357 int list_index; | |
358 list_index = generic_add_to_def(parent, worker->name, TRAPEZOID, WORKER, worker->num_inputs, worker->num_outputs, xpos, ypos); | |
359 | |
360 parent->implement_func->workerlist[list_index].value_index = worker; | |
361 return list_index; | |
362 } | |
363 | |
364 int add_get_comp_room(worker_def * parent, char * name, double xpos, double ypos) | |
365 { | |
366 return generic_add_to_def(parent, name, RECTANGLE, GET_COMP, 1, 2, xpos, ypos); | |
367 } | |
368 | |
369 int add_set_comp_room(worker_def * parent, char * name, double xpos, double ypos) | |
370 { | |
371 return generic_add_to_def(parent, name, RECTANGLE, SET_COMP, 2, 1, xpos, ypos); | |
372 } | |
373 | |
374 int add_global(worker_def * parent, char * name, double xpos, double ypos, int type) | |
375 { | |
376 int i,j; | |
377 int thisdef; | |
378 int num_in, num_out; | |
379 if(type == SET_GLOBAL) | |
380 { | |
381 num_in = 1; | |
382 num_out = 0; | |
383 parent->transaction_flags |= TRANSACTION_WRITE; | |
384 } | |
385 else | |
386 { | |
387 num_in = 0; | |
388 num_out = 1; | |
389 } | |
390 thisdef = generic_add_to_def(parent, name, RECTANGLE, type, num_in, num_out, xpos, ypos); | |
391 for(i = 0; name[i+1] != '\0'; ++i) | |
392 { | |
393 if(name[i] == ':' && name[i+1] == ':') | |
394 { | |
395 parent->implement_func->workerlist[thisdef].value_index = (void *)-1; | |
396 if(i > 0) | |
397 { | |
398 for(j = 0; j < parent->num_stores; ++j) | |
399 { | |
400 if(strlen(parent->uses_stores[j]) == i && !memcmp(parent->uses_stores[j], name, i)) | |
401 { | |
402 parent->implement_func->workerlist[thisdef].value_index = (void *)j; | |
403 break; | |
404 } | |
405 } | |
406 if(parent->implement_func->workerlist[thisdef].value_index < 0) | |
407 { | |
408 name[i] = '\0'; | |
409 printf("Error: Worker %s is not declared to use global store %s but references it.\n", parent->name, name); | |
410 exit(-1); | |
411 } | |
412 } | |
413 else if(type == SET_GLOBAL) | |
414 parent->implement_func->workerlist[thisdef].value_index = 0; | |
415 parent->implement_func->workerlist[thisdef].io_num = i+2; | |
416 break; | |
417 } | |
418 } | |
419 return thisdef; | |
420 } | |
421 | |
422 int add_global_get(worker_def * parent, char * name, double xpos, double ypos) | |
423 { | |
424 return add_global(parent, name, xpos, ypos, GET_GLOBAL); | |
425 } | |
426 | |
427 int add_global_set(worker_def * parent, char * name, double xpos, double ypos) | |
428 { | |
429 return add_global(parent, name, xpos, ypos, SET_GLOBAL); | |
430 } | |
431 | |
432 int find_object(worker_def * def, char * name, int type) | |
433 { | |
434 int i; | |
435 for(i = 0; i < def->implement_func->num_workers; ++i) | |
436 if(!strcmp(def->implement_func->workerlist[i].name, name) && def->implement_func->workerlist[i].type == 1) | |
437 break; | |
438 if(i < def->implement_func->num_workers) | |
439 return i; | |
440 return -1; | |
441 } | |
442 | |
443 int create_find_room(worker_def * def, char * name, double xpos, double ypos) | |
444 { | |
445 int found = find_object(def, name, ROOM); | |
446 if(found >= 0) | |
447 return found; | |
448 return generic_add_to_def(def, name, RECTANGLE, ROOM, 1, 1, xpos, ypos); | |
449 } | |
450 | |
451 int add_constant(worker_def * def, char * value, double xpos, double ypos) | |
452 { | |
453 int index = generic_add_to_def(def, value, RECTANGLE, CONSTANT, 0, 1, xpos, ypos); | |
454 def->implement_func->workerlist[index].value_index = get_constant(value, -1, def->program); | |
455 return index; | |
456 } | |
457 | |
458 int add_input_num(worker_def * def, char * name, int input_num, double xpos, double ypos) | |
459 { | |
460 int i; | |
461 unsigned short * temp_types; | |
462 int found; | |
463 if(def->num_inputs <= input_num) | |
464 { | |
465 temp_types = def->input_types; | |
466 def->input_types = MALLOC(sizeof(short)*(input_num+1), "worker def input types"); | |
467 if(temp_types) { | |
468 memcpy(def->input_types, temp_types, sizeof(short)*def->num_inputs); | |
469 VIS_FREE(temp_types, "temp types?"); | |
470 } | |
471 for(i = def->num_inputs; i <= input_num; ++i) | |
472 def->input_types[i] = ANY_TYPE; | |
473 def->num_inputs = input_num+1; | |
474 } | |
475 found = generic_add_to_def(def, name, RECTANGLE, INPUT, 0, 1, xpos, ypos); | |
476 def->implement_func->workerlist[found].io_num = input_num; | |
477 return found; | |
478 } | |
479 int add_input(worker_def * def, char * name, double xpos, double ypos) | |
480 { | |
481 | |
482 int input_num; | |
483 int i; | |
484 for(i = 0; name[i] != 0; ++i) | |
485 if(name[i] == '(') | |
486 { | |
487 input_num = atol(name+i+1); | |
488 break; | |
489 } | |
490 return add_input_num(def, name, input_num, xpos, ypos); | |
491 } | |
492 | |
493 int add_output_num(worker_def * def, char * name, int output_num, double xpos, double ypos) | |
494 { | |
495 int i; | |
496 unsigned short * temp_types; | |
497 int found; | |
498 if(def->num_outputs <= output_num) | |
499 { | |
500 temp_types = def->output_types; | |
501 def->output_types = MALLOC(sizeof(short)*(output_num+1), "worker def output types"); | |
502 if(temp_types) | |
503 { | |
504 memcpy(def->output_types, temp_types, sizeof(short)*def->num_outputs); | |
505 VIS_FREE(temp_types, "temp types?"); | |
506 } | |
507 for(i = def->num_outputs; i <= output_num; ++i) | |
508 def->output_types[i] = ANY_TYPE; | |
509 def->num_outputs = output_num+1; | |
510 } | |
511 found = generic_add_to_def(def, name, RECTANGLE, OUTPUT, 1, 0, xpos, ypos); | |
512 def->implement_func->workerlist[found].io_num = output_num; | |
513 return found; | |
514 } | |
515 int add_output(worker_def * def, char * name, double xpos, double ypos) | |
516 { | |
517 int output_num; | |
518 int i; | |
519 | |
520 for(i = 0; name[i] != 0; ++i) | |
521 if(name[i] == '(') | |
522 { | |
523 output_num = atol(name+i+1); | |
524 break; | |
525 } | |
526 return add_output_num(def, name, output_num, xpos, ypos); | |
527 } | |
528 | |
529 int create_find_output(worker_def * def, char * name, double xpos, double ypos) | |
530 { | |
531 int output_num; | |
532 int i; | |
533 unsigned short * temp_types; | |
534 int found = find_object(def, name, OUTPUT); | |
535 if(found >= 0) | |
536 return found; | |
537 return add_output(def, name, xpos, ypos); | |
538 } | |
539 | |
540 void add_wire(worker_def * def, int start, int output_num, int end, int input_num) | |
541 { | |
542 VIS_EnterCriticalSection(def->implement_func->lock); | |
543 if(def->implement_func->num_wires >= def->implement_func->wire_storage) { | |
544 def->implement_func->wire_storage = def->implement_func->num_wires + (def->implement_func->num_wires >> 1); | |
545 def->implement_func->wirelist = realloc(def->implement_func->wirelist, def->implement_func->wire_storage * sizeof(wire)); | |
546 def->implement_func->workers_to_wires_up = realloc(def->implement_func->workers_to_wires_up, (def->implement_func->wire_storage+1) * sizeof(int)); | |
547 def->implement_func->workers_to_wires_down = realloc(def->implement_func->workers_to_wires_down, (def->implement_func->wire_storage+1) * sizeof(int)); | |
548 } | |
549 def->implement_func->wirelist[def->implement_func->num_wires].start_worker = start; | |
550 def->implement_func->wirelist[def->implement_func->num_wires].end_worker = end; | |
551 def->implement_func->wirelist[def->implement_func->num_wires].output_num = output_num; | |
552 def->implement_func->wirelist[def->implement_func->num_wires].input_num = input_num; | |
553 def->implement_func->dirty = TRUE; | |
554 ++def->implement_func->num_wires; | |
555 if(input_num == -1) | |
556 { | |
557 def->implement_func->workerlist[end].null_input = TRUE; | |
558 } | |
559 VIS_LeaveCriticalSection(def->implement_func->lock); | |
560 } | |
561 | |
562 int process_expression(worker_def * def, int num_outputs, char ** outvars, int num_inputs, char ** inputs, char * workername, BOOL worker_expr, int block_depth, int * block_workers, int * block_output, int last_worker) | |
563 { | |
564 int i,j; | |
565 int current; | |
566 int this_worker;// = ++return_worker; | |
567 int expected_in, expected_out; | |
568 int input_num=-1; | |
569 int worker_num; | |
570 worker_def * call_def; | |
571 BOOL block_attach=FALSE; | |
572 BOOL room = FALSE; | |
573 BOOL global_flag; | |
574 if(worker_expr) | |
575 { | |
576 DEBUGPUTS("calling find_worker\n"); | |
577 expected_in = num_inputs; | |
578 expected_out = num_outputs; | |
579 worker_num = find_worker(workername, &expected_in, &expected_out, def->program, &call_def); | |
580 DEBUGPRINTF("\nWorker %s with %d inputs and %d outputs expects %d inputs and %d outputs\n", workername, num_inputs, num_outputs, expected_in, expected_out); | |
581 if(worker_num >= 0) | |
582 this_worker = add_worker_to_def(def, call_def, 1.0, 1.0); | |
583 else if(worker_num == -1) | |
584 this_worker = add_get_comp_room(def, workername, 1.0, 1.0); | |
585 else if(worker_num == -2) | |
586 this_worker = add_set_comp_room(def, workername, 1.0, 1.0); | |
587 else | |
588 { | |
589 ERRORPRINTF("Could not find a worker named %s or a method of the same name with %d inputs and at least %d outputs\n", workername, num_inputs, num_outputs); | |
590 for(i = 0; i < num_inputs; ++i) | |
591 { | |
592 ERRORPRINTF("Input %d was %s\n", i, inputs[i]); | |
593 } | |
594 exit(-1); | |
595 } | |
596 } | |
597 else | |
598 { | |
599 if(workername[0] == '{' || workername[0] == '"' || (workername[0] >= '0' && workername[0] <= '9') || strcmp(workername, "Yes") == 0 || strcmp(workername, "No") == 0) | |
600 { | |
601 //Constant expression | |
602 this_worker = add_constant(def, workername, 1.0, 1.0); | |
603 } | |
604 /*else if(workername[0] == '"') | |
605 { | |
606 //printf("\nString %s\n", workername); | |
607 workername[strlen(workername)-1] = '\0'; | |
608 this_worker = add_constant(def, workername+1, 1.0, 1.0); | |
609 } | |
610 else if(workername[0] >= '0' && workername[0] <= '9') | |
611 { | |
612 //printf("\nNumber %s\n", workername); | |
613 this_worker = add_constant(def, workername, 1.0, 1.0); | |
614 } | |
615 else if(strcmp(workername, "Yes") == 0 || strcmp(workername, "No") == 0) | |
616 { | |
617 this_worker = add_constant(def, workername, 1.0, 1.0); | |
618 }*/ | |
619 else | |
620 { | |
621 for(i = 0; workername[i] != 0; ++i) | |
622 if(workername[i] == '(') | |
623 { | |
624 input_num = atol(workername + i+1); | |
625 break; | |
626 } | |
627 if(input_num >= 0) | |
628 { | |
629 //printf("\nInput %d %s\n", input_num, workername); | |
630 this_worker = add_input(def, workername, 1.0, 1.0); | |
631 } | |
632 else | |
633 { | |
634 room = TRUE; | |
635 //printf("\nRoom %s\n", workername); | |
636 for(i = 0; i < strlen(workername)-1; ++i) | |
637 { | |
638 if(workername[i] == ':' && workername[i+1] == ':') | |
639 { | |
640 room = FALSE; | |
641 break; | |
642 } | |
643 } | |
644 if(room) | |
645 this_worker = create_find_room(def, workername, 1.0, 1.0); | |
646 else | |
647 this_worker = add_global_get(def, workername, 1.0, 1.0); | |
648 | |
649 } | |
650 } | |
651 } | |
652 for(i = 0; i < num_inputs; ++i) | |
653 if(inputs[i]) | |
654 { | |
655 if(!strcmp(inputs[i], "~")) | |
656 { | |
657 //printf("Input %d = ~ (parent block)\n", i); | |
658 if(!block_depth) | |
659 { | |
660 printf("Error: Reference to parent block (~) for input %d of worker %s, but block depth is 0", i, workername); | |
661 exit(-2); | |
662 } | |
663 add_wire(def, block_workers[block_depth-1], block_output[block_depth-1], this_worker, i); | |
664 block_attach = TRUE; | |
665 } | |
666 else | |
667 { | |
668 DEBUGPRINTF("Processing input %d (%s)\n", i, inputs[i]); | |
669 if(block_depth) | |
670 current = parse_body(def, inputs[i], strlen(inputs[i]), block_depth, block_output, block_workers); | |
671 else | |
672 current = parse_body(def, inputs[i], strlen(inputs[i]), 0, NULL, NULL); | |
673 add_wire(def, current, 0, this_worker, i); | |
674 } | |
675 } | |
676 else | |
677 { | |
678 //printf("Input %d = last_worker(%d)\n", i, last_worker); | |
679 add_wire(def, last_worker, 0, this_worker, i); | |
680 } | |
681 for(i = 0; i < num_outputs; ++i) | |
682 { | |
683 global_flag = FALSE; | |
684 //printf("Output %d = %s\n", i, outvars[i]); | |
685 for(j = 0; outvars[i][j] != '\0'; ++j) | |
686 if(outvars[i][j] == '(') | |
687 break; | |
688 else if(outvars[i][j] == ':' && outvars[i][j+1] == ':') | |
689 break; | |
690 if(outvars[i][j] == '\0') | |
691 current = create_find_room(def, outvars[i], 2.0, 2.0); | |
692 else if(outvars[i][j] == ':') | |
693 current = add_global_set(def, outvars[i], 2.0, 2.0); | |
694 else | |
695 current = create_find_output(def, outvars[i], 2.0, 2.0); | |
696 add_wire(def, this_worker, i, current, 0); | |
697 } | |
698 | |
699 //printf("Current blockdepth: %d\n", block_depth); | |
700 if(block_depth > 0) | |
701 { | |
702 //printf("Block Worker: %d\nBlock Output: %d\n", block_workers[block_depth-1], block_output[block_depth-1]); | |
703 if(worker_expr && num_inputs < expected_in) | |
704 { | |
705 if(block_attach) | |
25
9749109b3198
Fixed spelling error in parser error message.
William Morgan <wbm25+rhopehg@drexel.edu>
parents:
0
diff
changeset
|
706 printf("Warning: Worker %s is attached to block both explicitly and implicitly (i.e. at least one input was stated as ~, but there are still unsatisfied inputs)\n", workername); |
0 | 707 if(expected_in - num_inputs > 1) |
708 printf("Warning: More than one input of worker %s implicitly tied to block (%d inputs implicitly tied)", workername, expected_in - num_inputs); | |
709 for(i = num_inputs; i < expected_in; ++i) | |
710 add_wire(def, block_workers[block_depth-1], block_output[block_depth-1], this_worker, i); | |
711 | |
712 } | |
713 else if(!block_attach && !room) | |
714 { | |
715 add_wire(def, block_workers[block_depth-1], block_output[block_depth-1], this_worker, -1); | |
716 //def->implement_func->workerlist[this_worker].null_input = TRUE; | |
717 } | |
718 } | |
719 else if(worker_expr && num_inputs < expected_in) | |
720 { | |
721 ERRORPRINTF("Error: Worker %s expects %d input(s), but was only given %d input(s)\n", workername, expected_in, num_inputs); | |
722 exit(-1); | |
723 } | |
724 //printf("Returning %d\n\n", this_worker); | |
725 return this_worker; | |
726 } | |
727 typedef enum {NULL_STATE, OUT_STATE, BETWEEN_OUT, BEFORE_WORK, PRE_IN_STATE, BETWEEN_PRE_IN, WORK_STATE, IN_STATE, BETWEEN_IN, AFTER_IN, BLOCK_FIND, LINE_COMMENT_STATE} parse_state; | |
728 char state_txt[12][20] = {"Null","Out","Between Out","Before Work","Pre Input","Between Pre-Input","Worker","Input","Between Input","After Input","Block Find"}; | |
729 int parse_body(worker_def * def, char * code, int len, int prev_block_depth, int * prev_block_output, int * prev_block_workers) | |
730 { | |
731 char * outputs[32]; | |
732 char * inputs[32]; | |
733 char * worker; | |
734 short saw_line=0; | |
735 int num_inputs=0, num_outputs=0; | |
736 int left_bracket=0; | |
737 int left_curly=0; | |
738 int block_depth = 0; | |
739 int block_workers[32]; | |
740 int block_output[32]; | |
741 int last_worker = 0; | |
742 BOOL worker_expr = FALSE; | |
743 BOOL in_string = FALSE; | |
744 BOOL literal = FALSE; | |
745 BOOL do_curly = FALSE; | |
746 BOOL saw_newline = FALSE; | |
747 int i,j; | |
748 int start; | |
749 int line_comment_start; | |
750 parse_state state = NULL_STATE; | |
751 parse_state old_state; | |
752 DEBUGPRINTF("code: %X\n", code); | |
753 //printf("prev_block_depth: %d\n", prev_block_depth); | |
754 for(i=0; i < len; ++i) | |
755 { | |
756 //printf("i: %d, code[i]: '%c', state: %s(%d)\n", i, code[i], state_txt[state],state); | |
757 DEBUGPRINTF("i: %d, code[i]: '%c', state: %s(%d), left_bracket: %d, num_inputs: %d\n", i, code[i], state_txt[state],state, left_bracket, num_inputs); | |
758 if(!in_string) | |
759 { | |
760 if(state != LINE_COMMENT_STATE) | |
761 { | |
762 if(code[i] == '/' && code[i+1] == '/') | |
763 { | |
764 old_state = state; | |
765 state = LINE_COMMENT_STATE; | |
766 line_comment_start = i; | |
767 i += 2; | |
768 } | |
769 else if(code[i] == '[') | |
770 ++left_bracket; | |
771 else if(code[i] == ']') | |
772 --left_bracket; | |
773 else if(code[i] == '{') | |
774 do_curly = TRUE; | |
775 else if(code[i] == '}') | |
776 --left_curly; | |
777 else if(code[i] == '"') | |
778 { | |
779 in_string = TRUE; | |
780 //continue; | |
781 } | |
782 } | |
783 if(left_curly == 0) | |
784 { | |
785 switch(state) | |
786 { | |
787 case NULL_STATE: | |
788 | |
789 if(code[i] == '[') | |
790 { | |
791 //puts("worker_expr = TRUE"); | |
792 worker_expr = TRUE; | |
793 state = BETWEEN_PRE_IN; | |
794 } | |
795 else if(code[i] == ':' && code[i+1] == '|') | |
796 { | |
797 ++i; | |
798 state = BLOCK_FIND; | |
799 } | |
800 else if(code[i] == '|' && code[i+1] == ':') | |
801 { | |
802 block_workers[block_depth] = last_worker; | |
803 block_output[block_depth++] = 0; | |
804 //puts("Found |: increasing block depth"); | |
805 ++i; | |
806 } | |
807 else if(!is_whitespace(code[i])) | |
808 { | |
809 start = i; | |
810 for(j = i; j < len-1; ++j) | |
811 if(code[j] == '<' && code[j+1] == '-') | |
812 { | |
813 state = OUT_STATE; | |
814 --i; | |
815 break; | |
816 } | |
817 else if(code[j] == '[' || code[j] == '\n' || (code[j] == '|' && code[j+1] == ':') || code[j] == '#' || code[j] == '"') | |
818 { | |
819 state = WORK_STATE; | |
820 break; | |
821 } | |
822 if(state == NULL_STATE) | |
823 state = WORK_STATE; | |
824 } | |
825 break; | |
826 case OUT_STATE: | |
827 if(code[i] == ',' || (code[i] == '<' && code[i+1] == '-')) | |
828 { | |
829 outputs[num_outputs++] = code + start; | |
830 for(j = i-1; j > start; --j) | |
831 if(!is_whitespace(code[j])) | |
832 break; | |
833 if(code[i] == ',') | |
834 state = BETWEEN_OUT; | |
835 else | |
836 { | |
837 state = BEFORE_WORK; | |
838 ++i; | |
839 } | |
840 code[j+1] = '\0'; | |
841 } | |
842 break; | |
843 case BETWEEN_OUT: | |
844 if(!is_whitespace(code[i])) | |
845 { | |
846 start = i; | |
847 state = OUT_STATE; | |
848 --i; | |
849 } | |
850 break; | |
851 case BEFORE_WORK: | |
852 if(code[i] == '[') | |
853 { | |
854 //puts("worker_expr = TRUE"); | |
855 worker_expr = TRUE; | |
856 state = BETWEEN_PRE_IN; | |
857 } | |
858 else if(code[i] == ':' && code[i+1] == '|') | |
859 { | |
860 start = i; | |
861 while(i < len && (code[i] != '\n' || saw_line < 5)) | |
862 { | |
863 if(code[i] == '\n') | |
864 ++saw_line; | |
865 ++i; | |
866 } | |
867 code[i] = '\0'; | |
868 ERRORPRINTF("Error: Expected a worker name, but found a closing bracket (:|) instead at:\n%s", code + start); | |
869 exit(-1); | |
870 } | |
871 else if(!is_whitespace(code[i])) | |
872 { | |
873 start = i; | |
874 state = WORK_STATE; | |
875 } | |
876 break; | |
877 case PRE_IN_STATE: | |
878 if((code[i] == ',' && left_bracket == 1) || (code[i] == ']' && left_bracket == 0) ) | |
879 { | |
880 inputs[num_inputs++] = code + start; | |
881 for(j = i-1; j > start; --j) | |
882 if(!is_whitespace(code[j])) | |
883 break; | |
884 if(code[i] == ',') | |
885 state = BETWEEN_PRE_IN; | |
886 else | |
887 state = BEFORE_WORK; | |
888 code[j+1] = '\0'; | |
889 } | |
890 break; | |
891 case BETWEEN_PRE_IN: | |
892 if(code[i] == ']') | |
893 { | |
894 state = BEFORE_WORK; | |
895 } | |
896 else if(!is_whitespace(code[i])) | |
897 { | |
898 start = i; | |
899 state = PRE_IN_STATE; | |
900 } | |
901 break; | |
902 case WORK_STATE: | |
903 if(code[i] == '[' || code[i] == '#' || (code[i] == '|' && code[i+1] == ':') || (code[i] == ':' && code[i+1] == '|') || code[i] == '\n') | |
904 { | |
905 for(j = i-1; j > start; --j) | |
906 if(!is_whitespace(code[j])) | |
907 break; | |
908 | |
909 worker = code+start; | |
910 | |
911 if(code[i] == '[') | |
912 { | |
913 code[j+1] = '\0'; | |
914 // puts("Worker to Between Input"); | |
915 // puts("worker_expr = TRUE;"); | |
916 worker_expr = TRUE; | |
917 state = BETWEEN_IN; | |
918 } | |
919 else if(code[i] == '#' || code[i] == '\n') | |
920 { | |
921 code[j+1] = '\0'; | |
922 // puts("Worker to Null State(#)"); | |
923 //printf("worker_expr: %d\n", worker_expr); | |
924 if(block_depth) | |
925 last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker); | |
926 else | |
927 last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker); | |
928 num_inputs = 0; | |
929 num_outputs = 0; | |
930 worker_expr = FALSE; | |
931 state = NULL_STATE; | |
932 } | |
933 else if(code[i] == ':') | |
934 { | |
935 code[j+1] = '\0'; | |
936 if(block_depth) | |
937 last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker); | |
938 else | |
939 last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker); | |
940 num_inputs = 0; | |
941 num_outputs = 0; | |
942 worker_expr = FALSE; | |
943 state = BLOCK_FIND; | |
944 ++i; | |
945 } | |
946 else | |
947 { | |
948 //puts("Worker to Null State(else)"); | |
949 code[j+1] = '\0'; | |
950 if(block_depth) | |
951 last_worker = block_workers[block_depth] = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker); | |
952 else | |
953 last_worker = block_workers[block_depth] = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker); | |
954 block_output[block_depth++] = 0; | |
955 //puts("Found |:, increasinb block depth"); | |
956 num_inputs = 0; | |
957 num_outputs = 0; | |
958 worker_expr = FALSE; | |
959 state = NULL_STATE; | |
960 ++i; | |
961 } | |
962 | |
963 } | |
964 break; | |
965 case BETWEEN_IN: | |
966 if(code[i] == ']') | |
967 { | |
968 state = AFTER_IN; | |
969 } | |
970 else if(!is_whitespace(code[i])) | |
971 { | |
972 start = i; | |
973 state = IN_STATE; | |
974 } | |
975 break; | |
976 case IN_STATE: | |
977 if((code[i] == ',' && left_bracket == 1) || (code[i] == ']' && left_bracket == 0) ) | |
978 { | |
979 inputs[num_inputs++] = code + start; | |
980 for(j = i-1; j > start; --j) | |
981 if(!is_whitespace(code[j])) | |
982 break; | |
983 | |
984 if(code[i] == ',') | |
985 state = BETWEEN_IN; | |
986 else | |
987 state = AFTER_IN; | |
988 code[j+1] = '\0'; | |
989 } | |
990 break; | |
991 case AFTER_IN: | |
992 //puts("AFTER_IN test"); | |
993 if(code[i] == '\n') | |
994 saw_newline = TRUE; | |
995 if(code[i] == '|' && code[i+1] == ':') | |
996 { | |
997 if(block_depth) | |
998 last_worker = block_workers[block_depth] = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker); | |
999 else | |
1000 last_worker = block_workers[block_depth] = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker); | |
1001 block_output[block_depth++] = 0; | |
1002 //puts("Found |: increasing block depth"); | |
1003 state = NULL_STATE; | |
1004 num_inputs = 0; | |
1005 num_outputs = 0; | |
1006 worker_expr = FALSE; | |
1007 ++i; | |
1008 } | |
1009 else if(code[i] == '#') | |
1010 { | |
1011 if(block_depth) | |
1012 last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker); | |
1013 else | |
1014 last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker); | |
1015 state = NULL_STATE; | |
1016 num_inputs = 0; | |
1017 num_outputs = 0; | |
1018 worker_expr = FALSE; | |
1019 } | |
1020 else if(code[i] == '[') | |
1021 { | |
1022 if(saw_newline) | |
1023 { | |
1024 if(block_depth) | |
1025 last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker); | |
1026 else | |
1027 last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker); | |
1028 saw_newline = FALSE; | |
1029 state = NULL_STATE; | |
1030 num_inputs = 0; | |
1031 num_outputs = 0; | |
1032 worker_expr = FALSE; | |
1033 --left_bracket; | |
1034 --i; | |
1035 } | |
1036 else | |
1037 { | |
1038 puts("Error: Too many input blocks at"); | |
1039 code[i+1] = '\0'; | |
1040 for(j = i-1; j > 0; --j) | |
1041 if(code[j] == '\n') | |
1042 { | |
1043 ++j; | |
1044 break; | |
1045 } | |
1046 puts(code + j); | |
1047 exit(-1); | |
1048 } | |
1049 } | |
1050 else if(!is_whitespace(code[i])) | |
1051 { | |
1052 if(block_depth) | |
1053 last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker); | |
1054 else | |
1055 last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker); | |
1056 if(saw_newline) | |
1057 { | |
1058 saw_newline = FALSE; | |
1059 num_inputs = 0; | |
1060 } | |
1061 else | |
1062 { | |
1063 num_inputs = 1; | |
1064 inputs[0] = NULL; | |
1065 } | |
1066 state = NULL_STATE; | |
1067 | |
1068 num_outputs = 0; | |
1069 worker_expr = FALSE; | |
1070 --i; | |
1071 } | |
1072 break; | |
1073 case BLOCK_FIND: | |
1074 if(code[i] == '|' && code[i+1] == ':') | |
1075 { | |
1076 //puts("Found |: increasing output number (not block depth)"); | |
1077 ++block_output[block_depth-1]; | |
1078 ++i; | |
1079 state = NULL_STATE; | |
1080 } | |
1081 else if(!is_whitespace(code[i])) | |
1082 { | |
1083 //puts("Found :| without another |: following; decreasing block depth"); | |
1084 --block_depth; | |
1085 if(code[i] == '[') | |
1086 --left_bracket; | |
1087 --i; | |
1088 num_inputs = 0; | |
1089 state = NULL_STATE; | |
1090 | |
1091 } | |
1092 break; | |
1093 case LINE_COMMENT_STATE: | |
1094 if(code[i+1] == '\n') | |
1095 { | |
1096 for(;line_comment_start <= i; ++line_comment_start) | |
1097 code[line_comment_start] = ' '; | |
1098 state = old_state; | |
1099 } | |
1100 break; | |
1101 } | |
1102 } | |
1103 if(do_curly) | |
1104 { | |
1105 ++left_curly; | |
1106 do_curly = FALSE; | |
1107 } | |
1108 } | |
1109 else if(literal) | |
1110 literal = FALSE; | |
1111 else if(code[i] == '"') | |
1112 in_string = FALSE; | |
1113 else if(code[i] == '\\') | |
1114 literal = TRUE; | |
1115 } | |
1116 //printf("State at end of code chunk: %s(%d)\n", state_txt[state], state); | |
1117 if((state != BLOCK_FIND && block_depth != 0) || (state == BLOCK_FIND && block_depth > 1)) | |
1118 { | |
1119 ERRORPRINTF("Syntax Error: Missing %d block close symbol(s) (:|)\n", block_depth); | |
1120 exit(-1); | |
1121 } | |
1122 else | |
1123 { | |
1124 switch(state) | |
1125 { | |
1126 case WORK_STATE: | |
1127 for(j = i-1; j > start; --j) | |
1128 if(!is_whitespace(code[j])) | |
1129 break; | |
1130 | |
1131 worker = code+start; | |
1132 code[j+1] = '\0'; | |
1133 case AFTER_IN: | |
1134 if(block_depth) | |
1135 last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, block_depth, block_workers, block_output, last_worker); | |
1136 else | |
1137 last_worker = process_expression(def, num_outputs, outputs, num_inputs, inputs, worker, worker_expr, prev_block_depth, prev_block_workers, prev_block_output, last_worker); | |
1138 break; | |
1139 case BLOCK_FIND: | |
1140 case NULL_STATE: | |
1141 break; | |
1142 default: | |
1143 printf("Syntax Error: State is %s but there are no more characters left to process.\n", state_txt[state]); | |
1144 puts(code + start); | |
1145 exit(-1); | |
1146 } | |
1147 } | |
1148 return last_worker; | |
1149 } | |
1150 typedef struct parse_worker | |
1151 { | |
1152 char * worker_name; | |
1153 int num_inputs; | |
1154 int num_outputs; | |
1155 worker_def * def; | |
1156 char * block; | |
1157 int block_len; | |
1158 struct parse_worker * next; | |
1159 } parse_worker; | |
1160 | |
1161 void parse_company(char * name, char * code, int len, program * prog) | |
1162 { | |
1163 char * type_name; | |
1164 char * field_name; | |
1165 int i; | |
1166 int part_start; | |
1167 int part_end; | |
1168 int type; | |
1169 company * comp; | |
1170 BOOL saw_newline; | |
1171 field_name = type_name = NULL; | |
1172 comp = create_company(prog, name, 0, 0, TRUE); | |
1173 i = 0; | |
1174 while(i < len) | |
1175 { | |
1176 saw_newline = FALSE; | |
1177 part_start = -1; | |
1178 for(; i < len; ++i) | |
1179 { | |
1180 DEBUGPRINTF("i: %d, code[i]: %c ", i, code[i]); | |
1181 if(part_start < 0) | |
1182 { | |
1183 if(!is_whitespace(code[i])) | |
1184 part_end = part_start = i; | |
1185 } | |
1186 else if(code[i] == ':' && code[i-1] == ':') | |
1187 { | |
1188 type_name = code + part_start; | |
1189 type_name[part_end - part_start-1] = '\0'; | |
1190 part_start = -1; | |
1191 ++i; | |
1192 break; | |
1193 } | |
1194 else if(!is_whitespace(code[i])) | |
1195 { | |
1196 DEBUGPUTS("Not whitespace\n"); | |
1197 if(saw_newline) | |
1198 { | |
1199 code[part_end] = '\0'; | |
1200 add_comp_room(comp, code + part_start, -1, -1, ROOM_VIS_REF, ROOM_VIS_REF); | |
1201 --i; | |
1202 part_start = -1; | |
1203 saw_newline = FALSE; | |
1204 } | |
1205 else | |
1206 part_end = i+1; | |
1207 } | |
1208 | |
1209 else if(code[i] == '\n') | |
1210 { | |
1211 DEBUGPUTS("saw newline\n"); | |
1212 saw_newline = TRUE; | |
1213 } | |
1214 } | |
1215 if(i >= len && part_start >= 0 && part_end > part_start) | |
1216 { | |
1217 code[part_end] = '\0'; | |
1218 add_comp_room(comp, code + part_start, -1, -1, ROOM_VIS_REF, ROOM_VIS_REF); | |
1219 part_start = -1; | |
1220 } | |
1221 for(; i < len; ++i) | |
1222 { | |
1223 DEBUGPRINTF("i: %d, code[i]: %c ", i, code[i]); | |
1224 if(part_start < 0) | |
1225 { | |
1226 if(!is_whitespace(code[i])) | |
1227 part_end = part_start = i; | |
1228 DEBUGPRINTF("part_start: %d\n", part_start); | |
1229 } | |
1230 else if(!is_whitespace(code[i])) | |
1231 { | |
1232 DEBUGPRINTF("part_end: %d\n", part_end); | |
1233 part_end = i+1; | |
1234 } | |
1235 else if(code[i] == '\n') | |
1236 { | |
1237 DEBUGPRINTF("saw newline, type name: %s\n", type_name); | |
1238 if(!strcmp("Byte", type_name)) | |
1239 type = ROOM_BYTE; | |
1240 else if(!strcmp("Word", type_name)) | |
1241 type = ROOM_SHORT; | |
1242 else if(!strcmp("Long", type_name)) | |
1243 type = ROOM_LONG; | |
1244 else | |
1245 type = ROOM_VIS_REF; | |
1246 code[part_end] = '\0'; | |
1247 add_comp_room(comp, code + part_start, -1, -1, type, type); | |
1248 break; | |
1249 } | |
1250 } | |
1251 } | |
1252 if(part_start >= 0 && part_end > part_start) | |
1253 { | |
1254 if(!strcmp("Byte", type_name)) | |
1255 type = ROOM_BYTE; | |
1256 else if(!strcmp("Word", type_name)) | |
1257 type = ROOM_SHORT; | |
1258 else if(!strcmp("Long", type_name)) | |
1259 type = ROOM_LONG; | |
1260 else | |
1261 type = ROOM_VIS_REF; | |
1262 code[part_end] = '\0'; | |
1263 add_comp_room(comp, code + part_start, -1, -1, type, type); | |
1264 } | |
1265 } | |
1266 | |
1267 void import(char * filename, program * prog) | |
1268 { | |
1269 int size; | |
1270 char * code; | |
1271 FILE * imp; | |
1272 imp = fopen(filename, "rb"); | |
1273 if(imp) | |
1274 { | |
1275 fseek(imp, 0, SEEK_END); | |
1276 size = ftell(imp); | |
1277 fseek(imp, 0, SEEK_SET); | |
1278 code = MALLOC(size, "code from imported file"); | |
1279 fread(code, 1, size, imp); | |
1280 DEBUGPRINTF("Read %d bytes\n", size); | |
1281 parse(code, size, prog); | |
1282 DEBUGPUTS("Finished parsing import file\n"); | |
1283 VIS_FREE(code, "code buffer"); | |
1284 fclose(imp); | |
1285 } | |
1286 else | |
1287 { | |
1288 ERRORPRINTF("Warning: Could not open import file: %s\n", filename); | |
1289 } | |
1290 } | |
1291 | |
1292 typedef enum {NULL_PARSE, WORKER_STATE, BLOCK_STATE, STRING_STATE, LITERAL_STATE, LIST_STATE, LIST_STRING, LIST_LITERAL, LINE_COMMENT} super_state; | |
1293 char super_state_txt[9][30] = {"Null", "Worker", "Block", "String", "String Literal", "List", "String in List", "String Literal in List", "Single Line Comment"}; | |
1294 void parse(char * code, int len, program * prog) | |
1295 { | |
1296 parse_worker *list=NULL, *current=NULL, *temp; | |
1297 short saw_line = 0; | |
1298 int i,j,k; | |
1299 int block_count = 0; | |
1300 int start; | |
1301 int end; | |
1302 int num_inputs; | |
1303 int num_outputs; | |
1304 int company_len, import_len; | |
1305 char * worker_name; | |
1306 int left_curly=0; | |
1307 int block_done = -1; | |
1308 int comp_start, comp_end; | |
1309 char * company_name; | |
1310 char * comp_block; | |
1311 int comp_block_len; | |
1312 int num_uses; | |
1313 char * importfiles[32]; | |
1314 int num_imported = 0; | |
1315 super_state old_state; | |
1316 char ** uses_names = NULL; | |
1317 BOOL lastwasspace = FALSE; | |
1318 super_state state = NULL_PARSE; | |
1319 company_len = strlen("Company"); | |
1320 import_len = strlen("Import"); | |
1321 for(i = 0; i < len; ++i) | |
1322 { | |
1323 DEBUGPRINTF("i: %d, code[i]: %c, state: %s(%d)\n", i, code[i], super_state_txt[state], state); | |
1324 if(code[i] == '/' && code[i+1] == '/' && state != STRING_STATE && state != LIST_STRING) | |
1325 { | |
1326 old_state = state; | |
1327 state = LINE_COMMENT; | |
1328 i += 2; | |
1329 } | |
1330 switch(state) | |
1331 { | |
1332 case NULL_PARSE: | |
1333 if(len - i >= import_len && !memcmp("Import", code + i, import_len)) | |
1334 { | |
1335 start = end = -1; | |
1336 for(j = i+import_len; j < len && code[j] != '\n'; ++j) | |
1337 { | |
1338 if(start < 0) | |
1339 { | |
1340 if(!is_whitespace(code[j])) | |
1341 start = j; | |
1342 } | |
1343 else | |
1344 { | |
1345 if(!is_whitespace(code[j])) | |
1346 end = j; | |
1347 } | |
1348 } | |
1349 if(end < 0) | |
1350 { | |
1351 puts("Error: Import statement with no file name"); | |
1352 exit(-1); | |
1353 } | |
1354 ++end; | |
1355 code[end] = '\0'; | |
1356 i = end; | |
1357 if(num_imported < 32) | |
1358 importfiles[num_imported++] = code+start; | |
1359 else | |
1360 { | |
1361 puts("Error: You cannot have more than 32 import statements in the same file"); | |
1362 exit(-1); | |
1363 } | |
1364 } | |
1365 else if(code[i] == ':' && code[i+1] == '|') | |
1366 { | |
1367 start = i; | |
1368 while((code[i] != '\n' || saw_line < 5) && i < len) | |
1369 { | |
1370 if(code[i] == '\n') | |
1371 ++saw_line; | |
1372 ++i; | |
1373 } | |
1374 code[i] = '\0'; | |
1375 ERRORPRINTF("Error: Unexpected closing bracket (:|) found:\n%s", code + start); | |
1376 exit(-1); | |
1377 } | |
1378 else if(!is_whitespace(code[i])) | |
1379 { | |
1380 start = i; | |
1381 state = WORKER_STATE; | |
1382 } | |
1383 break; | |
1384 case WORKER_STATE: | |
1385 if(is_whitespace(code[i])) | |
1386 lastwasspace = TRUE; | |
1387 else if(code[i] == '|' && code[i+1] == ':') | |
1388 { | |
1389 if(!strncmp(code+start, "Company",company_len) && is_whitespace(code[start+company_len])) | |
1390 { | |
1391 comp_start = -1; | |
1392 comp_end = 0; | |
1393 for(j = start+company_len+1; j < len-1; ++j) | |
1394 { | |
1395 if(comp_start >= 0) | |
1396 { | |
1397 if(code[j] == '|' && code[j+1] == ':') | |
1398 break; | |
1399 else if(!is_whitespace(code[j])) | |
1400 comp_end = j+1; | |
1401 } | |
1402 else | |
1403 { | |
1404 if(!is_whitespace(code[j])) | |
1405 comp_start = j; | |
1406 } | |
1407 } | |
1408 if(comp_start >= 0 && comp_end > comp_start) | |
1409 { | |
1410 company_name = code + comp_start; | |
1411 code[comp_end] = '\0'; | |
1412 comp_start = -1; | |
1413 for(j = comp_end+1; j < len-1; ++j) | |
1414 { | |
1415 if(comp_start < 0) | |
1416 { | |
1417 if(code[j] == '|' && code[j+1] == ':') | |
1418 comp_start = j+2; | |
1419 } | |
1420 else | |
1421 { | |
1422 if(code[j] == ':' && code[j+1] == '|') | |
1423 { | |
1424 comp_end = j; | |
1425 break; | |
1426 } | |
1427 } | |
1428 } | |
1429 if(comp_start > 0) | |
1430 { | |
1431 comp_block = code+comp_start; | |
1432 comp_block_len = comp_end-comp_start; | |
1433 DEBUGPRINTF("Company block start: %d, end: %d, length: %d\n", comp_start, comp_end, comp_block_len); | |
1434 code[comp_end] = '\0'; | |
1435 i = comp_end+1; | |
1436 parse_company(company_name, comp_block, comp_block_len, prog); | |
1437 } | |
1438 else | |
1439 { | |
1440 printf("Error parsing Company, comp_start is %d\n", comp_start); | |
1441 } | |
1442 | |
1443 } | |
1444 else | |
1445 { | |
1446 puts("Error parsing Company\n"); | |
1447 } | |
1448 state = NULL_STATE; | |
1449 | |
1450 } | |
1451 else | |
1452 { | |
1453 for(j = i-1; j > start; --j) | |
1454 if(code[j] != ' ' && code[j] != '\t' && code[j] != '\n' && code[j] != '\r') | |
1455 break; | |
1456 for(k = start; k <= j; ++k) | |
1457 if(code[k] == '(') | |
1458 { | |
1459 code[k] = '\0'; | |
1460 num_inputs = atol(code + k + 1); | |
1461 } | |
1462 else if(code[k] == ',') | |
1463 num_outputs = atol(code + k + 1); | |
1464 worker_name = code + start; | |
1465 //printf("Found worker def: %s with %d outputs and %d inputs\n", worker_name, num_outputs, num_inputs); | |
1466 start = i+2; | |
1467 ++i; | |
1468 num_uses = 0; | |
1469 state = BLOCK_STATE; | |
1470 } | |
1471 } | |
1472 else if(lastwasspace && !strncmp(code+i, "uses", 4)) | |
1473 { | |
1474 for(j = i-1; j > start; --j) | |
1475 if(code[j] != ' ' && code[j] != '\t' && code[j] != '\n' && code[j] != '\r') | |
1476 break; | |
1477 for(k = start; k <= j; ++k) | |
1478 if(code[k] == '(') | |
1479 { | |
1480 code[k] = '\0'; | |
1481 num_inputs = atol(code + k + 1); | |
1482 } | |
1483 else if(code[k] == ',') | |
1484 num_outputs = atol(code + k + 1); | |
1485 worker_name = code + start; | |
1486 num_uses = 1; | |
1487 for(j = i + strlen("uses"); code[j] != '|' && j < len; ++j) | |
1488 if(code[j] == ',') | |
1489 ++num_uses; | |
1490 DEBUGPRINTF("num_uses: %d\n", num_uses); | |
1491 i += strlen("uses"); | |
1492 uses_names = MALLOC(sizeof(char *) * num_uses, "uses stores names"); | |
1493 end = -1; | |
1494 start = i; | |
1495 j = 0; | |
1496 while(code[i] != '|' && i < len) | |
1497 { | |
1498 if(code[i] == ',') | |
1499 { | |
1500 uses_names[j] = MALLOC(sizeof(char) * (end-start+1), "global store name for uses stores"); | |
1501 memcpy(uses_names[j], code+start, end-start); | |
1502 uses_names[j][end-start] = '\0'; | |
1503 DEBUGPRINTF("uses: %s\n", uses_names[j]); | |
1504 end = -1; | |
1505 ++j; | |
1506 } | |
1507 else if(code[i] != ' ' && code[i] != '\t' && code[i] != '\r' && code[i] != '\n') | |
1508 end = i+1; | |
1509 else if(end < 0) | |
1510 start = i+1; | |
1511 ++i; | |
1512 } | |
1513 if(end >= 0) | |
1514 { | |
1515 uses_names[j] = MALLOC(sizeof(char) * (end-start+1), "global store name for uses stores"); | |
1516 memcpy(uses_names[j], code+start, end-start); | |
1517 uses_names[j][end-start] = '\0'; | |
1518 DEBUGPRINTF("uses: %s\n", uses_names[j]); | |
1519 end = -1; | |
1520 ++j; | |
1521 } | |
1522 start = i+2; | |
1523 ++i; | |
1524 state = BLOCK_STATE; | |
1525 | |
1526 } | |
1527 break; | |
1528 case BLOCK_STATE: | |
1529 //printf("Block count: %d\n", block_count); | |
1530 if((i-block_done)>1 && code[i] == ':' && code[i-1] == '|') | |
1531 { | |
1532 ++block_count; | |
1533 } | |
1534 else if(code[i] == '"') { | |
1535 state = STRING_STATE; | |
1536 } | |
1537 else if(code[i] == '{') { | |
1538 state = LIST_STATE; | |
1539 } | |
1540 else if(code[i] == '|' && code[i-1] == ':') | |
1541 { | |
1542 if(block_count == 0) | |
1543 { | |
1544 if(current) | |
1545 { | |
1546 current->next = MALLOC(sizeof(parse_worker),"parse worker"); | |
1547 current = current->next; | |
1548 } | |
1549 else | |
1550 { | |
1551 list = current = MALLOC(sizeof(parse_worker),"parse worker"); | |
1552 } | |
1553 current->num_inputs = num_inputs; | |
1554 current->num_outputs = num_outputs; | |
1555 current->worker_name = worker_name; | |
1556 current->block = code + start; | |
1557 current->block_len = i-start-1; | |
1558 current->next = NULL; | |
1559 current->def = create_worker(prog, current->worker_name, current->num_inputs, current->num_outputs, USER_FLAG | WORKER_TYPE); | |
1560 current->def->uses_stores = uses_names; | |
1561 current->def->num_stores = num_uses; | |
1562 uses_names = NULL; | |
1563 num_uses = 0; | |
1564 state = NULL_PARSE; | |
1565 block_done = -1; | |
1566 } | |
1567 else | |
1568 { | |
1569 block_done = i; | |
1570 --block_count; | |
1571 } | |
1572 } | |
1573 break; | |
1574 case STRING_STATE: | |
1575 if(code[i] == '\\') | |
1576 state = LITERAL_STATE; | |
1577 else if(code[i] == '"') | |
1578 state = BLOCK_STATE; | |
1579 break; | |
1580 case LITERAL_STATE: | |
1581 state = STRING_STATE; | |
1582 break; | |
1583 case LIST_STATE: | |
1584 if(code[i] == '{') | |
1585 ++left_curly; | |
1586 else if(code[i] == '}') | |
1587 if(left_curly) | |
1588 --left_curly; | |
1589 else | |
1590 state = BLOCK_STATE; | |
1591 else if(code[i] == '"') | |
1592 state = LIST_STRING; | |
1593 break; | |
1594 case LIST_STRING: | |
1595 if(code[i] == '\\') | |
1596 state = LIST_LITERAL; | |
1597 else if(code[i] == '"') | |
1598 state = LIST_STATE; | |
1599 break; | |
1600 case LIST_LITERAL: | |
1601 state = LIST_STRING; | |
1602 break; | |
1603 case LINE_COMMENT: | |
1604 if(code[i+1] == '\n') | |
1605 state = old_state; | |
1606 break; | |
1607 } | |
1608 } | |
1609 if(state != NULL_PARSE) | |
1610 { | |
1611 printf("Error: Current parse state is %s(%d) in first pass but there are no more characters to parse.\n", super_state_txt[state], state); | |
1612 if(state == BLOCK_STATE) | |
1613 { | |
1614 printf("Worker %s appears to be missing a closing bracket (:|)\n", worker_name); | |
1615 } | |
1616 exit(-3); | |
1617 } | |
1618 for(i = 0; i < num_imported; ++i) | |
1619 { | |
1620 import(importfiles[i], prog); | |
1621 } | |
1622 current = list; | |
1623 while(current) | |
1624 { | |
1625 DEBUGPRINTF("Processing worker %s with %d inputs and %d outputs\n\n", current->worker_name, current->num_inputs, current->num_outputs); | |
1626 parse_body(current->def, current->block, current->block_len, 0, NULL, NULL); | |
1627 temp = current; | |
1628 current = current->next; | |
1629 free(temp); | |
1630 } | |
1631 } | |
1632 | |
1633 |