Mercurial > repos > rhope
annotate parser.c @ 114:25a205094f9b
More performance optimizations
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 13 Oct 2010 01:15:04 +0000 |
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 |