|
1 /* |
|
2 * (c) 2003 Mario de Sousa |
|
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 /* |
|
27 * Conversion of st statements (i.e. ST code). |
|
28 * |
|
29 * This is part of the 4th stage that generates |
|
30 * a c++ source program equivalent to the IL and ST |
|
31 * code. |
|
32 */ |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 class generate_cc_st_c: public generate_cc_typedecl_c { |
|
39 |
|
40 private: |
|
41 /* When calling a function block, we must first find it's type, |
|
42 * by searching through the declarations of the variables currently |
|
43 * in scope. |
|
44 * This class does just that... |
|
45 * A new class is instantiated whenever we begin generating the code |
|
46 * for a function block type declaration, or a program declaration. |
|
47 * This object instance will then later be called while the |
|
48 * function block's or the program's body is being handled. |
|
49 * |
|
50 * Note that functions cannot contain calls to function blocks, |
|
51 * so we do not create an object instance when handling |
|
52 * a function declaration. |
|
53 */ |
|
54 search_fb_instance_decl_c *search_fb_instance_decl; |
|
55 |
|
56 |
|
57 public: |
|
58 generate_cc_st_c(stage4out_c *s4o_ptr, symbol_c *scope, const char *variable_prefix = NULL) |
|
59 : generate_cc_typedecl_c(s4o_ptr) { |
|
60 search_fb_instance_decl = new search_fb_instance_decl_c(scope); |
|
61 this->set_variable_prefix(variable_prefix); |
|
62 } |
|
63 |
|
64 virtual ~generate_cc_st_c(void) { |
|
65 delete search_fb_instance_decl; |
|
66 } |
|
67 |
|
68 |
|
69 private: |
|
70 /* Some function calls in the body of functions or function blocks |
|
71 * may leave some parameters to their default values, and |
|
72 * ignore some output parameters of the function being called. |
|
73 * Our conversion of ST functions to C++ does not contemplate that, |
|
74 * i.e. each called function must get all it's input and output |
|
75 * parameters set correctly. |
|
76 * For input parameters we merely need to call the function with |
|
77 * the apropriate default value, but for output parameters |
|
78 * we must create temporary variables to hold the output value. |
|
79 * |
|
80 * We declare all the temporary output variables at the begining of |
|
81 * the body of each function or function block, and use them as |
|
82 * in function calls later on as they become necessary... |
|
83 * Note that we cannot create these variables just before a function |
|
84 * call, as the function call itself may be integrated within an |
|
85 * expression, or another function call! |
|
86 * |
|
87 * The variables are declared in the exact same order in which they |
|
88 * will be used later on during the function calls, which allows us |
|
89 * to simply re-create the name that was used for the temporary variable |
|
90 * instead of keeping it in some list. |
|
91 * The names are recreated by the temp_var_name_factory, after reset() |
|
92 * has been called! |
|
93 * |
|
94 * This function will genertae code similar to... |
|
95 * |
|
96 * INT __TMP_0 = 23; |
|
97 * REAL __TMP_1 = 45.5; |
|
98 * ... |
|
99 */ |
|
100 temp_var_name_c temp_var_name_factory; |
|
101 |
|
102 public: |
|
103 void generate(statement_list_c *stl) { |
|
104 generate_cc_tempvardecl_c generate_cc_tempvardecl(&s4o); |
|
105 generate_cc_tempvardecl.generate(stl, &temp_var_name_factory); |
|
106 stl->accept(*this); |
|
107 } |
|
108 |
|
109 private: |
|
110 /***************************************/ |
|
111 /* B.3 - Language ST (Structured Text) */ |
|
112 /***************************************/ |
|
113 /***********************/ |
|
114 /* B 3.1 - Expressions */ |
|
115 /***********************/ |
|
116 void *visit(or_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " || ");} |
|
117 /* TODO ... XOR expression... */ |
|
118 void *visit(xor_expression_c *symbol) {ERROR; return print_binary_expression(symbol->l_exp, symbol->r_exp, " XOR ");} |
|
119 void *visit(and_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " && ");} |
|
120 void *visit(equ_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " == ");} |
|
121 void *visit(notequ_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " != ");} |
|
122 void *visit(lt_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " < ");} |
|
123 void *visit(gt_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " > ");} |
|
124 void *visit(le_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " <= ");} |
|
125 void *visit(ge_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " >= ");} |
|
126 void *visit(add_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " + ");} |
|
127 void *visit(sub_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " - ");} |
|
128 void *visit(mul_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " * ");} |
|
129 void *visit(div_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " / ");} |
|
130 void *visit(mod_expression_c *symbol) { |
|
131 s4o.print("(("); |
|
132 symbol->r_exp->accept(*this); |
|
133 s4o.print(" == 0)?0:"); |
|
134 print_binary_expression(symbol->l_exp, symbol->r_exp, " % "); |
|
135 s4o.print(")"); |
|
136 return NULL; |
|
137 } |
|
138 |
|
139 /* TODO: power expression... */ |
|
140 void *visit(power_expression_c *symbol) {ERROR; return print_binary_expression(symbol->l_exp, symbol->r_exp, " ** ");} |
|
141 void *visit(neg_expression_c *symbol) {return print_unary_expression(symbol->exp, " -");} |
|
142 void *visit(not_expression_c *symbol) {return print_unary_expression(symbol->exp, "!");} |
|
143 |
|
144 void *visit(function_invocation_c *symbol) { |
|
145 function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name); |
|
146 |
|
147 if (f_decl == function_symtable.end_value()) |
|
148 /* should never occur. The function being called MUST be in the symtable... */ |
|
149 ERROR; |
|
150 |
|
151 symbol->function_name->accept(*this); |
|
152 s4o.print("("); |
|
153 |
|
154 /* loop through each function parameter, find the value we should pass |
|
155 * to it, and then output the c equivalent... |
|
156 */ |
|
157 |
|
158 function_param_iterator_c fp_iterator(f_decl); |
|
159 identifier_c *param_name; |
|
160 function_call_param_iterator_c function_call_param_iterator(symbol); |
|
161 for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { |
|
162 if (i != 1) |
|
163 s4o.print(", "); |
|
164 |
|
165 symbol_c *param_type = fp_iterator.param_type(); |
|
166 if (param_type == NULL) ERROR; |
|
167 |
|
168 function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); |
|
169 |
|
170 /* Get the value from a foo(<param_name> = <param_value>) style call */ |
|
171 symbol_c *param_value = function_call_param_iterator.search(param_name); |
|
172 |
|
173 /* Get the value from a foo(<param_value>) style call */ |
|
174 if (param_value == NULL) |
|
175 param_value = function_call_param_iterator.next(); |
|
176 |
|
177 switch (param_direction) { |
|
178 case function_param_iterator_c::direction_in: |
|
179 if (param_value == NULL) { |
|
180 /* No value given for parameter, so we must use the default... */ |
|
181 /* First check whether default value specified in function declaration...*/ |
|
182 param_value = fp_iterator.default_value(); |
|
183 } |
|
184 if (param_value == NULL) { |
|
185 /* If not, get the default value of this variable's type */ |
|
186 param_value = (symbol_c *)param_type->accept(*type_initial_value_c::instance()); |
|
187 } |
|
188 if (param_value == NULL) ERROR; |
|
189 param_value->accept(*this); |
|
190 break; |
|
191 case function_param_iterator_c::direction_out: |
|
192 case function_param_iterator_c::direction_inout: |
|
193 if (param_value == NULL) { |
|
194 /* no parameter value given, so we pass a previously declared temporary variable. */ |
|
195 std::string *temp_var_name = temp_var_name_factory.new_name(); |
|
196 s4o.print(*temp_var_name); |
|
197 delete temp_var_name; |
|
198 } else { |
|
199 param_value->accept(*this); |
|
200 } |
|
201 break; |
|
202 case function_param_iterator_c::direction_extref: |
|
203 /* TODO! */ |
|
204 ERROR; |
|
205 break; |
|
206 } /* switch */ |
|
207 } /* for(...) */ |
|
208 |
|
209 // symbol->parameter_assignment->accept(*this); |
|
210 s4o.print(")"); |
|
211 return NULL; |
|
212 } |
|
213 |
|
214 /********************/ |
|
215 /* B 3.2 Statements */ |
|
216 /********************/ |
|
217 void *visit(statement_list_c *symbol) { |
|
218 return print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n"); |
|
219 } |
|
220 |
|
221 /*********************************/ |
|
222 /* B 3.2.1 Assignment Statements */ |
|
223 /*********************************/ |
|
224 void *visit(assignment_statement_c *symbol) { |
|
225 symbol->l_exp->accept(*this); |
|
226 s4o.print(" = "); |
|
227 symbol->r_exp->accept(*this); |
|
228 return NULL; |
|
229 } |
|
230 |
|
231 /*****************************************/ |
|
232 /* B 3.2.2 Subprogram Control Statements */ |
|
233 /*****************************************/ |
|
234 |
|
235 /* fb_name '(' [param_assignment_list] ')' */ |
|
236 /* param_assignment_list -> may be NULL ! */ |
|
237 //SYM_REF2(fb_invocation_c, fb_name, param_assignment_list) |
|
238 void *visit(fb_invocation_c *symbol) { |
|
239 TRACE("fb_invocation_c"); |
|
240 /* first figure out what is the name of the function block type of the function block being called... */ |
|
241 symbol_c *function_block_type_name = this->search_fb_instance_decl->get_type_name(symbol->fb_name); |
|
242 /* should never occur. The function block instance MUST have been declared... */ |
|
243 if (function_block_type_name == NULL) ERROR; |
|
244 |
|
245 /* Now find the declaration of the function block type being called... */ |
|
246 function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(function_block_type_name); |
|
247 /* should never occur. The function block type being called MUST be in the symtable... */ |
|
248 if (fb_decl == function_block_type_symtable.end_value()) ERROR; |
|
249 |
|
250 /* loop through each function block parameter, find the value we should pass |
|
251 * to it, and then output the c equivalent... |
|
252 */ |
|
253 function_param_iterator_c fp_iterator(fb_decl); |
|
254 identifier_c *param_name; |
|
255 function_call_param_iterator_c function_call_param_iterator(symbol); |
|
256 for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { |
|
257 function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); |
|
258 |
|
259 /* Get the value from a foo(<param_name> = <param_value>) style call */ |
|
260 symbol_c *param_value = function_call_param_iterator.search(param_name); |
|
261 |
|
262 /* Get the value from a foo(<param_value>) style call */ |
|
263 if (param_value == NULL) |
|
264 param_value = function_call_param_iterator.next(); |
|
265 |
|
266 /* now output the value assignment */ |
|
267 if (param_value != NULL) |
|
268 if ((param_direction == function_param_iterator_c::direction_in) || |
|
269 (param_direction == function_param_iterator_c::direction_inout)) { |
|
270 symbol->fb_name->accept(*this); |
|
271 s4o.print("."); |
|
272 param_name->accept(*this); |
|
273 s4o.print(" = "); |
|
274 param_value->accept(*this); |
|
275 s4o.print(";\n" + s4o.indent_spaces); |
|
276 } |
|
277 } /* for(...) */ |
|
278 |
|
279 /* now call the function... */ |
|
280 function_block_type_name->accept(*this); |
|
281 s4o.print(FB_FUNCTION_SUFFIX); |
|
282 s4o.print("(&"); |
|
283 symbol->fb_name->accept(*this); |
|
284 s4o.print(")"); |
|
285 |
|
286 /* loop through each function parameter, find the variable to which |
|
287 * we should atribute the value of all output or inoutput parameters. |
|
288 */ |
|
289 fp_iterator.reset(); |
|
290 function_call_param_iterator.reset(); |
|
291 for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { |
|
292 function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); |
|
293 |
|
294 /* Get the value from a foo(<param_name> = <param_value>) style call */ |
|
295 symbol_c *param_value = function_call_param_iterator.search(param_name); |
|
296 |
|
297 /* Get the value from a foo(<param_value>) style call */ |
|
298 if (param_value == NULL) |
|
299 param_value = function_call_param_iterator.next(); |
|
300 |
|
301 /* now output the value assignment */ |
|
302 if (param_value != NULL) |
|
303 if ((param_direction == function_param_iterator_c::direction_out) || |
|
304 (param_direction == function_param_iterator_c::direction_inout)) { |
|
305 s4o.print(";\n"+ s4o.indent_spaces); |
|
306 param_value->accept(*this); |
|
307 s4o.print(" = "); |
|
308 symbol->fb_name->accept(*this); |
|
309 s4o.print("."); |
|
310 param_name->accept(*this); |
|
311 } |
|
312 } /* for(...) */ |
|
313 |
|
314 return NULL; |
|
315 } |
|
316 |
|
317 |
|
318 |
|
319 |
|
320 /* helper symbol for fb_invocation */ |
|
321 /* param_assignment_list ',' param_assignment */ |
|
322 void *visit(param_assignment_list_c *symbol) { |
|
323 TRACE("param_assignment_list_c"); |
|
324 /* this should never be called... */ |
|
325 ERROR; |
|
326 return NULL; |
|
327 // return print_list(symbol, "", ", "); |
|
328 } |
|
329 |
|
330 |
|
331 void *visit(input_variable_param_assignment_c *symbol) { |
|
332 TRACE("input_variable_param_assignment_c"); |
|
333 /* this should never be called... */ |
|
334 ERROR; |
|
335 return NULL; |
|
336 /* |
|
337 symbol->variable_name->accept(*this); |
|
338 s4o.print(" = "); |
|
339 symbol->expression->accept(*this); |
|
340 return NULL; |
|
341 */ |
|
342 } |
|
343 |
|
344 void *visit(output_variable_param_assignment_c *symbol) { |
|
345 TRACE("output_variable_param_assignment_c"); |
|
346 /* this should never be called... */ |
|
347 ERROR; |
|
348 return NULL; |
|
349 /* |
|
350 s4o.print(s4o.indent_spaces); |
|
351 if (symbol->not_param != NULL) |
|
352 symbol->not_param->accept(*this); |
|
353 symbol->variable_name->accept(*this); |
|
354 s4o.print(" => "); |
|
355 symbol->variable->accept(*this); |
|
356 return NULL; |
|
357 */ |
|
358 } |
|
359 |
|
360 // TODO: the NOT symbol in function (block) calls... |
|
361 void *visit(not_paramassign_c *symbol) { |
|
362 TRACE("not_paramassign_c"); |
|
363 /* this should never be called... */ |
|
364 ERROR; |
|
365 return NULL; |
|
366 /* |
|
367 s4o.print("NOT "); |
|
368 return NULL; |
|
369 */ |
|
370 } |
|
371 |
|
372 |
|
373 /********************************/ |
|
374 /* B 3.2.3 Selection Statements */ |
|
375 /********************************/ |
|
376 void *visit(if_statement_c *symbol) { |
|
377 s4o.print("if ("); |
|
378 symbol->expression->accept(*this); |
|
379 s4o.print(") {\n"); |
|
380 s4o.indent_right(); |
|
381 symbol->statement_list->accept(*this); |
|
382 s4o.indent_left(); |
|
383 symbol->elseif_statement_list->accept(*this); |
|
384 |
|
385 if (symbol->else_statement_list != NULL) { |
|
386 s4o.print(s4o.indent_spaces); s4o.print("} else {\n"); |
|
387 s4o.indent_right(); |
|
388 symbol->else_statement_list->accept(*this); |
|
389 s4o.indent_left(); |
|
390 } |
|
391 s4o.print(s4o.indent_spaces); s4o.print("}"); |
|
392 return NULL; |
|
393 } |
|
394 |
|
395 /* helper symbol for if_statement */ |
|
396 void *visit(elseif_statement_list_c *symbol) {return print_list(symbol);} |
|
397 |
|
398 /* helper symbol for elseif_statement_list */ |
|
399 void *visit(elseif_statement_c *symbol) { |
|
400 s4o.print(s4o.indent_spaces); s4o.print("} else if ("); |
|
401 symbol->expression->accept(*this); |
|
402 s4o.print(") {\n"); |
|
403 s4o.indent_right(); |
|
404 symbol->statement_list->accept(*this); |
|
405 s4o.indent_left(); |
|
406 return NULL; |
|
407 } |
|
408 |
|
409 void *visit(case_statement_c *symbol) { |
|
410 s4o.print("switch("); |
|
411 symbol->expression->accept(*this); |
|
412 s4o.print(") {\n"); |
|
413 s4o.indent_right(); |
|
414 symbol->case_element_list->accept(*this); |
|
415 if (symbol->statement_list != NULL) { |
|
416 s4o.print(s4o.indent_spaces + "default:\n"); |
|
417 s4o.indent_right(); |
|
418 symbol->statement_list->accept(*this); |
|
419 s4o.print(s4o.indent_spaces + "break;\n"); |
|
420 s4o.indent_left(); |
|
421 } |
|
422 s4o.indent_left(); |
|
423 s4o.print(s4o.indent_spaces + "}"); |
|
424 return NULL; |
|
425 } |
|
426 |
|
427 /* helper symbol for case_statement */ |
|
428 void *visit(case_element_list_c *symbol) {return print_list(symbol);} |
|
429 |
|
430 void *visit(case_element_c *symbol) { |
|
431 s4o.print(s4o.indent_spaces + "case "); |
|
432 symbol->case_list->accept(*this); |
|
433 s4o.print(" :\n"); |
|
434 s4o.indent_right(); |
|
435 symbol->statement_list->accept(*this); |
|
436 s4o.print(s4o.indent_spaces + "break;\n"); |
|
437 s4o.indent_left(); |
|
438 return NULL; |
|
439 } |
|
440 |
|
441 void *visit(case_list_c *symbol) {return print_list(symbol, "", ", ");} |
|
442 |
|
443 /********************************/ |
|
444 /* B 3.2.4 Iteration Statements */ |
|
445 /********************************/ |
|
446 void *visit(for_statement_c *symbol) { |
|
447 s4o.print("for("); |
|
448 symbol->control_variable->accept(*this); |
|
449 s4o.print(" = "); |
|
450 symbol->beg_expression->accept(*this); |
|
451 s4o.print("; "); |
|
452 symbol->control_variable->accept(*this); |
|
453 s4o.print(" != "); |
|
454 symbol->end_expression->accept(*this); |
|
455 s4o.print("; "); |
|
456 symbol->control_variable->accept(*this); |
|
457 if (symbol->by_expression != NULL) { |
|
458 s4o.print(" += "); |
|
459 symbol->by_expression->accept(*this); |
|
460 } else { |
|
461 s4o.print("++"); |
|
462 } |
|
463 s4o.print(") {\n"); |
|
464 s4o.indent_right(); |
|
465 symbol->statement_list->accept(*this); |
|
466 s4o.indent_left(); |
|
467 s4o.print(s4o.indent_spaces); s4o.print("}"); |
|
468 return NULL; |
|
469 } |
|
470 void *visit(while_statement_c *symbol) { |
|
471 s4o.print("while ("); |
|
472 symbol->expression->accept(*this); |
|
473 s4o.print(") {\n"); |
|
474 s4o.indent_right(); |
|
475 symbol->statement_list->accept(*this); |
|
476 s4o.indent_left(); |
|
477 s4o.print(s4o.indent_spaces); s4o.print("}"); |
|
478 return NULL; |
|
479 } |
|
480 void *visit(repeat_statement_c *symbol) { |
|
481 s4o.print("do {\n"); |
|
482 s4o.indent_right(); |
|
483 symbol->statement_list->accept(*this); |
|
484 s4o.indent_left(); |
|
485 s4o.print(s4o.indent_spaces); s4o.print("} while("); |
|
486 symbol->expression->accept(*this); |
|
487 s4o.print(")"); |
|
488 return NULL; |
|
489 } |
|
490 void *visit(exit_statement_c *symbol) { |
|
491 s4o.print("exit(0)"); |
|
492 return NULL; |
|
493 } |
|
494 |
|
495 |
|
496 |
|
497 }; /* generate_cc_st_c */ |
|
498 |
|
499 |
|
500 |
|
501 |
|
502 |
|
503 |
|
504 |
|
505 |
|
506 |