|
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 * Function parameter iterator. |
|
28 * Iterate through the in/out parameters of a function declaration. |
|
29 * Function blocks are also suported. |
|
30 * |
|
31 * This is part of the 4th stage that generates |
|
32 * a c++ source program equivalent to the IL and ST |
|
33 * code. |
|
34 */ |
|
35 |
|
36 /* Given a function_declaration_c, iterate through each |
|
37 * function in/out/inout parameter, returning the name |
|
38 * of each parameter...function_param_iterator_c |
|
39 */ |
|
40 |
|
41 |
|
42 |
|
43 #include "function_param_iterator.hh" |
|
44 #include "spec_init_separator.hh" |
|
45 #include <strings.h> |
|
46 |
|
47 |
|
48 //#define DEBUG |
|
49 #ifdef DEBUG |
|
50 #define TRACE(classname) printf("\n____%s____\n",classname); |
|
51 #else |
|
52 #define TRACE(classname) |
|
53 #endif |
|
54 |
|
55 |
|
56 #define ERROR error_exit(__FILE__,__LINE__) |
|
57 /* function defined in main.cc */ |
|
58 extern void error_exit(const char *file_name, int line_no); |
|
59 |
|
60 |
|
61 |
|
62 void* function_param_iterator_c::handle_param_list(list_c *list) { |
|
63 if (next_param <= param_count + list->n) |
|
64 return list->elements[next_param - param_count - 1]; |
|
65 |
|
66 /* the desired param is not on this list... */ |
|
67 param_count += list->n; |
|
68 return NULL; |
|
69 } |
|
70 |
|
71 void* function_param_iterator_c::handle_single_param(symbol_c *var_name) { |
|
72 param_count++; |
|
73 if (next_param == param_count) |
|
74 return var_name; |
|
75 |
|
76 /* not yet the desired param... */ |
|
77 return NULL; |
|
78 } |
|
79 |
|
80 void* function_param_iterator_c::iterate_list(list_c *list) { |
|
81 void *res; |
|
82 for (int i = 0; i < list->n; i++) { |
|
83 res = list->elements[i]->accept(*this); |
|
84 if (res != NULL) |
|
85 return res; |
|
86 } |
|
87 return NULL; |
|
88 } |
|
89 |
|
90 /* start off at the first parameter once again... */ |
|
91 void function_param_iterator_c::reset(void) { |
|
92 next_param = param_count = 0; |
|
93 current_param_name = NULL; |
|
94 current_param_type = current_param_default_value = NULL; |
|
95 en_declared = false; |
|
96 eno_declared = false; |
|
97 } |
|
98 |
|
99 /* initialise the iterator object. |
|
100 * We must be given a reference to the function declaration |
|
101 * that will be analysed... |
|
102 */ |
|
103 function_param_iterator_c::function_param_iterator_c(function_declaration_c *f_decl) { |
|
104 this->f_decl = f_decl; |
|
105 reset(); |
|
106 } |
|
107 |
|
108 /* initialise the iterator object. |
|
109 * We must be given a reference to the function block declaration |
|
110 * that will be analysed... |
|
111 */ |
|
112 function_param_iterator_c::function_param_iterator_c(function_block_declaration_c *fb_decl) { |
|
113 this->f_decl = fb_decl; |
|
114 reset(); |
|
115 } |
|
116 |
|
117 /* initialise the iterator object. |
|
118 * We must be given a reference to the program declaration |
|
119 * that will be analysed... |
|
120 */ |
|
121 function_param_iterator_c::function_param_iterator_c(program_declaration_c *p_decl) { |
|
122 this->f_decl = p_decl; |
|
123 reset(); |
|
124 } |
|
125 |
|
126 /* Skip to the next parameter. After object creation, |
|
127 * the object references on parameter _before_ the first, so |
|
128 * this function must be called once to get the object to |
|
129 * reference the first parameter... |
|
130 * |
|
131 * Returns the parameter's name! |
|
132 */ |
|
133 identifier_c *function_param_iterator_c::next(void) { |
|
134 void *res; |
|
135 identifier_c *identifier; |
|
136 param_count = 0; |
|
137 next_param++; |
|
138 res = f_decl->accept(*this); |
|
139 if (res != NULL) { |
|
140 symbol_c *sym = (symbol_c *)res; |
|
141 identifier = dynamic_cast<identifier_c *>(sym); |
|
142 if (identifier == NULL) |
|
143 ERROR; |
|
144 } |
|
145 else if (!en_declared) { |
|
146 current_param_direction = direction_in; |
|
147 identifier = declare_en_param(); |
|
148 } |
|
149 else if (!eno_declared) { |
|
150 current_param_direction = direction_out; |
|
151 identifier = declare_eno_param(); |
|
152 } |
|
153 else |
|
154 return NULL; |
|
155 |
|
156 current_param_name = identifier; |
|
157 return current_param_name; |
|
158 } |
|
159 |
|
160 identifier_c *function_param_iterator_c::declare_en_param(void) { |
|
161 en_declared = true; |
|
162 identifier_c *identifier = new identifier_c("EN"); |
|
163 current_param_type = (symbol_c*)(new bool_type_name_c()); |
|
164 current_param_default_value = (symbol_c*)(new boolean_literal_c(current_param_type, new boolean_true_c())); |
|
165 return identifier; |
|
166 } |
|
167 |
|
168 identifier_c *function_param_iterator_c::declare_eno_param(void) { |
|
169 eno_declared = true; |
|
170 identifier_c *identifier = new identifier_c("ENO"); |
|
171 current_param_type = (symbol_c*)(new bool_type_name_c()); |
|
172 current_param_default_value = NULL; |
|
173 return identifier; |
|
174 } |
|
175 |
|
176 /* Returns the currently referenced parameter's default value, |
|
177 * or NULL if none is specified in the function declrataion itself. |
|
178 */ |
|
179 symbol_c *function_param_iterator_c::default_value(void) { |
|
180 return current_param_default_value; |
|
181 } |
|
182 |
|
183 /* Returns the currently referenced parameter's type name. */ |
|
184 symbol_c *function_param_iterator_c::param_type(void) { |
|
185 return current_param_type; |
|
186 } |
|
187 |
|
188 /* Returns the currently referenced parameter's data passing direction. |
|
189 * i.e. VAR_INPUT, VAR_OUTPUT or VAR_INOUT |
|
190 */ |
|
191 function_param_iterator_c::param_direction_t function_param_iterator_c::param_direction(void) { |
|
192 return current_param_direction; |
|
193 } |
|
194 |
|
195 /****************************************/ |
|
196 /* 1.4.3 - Declaration & Initialisation */ |
|
197 /****************************************/ |
|
198 void *function_param_iterator_c::visit(input_declarations_c *symbol) { |
|
199 TRACE("input_declarations_c"); |
|
200 current_param_direction = direction_in; |
|
201 return symbol->input_declaration_list->accept(*this); |
|
202 } |
|
203 |
|
204 void *function_param_iterator_c::visit(input_declaration_list_c *symbol) {TRACE("input_declaration_list_c"); return iterate_list(symbol);} |
|
205 |
|
206 void *function_param_iterator_c::visit(edge_declaration_c *symbol) {TRACE("edge_declaration_c"); return symbol->var1_list->accept(*this);} |
|
207 |
|
208 void *function_param_iterator_c::visit(en_param_declaration_c *symbol) { |
|
209 TRACE("en_param_declaration_c"); |
|
210 if (en_declared) ERROR; |
|
211 return (void *)declare_en_param(); |
|
212 } |
|
213 |
|
214 /* var1_list ':' array_spec_init */ |
|
215 //SYM_REF2(array_var_init_decl_c, var1_list, array_spec_init) |
|
216 void *function_param_iterator_c::visit(array_var_init_decl_c *symbol) {TRACE("array_var_init_decl_c"); return symbol->var1_list->accept(*this);} |
|
217 |
|
218 /* var1_list ':' initialized_structure */ |
|
219 //SYM_REF2(structured_var_init_decl_c, var1_list, initialized_structure) |
|
220 void *function_param_iterator_c::visit(structured_var_init_decl_c *symbol) {TRACE("structured_var_init_decl_c"); return symbol->var1_list->accept(*this);} |
|
221 |
|
222 void *function_param_iterator_c::visit(output_declarations_c *symbol) { |
|
223 TRACE("output_declarations_c"); |
|
224 current_param_direction = direction_out; |
|
225 return symbol->var_init_decl_list->accept(*this); |
|
226 } |
|
227 void *function_param_iterator_c::visit(eno_param_declaration_c *symbol) { |
|
228 TRACE("eno_param_declaration_c"); |
|
229 if (eno_declared) ERROR; |
|
230 return (void *)declare_eno_param(); |
|
231 } |
|
232 void *function_param_iterator_c::visit(input_output_declarations_c *symbol) { |
|
233 TRACE("input_output_declarations_c"); |
|
234 current_param_direction = direction_inout; |
|
235 return symbol->var_declaration_list->accept(*this); |
|
236 } |
|
237 void *function_param_iterator_c::visit(var_declaration_list_c *symbol) {TRACE("var_declaration_list_c"); return iterate_list(symbol);} |
|
238 |
|
239 /* var1_list ':' array_specification */ |
|
240 //SYM_REF2(array_var_declaration_c, var1_list, array_specification) |
|
241 void *function_param_iterator_c::visit(array_var_declaration_c *symbol) {TRACE("array_var_declaration_c"); return symbol->var1_list->accept(*this);} |
|
242 |
|
243 /* var1_list ':' structure_type_name */ |
|
244 //SYM_REF2(structured_var_declaration_c, var1_list, structure_type_name) |
|
245 void *function_param_iterator_c::visit(structured_var_declaration_c *symbol) {TRACE("structured_var_declaration_c"); return symbol->var1_list->accept(*this);} |
|
246 |
|
247 /* VAR [CONSTANT] var_init_decl_list END_VAR */ |
|
248 void *function_param_iterator_c::visit(var_declarations_c *symbol) {TRACE("var_declarations_c"); return NULL;} |
|
249 |
|
250 /*| VAR_EXTERNAL [CONSTANT] external_declaration_list END_VAR */ |
|
251 /* option -> may be NULL ! */ |
|
252 // SYM_REF2(external_var_declarations_c, option, external_declaration_list) |
|
253 void *function_param_iterator_c::visit(external_var_declarations_c *symbol) { |
|
254 TRACE("external_var_declarations_c"); |
|
255 current_param_direction = direction_extref; |
|
256 return symbol->external_declaration_list->accept(*this); |
|
257 } |
|
258 |
|
259 /* helper symbol for external_var_declarations */ |
|
260 /*| external_declaration_list external_declaration';' */ |
|
261 // SYM_LIST(external_declaration_list_c) |
|
262 void *function_param_iterator_c::visit(external_declaration_list_c *symbol) {TRACE("external_declaration_list_c"); return iterate_list(symbol);} |
|
263 |
|
264 /* global_var_name ':' (simple_specification|subrange_specification|enumerated_specification|array_specification|prev_declared_structure_type_name|function_block_type_name */ |
|
265 //SYM_REF2(external_declaration_c, global_var_name, specification) |
|
266 void *function_param_iterator_c::visit(external_declaration_c *symbol) { |
|
267 TRACE("external_declaration_c"); |
|
268 /* It is OK to store these values in the current_param_XXX |
|
269 * variables, because if the desired parameter is not in the |
|
270 * variable list we will be analysing, the current_param_XXXX |
|
271 * variables will get overwritten when we visit the next |
|
272 * var1_init_decl_c list! |
|
273 */ |
|
274 current_param_default_value = spec_init_sperator_c::get_init(symbol->specification); |
|
275 current_param_type = spec_init_sperator_c::get_spec(symbol->specification); |
|
276 |
|
277 return handle_single_param(symbol->global_var_name); |
|
278 } |
|
279 |
|
280 |
|
281 #if 0 |
|
282 /*| VAR_GLOBAL [CONSTANT|RETAIN] global_var_decl_list END_VAR */ |
|
283 /* option -> may be NULL ! */ |
|
284 SYM_REF2(global_var_declarations_c, option, global_var_decl_list) |
|
285 |
|
286 /* helper symbol for global_var_declarations */ |
|
287 /*| global_var_decl_list global_var_decl ';' */ |
|
288 SYM_LIST(global_var_decl_list_c) |
|
289 |
|
290 /*| global_var_spec ':' [located_var_spec_init|function_block_type_name] */ |
|
291 /* type_specification ->may be NULL ! */ |
|
292 SYM_REF2(global_var_decl_c, global_var_spec, type_specification) |
|
293 |
|
294 /*| global_var_name location */ |
|
295 SYM_REF2(global_var_spec_c, global_var_name, location) |
|
296 |
|
297 /* AT direct_variable */ |
|
298 SYM_REF2(location_c, direct_variable, unused) |
|
299 |
|
300 /*| global_var_list ',' global_var_name */ |
|
301 SYM_LIST(global_var_list_c) |
|
302 |
|
303 /* var1_list ':' single_byte_string_spec */ |
|
304 SYM_REF2(single_byte_string_var_declaration_c, var1_list, single_byte_string_spec) |
|
305 |
|
306 /* STRING ['[' integer ']'] [ASSIGN single_byte_character_string] */ |
|
307 /* integer ->may be NULL ! */ |
|
308 /* single_byte_character_string ->may be NULL ! */ |
|
309 SYM_REF2(single_byte_string_spec_c, integer, single_byte_character_string) |
|
310 |
|
311 /* var1_list ':' double_byte_string_spec */ |
|
312 SYM_REF2(double_byte_string_var_declaration_c, var1_list, double_byte_string_spec) |
|
313 |
|
314 /* WSTRING ['[' integer ']'] [ASSIGN double_byte_character_string] */ |
|
315 /* integer ->may be NULL ! */ |
|
316 /* double_byte_character_string ->may be NULL ! */ |
|
317 SYM_REF2(double_byte_string_spec_c, integer, double_byte_character_string) |
|
318 |
|
319 /*| VAR [RETAIN|NON_RETAIN] incompl_located_var_decl_list END_VAR */ |
|
320 /* option ->may be NULL ! */ |
|
321 SYM_REF2(incompl_located_var_declarations_c, option, incompl_located_var_decl_list) |
|
322 |
|
323 /* helper symbol for incompl_located_var_declarations */ |
|
324 /*| incompl_located_var_decl_list incompl_located_var_decl ';' */ |
|
325 SYM_LIST(incompl_located_var_decl_list_c) |
|
326 |
|
327 /* variable_name incompl_location ':' var_spec */ |
|
328 SYM_REF4(incompl_located_var_decl_c, variable_name, incompl_location, var_spec, unused) |
|
329 |
|
330 /* AT incompl_location_token */ |
|
331 SYM_TOKEN(incompl_location_c) |
|
332 #endif |
|
333 |
|
334 |
|
335 void *function_param_iterator_c::visit(var1_init_decl_c *symbol) { |
|
336 TRACE("var1_init_decl_c"); |
|
337 /* It is OK to store these values in the current_param_XXX |
|
338 * variables, because if the desired parameter is not in the |
|
339 * variable list we will be analysing, the current_param_XXXX |
|
340 * variables will get overwritten when we visit the next |
|
341 * var1_init_decl_c list! |
|
342 */ |
|
343 current_param_default_value = spec_init_sperator_c::get_init(symbol->spec_init); |
|
344 current_param_type = spec_init_sperator_c::get_spec(symbol->spec_init); |
|
345 |
|
346 return symbol->var1_list->accept(*this); |
|
347 } |
|
348 |
|
349 |
|
350 |
|
351 void *function_param_iterator_c::visit(var1_list_c *symbol) { |
|
352 TRACE("var1_list_c"); |
|
353 return handle_param_list(symbol); |
|
354 } |
|
355 |
|
356 void *function_param_iterator_c::visit(var_init_decl_list_c *symbol) {TRACE("var_init_decl_list_c"); return iterate_list(symbol);} |
|
357 |
|
358 |
|
359 /***********************/ |
|
360 /* B 1.5.1 - Functions */ |
|
361 /***********************/ |
|
362 void *function_param_iterator_c::visit(function_declaration_c *symbol) {TRACE("function_declaration_c"); return symbol->var_declarations_list->accept(*this);} |
|
363 /* intermediate helper symbol for function_declaration */ |
|
364 void *function_param_iterator_c::visit(var_declarations_list_c *symbol) {TRACE("var_declarations_list_c"); return iterate_list(symbol);} |
|
365 void *function_param_iterator_c::visit(function_var_decls_c *symbol) {TRACE("function_var_decls_c"); /* ignore */ return NULL;} |
|
366 |
|
367 |
|
368 /*****************************/ |
|
369 /* B 1.5.2 - Function Blocks */ |
|
370 /*****************************/ |
|
371 /* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */ |
|
372 void *function_param_iterator_c::visit(function_block_declaration_c *symbol) {TRACE("function_block_declaration_c"); return symbol->var_declarations->accept(*this);} |
|
373 |
|
374 /* intermediate helper symbol for function_declaration */ |
|
375 /* { io_var_declarations | other_var_declarations } */ |
|
376 /* |
|
377 * NOTE: we re-use the var_declarations_list_c |
|
378 */ |
|
379 |
|
380 /* VAR_TEMP temp_var_decl_list END_VAR */ |
|
381 void *function_param_iterator_c::visit(temp_var_decls_c *symbol) {TRACE("temp_var_decls_c"); /* ignore */ return NULL;} |
|
382 void *function_param_iterator_c::visit(temp_var_decls_list_c *symbol) {TRACE("temp_var_decls_list_c"); /* ignore */ return NULL;} |
|
383 |
|
384 /* VAR NON_RETAIN var_init_decl_list END_VAR */ |
|
385 void *function_param_iterator_c::visit(non_retentive_var_decls_c *symbol) {TRACE("non_retentive_var_decls_c"); /* ignore */ return NULL;} |
|
386 |
|
387 |
|
388 /**********************/ |
|
389 /* B 1.5.3 - Programs */ |
|
390 /**********************/ |
|
391 /* PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */ |
|
392 // SYM_REF4(program_declaration_c, program_type_name, var_declarations, function_block_body, unused) |
|
393 void *function_param_iterator_c::visit(program_declaration_c *symbol) {TRACE("program_declaration_c"); return symbol->var_declarations->accept(*this);} |
|
394 |
|
395 /* intermediate helper symbol for program_declaration_c */ |
|
396 /* { io_var_declarations | other_var_declarations } */ |
|
397 /* |
|
398 * NOTE: we re-use the var_declarations_list_c |
|
399 */ |
|
400 |
|
401 |
|
402 |
|
403 |
|
404 |
|
405 |