|
1 /* |
|
2 * (c) 2007 Mario de Sousa and Laurent Bessard |
|
3 * |
|
4 * Offered to the public under the terms of the GNU General Public License |
|
5 * as published by the Free Software Foundation; either version 2 of the |
|
6 * License, or (at your option) any later version. |
|
7 * |
|
8 * This program is distributed in the hope that it will be useful, but |
|
9 * WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General |
|
11 * Public License for more details. |
|
12 * |
|
13 * This code is made available on the understanding that it will not be |
|
14 * used in safety-critical situations without a full and competent review. |
|
15 */ |
|
16 |
|
17 /* |
|
18 * An IEC 61131-3 IL and ST compiler. |
|
19 * |
|
20 * Based on the |
|
21 * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) |
|
22 * |
|
23 */ |
|
24 |
|
25 /* |
|
26 * This is one of the versions available for the 4th stage. |
|
27 * |
|
28 * This 4th stage generates a c++ source program equivalent |
|
29 * to the IL and ST code. |
|
30 */ |
|
31 |
|
32 //#include <stdio.h> /* required for NULL */ |
|
33 //#include <string> |
|
34 //#include <iostream> |
|
35 |
|
36 //#include "../../util/symtable.hh" |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 typedef struct |
|
42 { |
|
43 symbol_c *symbol; |
|
44 } SYMBOL; |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 /***********************************************************************/ |
|
50 /***********************************************************************/ |
|
51 /***********************************************************************/ |
|
52 /***********************************************************************/ |
|
53 /***********************************************************************/ |
|
54 /***********************************************************************/ |
|
55 /***********************************************************************/ |
|
56 /***********************************************************************/ |
|
57 |
|
58 class generate_var_list_c: protected generate_c_typedecl_c { |
|
59 |
|
60 private: |
|
61 symbol_c *current_var_type_symbol; |
|
62 unsigned int current_var_number; |
|
63 unsigned int step_number; |
|
64 unsigned int transition_number; |
|
65 unsigned int action_number; |
|
66 std::list<SYMBOL> current_symbol_list; |
|
67 search_base_type_c search_base_type; |
|
68 search_fb_typedecl_c *search_fb_typedecl; |
|
69 |
|
70 public: |
|
71 generate_var_list_c(stage4out_c *s4o_ptr, symbol_c *scope) |
|
72 : generate_c_typedecl_c(s4o_ptr) { |
|
73 search_fb_typedecl = new search_fb_typedecl_c(scope); |
|
74 current_var_type_symbol = NULL; |
|
75 current_var_number = 0; |
|
76 } |
|
77 |
|
78 ~generate_var_list_c(void) { |
|
79 delete search_fb_typedecl; |
|
80 } |
|
81 |
|
82 void update_var_type_symbol(symbol_c *symbol, bool is_fb = false) { |
|
83 this->current_var_type_symbol = spec_init_sperator_c::get_spec(symbol); |
|
84 if (this->current_var_type_symbol == NULL) |
|
85 ERROR; |
|
86 |
|
87 if (is_fb) |
|
88 this->current_var_type_symbol = search_fb_typedecl->get_decl(this->current_var_type_symbol); |
|
89 else |
|
90 this->current_var_type_symbol = (symbol_c *)(this->current_var_type_symbol->accept(search_base_type)); |
|
91 if (this->current_var_type_symbol == NULL) |
|
92 ERROR; |
|
93 } |
|
94 |
|
95 void reset_var_type_symbol(void) { |
|
96 this->current_var_type_symbol = NULL; |
|
97 } |
|
98 |
|
99 void declare_variables(symbol_c *symbol, bool is_fb = false) { |
|
100 list_c *list = dynamic_cast<list_c *>(symbol); |
|
101 /* should NEVER EVER occur!! */ |
|
102 if (list == NULL) ERROR; |
|
103 |
|
104 for(int i = 0; i < list->n; i++) { |
|
105 declare_variable(list->elements[i], is_fb); |
|
106 } |
|
107 } |
|
108 |
|
109 void declare_variable(symbol_c *symbol, bool is_fb = false) { |
|
110 if (is_fb) { |
|
111 SYMBOL *current_name; |
|
112 current_name = new SYMBOL; |
|
113 current_name->symbol = symbol; |
|
114 current_symbol_list.push_back(*current_name); |
|
115 this->current_var_type_symbol->accept(*this); |
|
116 current_symbol_list.pop_back(); |
|
117 } |
|
118 else { |
|
119 print_var_number(); |
|
120 s4o.print(";"); |
|
121 print_symbol_list(); |
|
122 symbol->accept(*this); |
|
123 s4o.print(";"); |
|
124 print_symbol_list(); |
|
125 symbol->accept(*this); |
|
126 s4o.print(";"); |
|
127 this->current_var_type_symbol->accept(*this); |
|
128 s4o.print(";\n"); |
|
129 } |
|
130 } |
|
131 |
|
132 void print_var_number(void) { |
|
133 char str[10]; |
|
134 sprintf(str, "%d", current_var_number); |
|
135 s4o.print(str); |
|
136 current_var_number++; |
|
137 } |
|
138 |
|
139 void print_step_number(void) { |
|
140 char str[10]; |
|
141 sprintf(str, "%d", step_number); |
|
142 s4o.print(str); |
|
143 } |
|
144 |
|
145 void print_transition_number(void) { |
|
146 char str[10]; |
|
147 sprintf(str, "%d", transition_number); |
|
148 s4o.print(str); |
|
149 } |
|
150 |
|
151 void print_action_number(void) { |
|
152 char str[10]; |
|
153 sprintf(str, "%d", action_number); |
|
154 s4o.print(str); |
|
155 } |
|
156 |
|
157 void print_symbol_list(void) { |
|
158 std::list<SYMBOL>::iterator pt; |
|
159 for(pt = current_symbol_list.begin(); pt != current_symbol_list.end(); pt++) { |
|
160 pt->symbol->accept(*this); |
|
161 s4o.print("."); |
|
162 } |
|
163 } |
|
164 |
|
165 /********************************************/ |
|
166 /* B.1.4.3 Declaration and initilization */ |
|
167 /********************************************/ |
|
168 |
|
169 /* [variable_name] location ':' located_var_spec_init */ |
|
170 /* variable_name -> may be NULL ! */ |
|
171 //SYM_REF4(located_var_decl_c, variable_name, location, located_var_spec_init, unused) |
|
172 void *visit(located_var_decl_c *symbol) { |
|
173 /* Start off by setting the current_var_type_symbol and |
|
174 * current_var_init_symbol private variables... |
|
175 */ |
|
176 update_var_type_symbol(symbol->located_var_spec_init); |
|
177 |
|
178 if (symbol->variable_name != NULL) |
|
179 declare_variable(symbol->variable_name); |
|
180 |
|
181 current_var_type_symbol = NULL; |
|
182 return NULL; |
|
183 } |
|
184 |
|
185 /* var1_list ':' array_spec_init */ |
|
186 // SYM_REF2(array_var_init_decl_c, var1_list, array_spec_init) |
|
187 void *visit(array_var_init_decl_c *symbol) { |
|
188 TRACE("array_var_init_decl_c"); |
|
189 /* Start off by setting the current_var_type_symbol and |
|
190 * current_var_init_symbol private variables... |
|
191 */ |
|
192 update_var_type_symbol(symbol->array_spec_init); |
|
193 |
|
194 declare_variables(symbol->var1_list); |
|
195 |
|
196 /* Values no longer in scope, and therefore no longer used. |
|
197 * Make an effort to keep them set to NULL when not in use |
|
198 * in order to catch bugs as soon as possible... |
|
199 */ |
|
200 reset_var_type_symbol(); |
|
201 |
|
202 return NULL; |
|
203 } |
|
204 |
|
205 /* var1_list ':' initialized_structure */ |
|
206 // SYM_REF2(structured_var_init_decl_c, var1_list, initialized_structure) |
|
207 void *visit(structured_var_init_decl_c *symbol) { |
|
208 TRACE("structured_var_init_decl_c"); |
|
209 /* Please read the comments inside the var1_init_decl_c |
|
210 * visitor, as they apply here too. |
|
211 */ |
|
212 |
|
213 /* Start off by setting the current_var_type_symbol and |
|
214 * current_var_init_symbol private variables... |
|
215 */ |
|
216 update_var_type_symbol(symbol->initialized_structure); |
|
217 |
|
218 /* now to produce the c equivalent... */ |
|
219 declare_variables(symbol->var1_list); |
|
220 |
|
221 /* Values no longer in scope, and therefore no longer used. |
|
222 * Make an effort to keep them set to NULL when not in use |
|
223 * in order to catch bugs as soon as possible... |
|
224 */ |
|
225 reset_var_type_symbol(); |
|
226 |
|
227 return NULL; |
|
228 } |
|
229 |
|
230 /* fb_name_list ':' function_block_type_name ASSIGN structure_initialization */ |
|
231 /* structure_initialization -> may be NULL ! */ |
|
232 void *visit(fb_name_decl_c *symbol) { |
|
233 TRACE("fb_name_decl_c"); |
|
234 /* Please read the comments inside the var1_init_decl_c |
|
235 * visitor, as they apply here too. |
|
236 */ |
|
237 |
|
238 /* Start off by setting the current_var_type_symbol and |
|
239 * current_var_init_symbol private variables... |
|
240 */ |
|
241 update_var_type_symbol(symbol, true); |
|
242 |
|
243 /* now to produce the c equivalent... */ |
|
244 declare_variables(symbol->fb_name_list, true); |
|
245 |
|
246 /* Values no longer in scope, and therefore no longer used. |
|
247 * Make an effort to keep them set to NULL when not in use |
|
248 * in order to catch bugs as soon as possible... |
|
249 */ |
|
250 reset_var_type_symbol(); |
|
251 |
|
252 return NULL; |
|
253 } |
|
254 |
|
255 /* global_var_name ':' (simple_specification|subrange_specification|enumerated_specification|array_specification|prev_declared_structure_type_name|function_block_type_name */ |
|
256 //SYM_REF2(external_declaration_c, global_var_name, specification) |
|
257 void *visit(external_declaration_c *symbol) { |
|
258 TRACE("external_declaration_c"); |
|
259 /* Please read the comments inside the var1_init_decl_c |
|
260 * visitor, as they apply here too. |
|
261 */ |
|
262 |
|
263 /* Start off by setting the current_var_type_symbol and |
|
264 * current_var_init_symbol private variables... |
|
265 */ |
|
266 this->current_var_type_symbol = (symbol_c *)(symbol->specification->accept(*search_fb_typedecl)); |
|
267 if (this->current_var_type_symbol == NULL) { |
|
268 this->current_var_type_symbol = symbol->specification; |
|
269 |
|
270 declare_variable(symbol->global_var_name); |
|
271 } |
|
272 else |
|
273 declare_variable(symbol->global_var_name, true); |
|
274 |
|
275 /* Values no longer in scope, and therefore no longer used. |
|
276 * Make an effort to keep them set to NULL when not in use |
|
277 * in order to catch bugs as soon as possible... |
|
278 */ |
|
279 reset_var_type_symbol(); |
|
280 |
|
281 return NULL; |
|
282 } |
|
283 |
|
284 /*| global_var_spec ':' [located_var_spec_init|function_block_type_name] */ |
|
285 /* type_specification ->may be NULL ! */ |
|
286 // SYM_REF2(global_var_decl_c, global_var_spec, type_specification) |
|
287 void *visit(global_var_decl_c *symbol) { |
|
288 TRACE("global_var_decl_c"); |
|
289 /* Please read the comments inside the var1_init_decl_c |
|
290 * visitor, as they apply here too. |
|
291 */ |
|
292 |
|
293 /* Start off by setting the current_var_type_symbol and |
|
294 * current_var_init_symbol private variables... |
|
295 */ |
|
296 update_var_type_symbol(symbol->type_specification); |
|
297 |
|
298 /* now to produce the c equivalent... */ |
|
299 symbol->global_var_spec->accept(*this); |
|
300 |
|
301 /* Values no longer in scope, and therefore no longer used. |
|
302 * Make an effort to keep them set to NULL when not in use |
|
303 * in order to catch bugs as soon as possible... |
|
304 */ |
|
305 reset_var_type_symbol(); |
|
306 |
|
307 return NULL; |
|
308 } |
|
309 |
|
310 void *visit(global_var_list_c *symbol) { |
|
311 declare_variables(symbol); |
|
312 return NULL; |
|
313 } |
|
314 |
|
315 /*| global_var_name location */ |
|
316 // SYM_REF2(global_var_spec_c, global_var_name, location) |
|
317 void *visit(global_var_spec_c *symbol) { |
|
318 if (symbol->global_var_name != NULL) |
|
319 declare_variable(symbol->global_var_name); |
|
320 return NULL; |
|
321 } |
|
322 |
|
323 void *visit(var1_init_decl_c *symbol) { |
|
324 TRACE("var1_init_decl_c"); |
|
325 |
|
326 /* Start off by setting the current_var_type_symbol and |
|
327 * current_var_init_symbol private variables... |
|
328 */ |
|
329 update_var_type_symbol(symbol->spec_init); |
|
330 |
|
331 /* now to produce the c equivalent... */ |
|
332 declare_variables(symbol->var1_list); |
|
333 |
|
334 /* Values no longer in scope, and therefore no longer used. |
|
335 * Make an effort to keep them set to NULL when not in use |
|
336 * in order to catch bugs as soon as possible... |
|
337 */ |
|
338 reset_var_type_symbol(); |
|
339 |
|
340 return NULL; |
|
341 } |
|
342 |
|
343 /**************************************/ |
|
344 /* B.1.5 - Program organization units */ |
|
345 /**************************************/ |
|
346 |
|
347 /*****************************/ |
|
348 /* B 1.5.2 - Function Blocks */ |
|
349 /*****************************/ |
|
350 void *visit(function_block_declaration_c *symbol) { |
|
351 symbol->var_declarations->accept(*this); |
|
352 symbol->fblock_body->accept(*this); |
|
353 return NULL; |
|
354 } |
|
355 |
|
356 /**********************/ |
|
357 /* B 1.5.3 - Programs */ |
|
358 /**********************/ |
|
359 void *visit(program_declaration_c *symbol) { |
|
360 symbol->var_declarations->accept(*this); |
|
361 symbol->function_block_body->accept(*this); |
|
362 return NULL; |
|
363 } |
|
364 |
|
365 /**********************************************/ |
|
366 /* B 1.6 - Sequential function chart elements */ |
|
367 /**********************************************/ |
|
368 |
|
369 /* | sequential_function_chart sfc_network */ |
|
370 //SYM_LIST(sequential_function_chart_c) |
|
371 void *visit(sequential_function_chart_c *symbol) { |
|
372 step_number = 0; |
|
373 transition_number = 0; |
|
374 action_number = 0; |
|
375 for(int i = 0; i < symbol->n; i++) { |
|
376 symbol->elements[i]->accept(*this); |
|
377 } |
|
378 return NULL; |
|
379 } |
|
380 |
|
381 /* INITIAL_STEP step_name ':' action_association_list END_STEP */ |
|
382 //SYM_REF2(initial_step_c, step_name, action_association_list) |
|
383 void *visit(initial_step_c *symbol) { |
|
384 print_var_number(); |
|
385 s4o.print(";"); |
|
386 print_symbol_list(); |
|
387 symbol->step_name->accept(*this); |
|
388 s4o.print(".X;"); |
|
389 print_symbol_list(); |
|
390 s4o.print("step_list["); |
|
391 print_step_number(); |
|
392 s4o.print("].state;STEP;\n"); |
|
393 step_number++; |
|
394 return NULL; |
|
395 } |
|
396 |
|
397 /* STEP step_name ':' action_association_list END_STEP */ |
|
398 //SYM_REF2(step_c, step_name, action_association_list) |
|
399 void *visit(step_c *symbol) { |
|
400 print_var_number(); |
|
401 s4o.print(";"); |
|
402 print_symbol_list(); |
|
403 symbol->step_name->accept(*this); |
|
404 s4o.print(".X;"); |
|
405 print_symbol_list(); |
|
406 s4o.print("step_list["); |
|
407 print_step_number(); |
|
408 s4o.print("].state;STEP;\n"); |
|
409 step_number++; |
|
410 return NULL; |
|
411 } |
|
412 |
|
413 /* TRANSITION [transition_name] ['(' PRIORITY ASSIGN integer ')'] |
|
414 * FROM steps TO steps |
|
415 * transition_condition |
|
416 * END_TRANSITION |
|
417 */ |
|
418 /* transition_name -> may be NULL ! */ |
|
419 /* integer -> may be NULL ! */ |
|
420 //SYM_REF5(transition_c, transition_name, integer, from_steps, to_steps, transition_condition) |
|
421 void *visit(transition_c *symbol) { |
|
422 print_var_number(); |
|
423 s4o.print(";"); |
|
424 print_symbol_list(); |
|
425 symbol->from_steps->accept(*this); |
|
426 s4o.print("->"); |
|
427 symbol->to_steps->accept(*this); |
|
428 s4o.print(";"); |
|
429 print_symbol_list(); |
|
430 s4o.print("transition_list["); |
|
431 print_transition_number(); |
|
432 s4o.print("];TRANSITION;\n"); |
|
433 transition_number++; |
|
434 return NULL; |
|
435 } |
|
436 |
|
437 /* step_name | '(' step_name_list ')' */ |
|
438 /* step_name -> may be NULL ! */ |
|
439 /* step_name_list -> may be NULL ! */ |
|
440 //SYM_REF2(steps_c, step_name, step_name_list) |
|
441 void *visit(steps_c *symbol) { |
|
442 if (symbol->step_name != NULL) |
|
443 symbol->step_name->accept(*this); |
|
444 if (symbol->step_name_list != NULL) |
|
445 symbol->step_name_list->accept(*this); |
|
446 return NULL; |
|
447 } |
|
448 |
|
449 /* | step_name_list ',' step_name */ |
|
450 //SYM_LIST(step_name_list_c) |
|
451 void *visit(step_name_list_c *symbol) { |
|
452 for(int i = 0; i < symbol->n; i++) { |
|
453 symbol->elements[i]->accept(*this); |
|
454 if (i < symbol->n - 1) |
|
455 s4o.print(","); |
|
456 } |
|
457 return NULL; |
|
458 } |
|
459 |
|
460 /* ACTION action_name ':' function_block_body END_ACTION */ |
|
461 //SYM_REF2(action_c, action_name, function_block_body) |
|
462 void *visit(action_c *symbol) { |
|
463 print_var_number(); |
|
464 s4o.print(";"); |
|
465 print_symbol_list(); |
|
466 symbol->action_name->accept(*this); |
|
467 s4o.print(".Q;"); |
|
468 print_symbol_list(); |
|
469 s4o.print("action_list["); |
|
470 print_action_number(); |
|
471 s4o.print("].state;ACTION;\n"); |
|
472 action_number++; |
|
473 return NULL; |
|
474 } |
|
475 |
|
476 |
|
477 /**************************************/ |
|
478 /* B.1.7 - Configuration elements */ |
|
479 /**************************************/ |
|
480 |
|
481 /* PROGRAM [RETAIN | NON_RETAIN] program_name [WITH task_name] ':' program_type_name ['(' prog_conf_elements ')'] */ |
|
482 //SYM_REF6(program_configuration_c, retain_option, program_name, task_name, program_type_name, prog_conf_elements, unused) |
|
483 void *visit(program_configuration_c *symbol) { |
|
484 |
|
485 /* Start off by setting the current_var_type_symbol and |
|
486 * current_var_init_symbol private variables... |
|
487 */ |
|
488 update_var_type_symbol(symbol->program_type_name, true); |
|
489 |
|
490 declare_variable(symbol->program_name, true); |
|
491 |
|
492 /* Values no longer in scope, and therefore no longer used. |
|
493 * Make an effort to keep them set to NULL when not in use |
|
494 * in order to catch bugs as soon as possible... |
|
495 */ |
|
496 reset_var_type_symbol(); |
|
497 |
|
498 return NULL; |
|
499 } |
|
500 |
|
501 /* CONFIGURATION configuration_name |
|
502 * optional_global_var_declarations |
|
503 * (resource_declaration_list | single_resource_declaration) |
|
504 * optional_access_declarations |
|
505 * optional_instance_specific_initializations |
|
506 * END_CONFIGURATION |
|
507 */ |
|
508 //SYM_REF5(configuration_declaration_c, configuration_name, global_var_declarations, resource_declarations, access_declarations, instance_specific_initializations) |
|
509 void *visit(configuration_declaration_c *symbol) { |
|
510 SYMBOL *current_name; |
|
511 current_name = new SYMBOL; |
|
512 current_name->symbol = symbol->configuration_name; |
|
513 current_symbol_list.push_back(*current_name); |
|
514 symbol->resource_declarations->accept(*this); |
|
515 current_symbol_list.pop_back(); |
|
516 return NULL; |
|
517 } |
|
518 |
|
519 /* RESOURCE resource_name ON resource_type_name |
|
520 * optional_global_var_declarations |
|
521 * single_resource_declaration |
|
522 * END_RESOURCE |
|
523 */ |
|
524 //SYM_REF4(resource_declaration_c, resource_name, resource_type_name, global_var_declarations, resource_declaration) |
|
525 void *visit(resource_declaration_c *symbol) { |
|
526 SYMBOL *current_name; |
|
527 current_name = new SYMBOL; |
|
528 current_name->symbol = symbol->resource_name; |
|
529 current_symbol_list.push_back(*current_name); |
|
530 |
|
531 if (symbol->global_var_declarations != NULL) |
|
532 symbol->global_var_declarations->accept(*this); |
|
533 |
|
534 symbol->resource_declaration->accept(*this); |
|
535 |
|
536 current_symbol_list.pop_back(); |
|
537 return NULL; |
|
538 } |
|
539 |
|
540 /* task_configuration_list program_configuration_list */ |
|
541 //SYM_REF2(single_resource_declaration_c, task_configuration_list, program_configuration_list) |
|
542 void *visit(single_resource_declaration_c *symbol) { |
|
543 symbol->program_configuration_list->accept(*this); |
|
544 return NULL; |
|
545 } |
|
546 |
|
547 |
|
548 /*************************************/ |
|
549 /* B 2.1 - Instructions and operands */ |
|
550 /*************************************/ |
|
551 void *visit(instruction_list_c *symbol) { |
|
552 return NULL; |
|
553 } |
|
554 |
|
555 /************************/ |
|
556 /* B 3.2 - Statements */ |
|
557 /************************/ |
|
558 void *visit(statement_list_c *symbol) { |
|
559 return NULL; |
|
560 } |
|
561 |
|
562 }; |