45 * function in/out/inout parameter, returning the name |
45 * function in/out/inout parameter, returning the name |
46 * of each parameter...function_param_iterator_c |
46 * of each parameter...function_param_iterator_c |
47 */ |
47 */ |
48 |
48 |
49 |
49 |
50 |
50 #include "function_param_iterator.hh" /* no longer required, aready included by absyntax_utils.hh */ |
51 #include "absyntax_utils.hh" /* required for extract_integer() */ |
51 #include "spec_init_separator.hh" /* no longer required, aready included by absyntax_utils.hh */ |
52 // #include "function_param_iterator.hh" /* no longer required, aready included by absyntax_utils.hh */ |
|
53 // #include "spec_init_separator.hh" /* no longer required, aready included by absyntax_utils.hh */ |
|
54 #include <stdlib.h> /* required for strtol() */ |
52 #include <stdlib.h> /* required for strtol() */ |
55 #include <string.h> |
53 #include <string.h> |
56 #include <strings.h> |
54 #include <strings.h> |
57 |
55 #include <limits> // required for std::numeric_limits< XXX >::max() |
|
56 #include <errno.h> // required for errno |
|
57 #include "../main.hh" // required for ERROR() and ERROR_MSG() macros. |
58 |
58 |
59 //#define DEBUG |
59 //#define DEBUG |
60 #ifdef DEBUG |
60 #ifdef DEBUG |
61 #define TRACE(classname) printf("\n____%s____\n",classname); |
61 #define TRACE(classname) printf("\n____%s____\n",classname); |
62 #else |
62 #else |
63 #define TRACE(classname) |
63 #define TRACE(classname) |
64 #endif |
64 #endif |
65 |
65 |
66 |
66 |
67 #define ERROR error_exit(__FILE__,__LINE__) |
67 |
68 /* function defined in main.cc */ |
68 |
69 extern void error_exit(const char *file_name, int line_no); |
69 |
|
70 /* NOTE: The following function is not really needed, as we could get the value that constant_folding_c determined for this |
|
71 * integer. Remember that currently constant_folding_c runs before this class is ever used/called! |
|
72 * However, I (Mario) do not currently feel it would be a good idea to restrict the use of this |
|
73 * abstract syntax utility to only after the constant_folding_c has had a chance to fill in the constant value |
|
74 * of this symbol. |
|
75 * For this reason only, I have opted to let this abstract syntax utility have its own private copy of the |
|
76 * extract_integer() function. |
|
77 * Another aspect that makes this OK is that this function will only be used to extract the integer value of the |
|
78 * index for the first extensible paramater (examples follow shortly). Since this is an extension to IEC 61131-3 |
|
79 * that we created to allow us to handle extensible functions with very little hard coding, it is OK if we |
|
80 * impose extra/different limits on how an integer may be legally be formated in this case. This will also |
|
81 * only show up in code that describes the interface to the standard function of IEC 61131-3, which the user |
|
82 * will not ever get to see. We write that IEC 61131-3 code ourselves! |
|
83 * |
|
84 * Example of source code we will be parsing and analysing: |
|
85 * |
|
86 * FUNCTION ADD : REAL VAR_INPUT IN 1 .. : REAL; END_VAR RETURN; END_FUNCTION |
|
87 * ^^^ |
|
88 * |
|
89 * FUNCTION MUX : REAL VAR_INPUT K : USINT; IN 0 .. : REAL; END_VAR RETURN; END_FUNCTION |
|
90 * ^^^ |
|
91 * |
|
92 * Basically, currently this will only be either a '0' or a '1' !! |
|
93 */ |
|
94 |
|
95 /* NOTE: it must ignore underscores! */ |
|
96 static int extract_first_index_value(symbol_c *sym) { |
|
97 std::string str = ""; |
|
98 integer_c *integer; |
|
99 long int ret; |
|
100 |
|
101 if ((integer = dynamic_cast<integer_c *>(sym)) == NULL) ERROR; |
|
102 for(unsigned int i = 0; i < strlen(integer->value); i++) |
|
103 if (integer->value[i] != '_') str += integer->value[i]; |
|
104 |
|
105 errno = 0; // since strtoXX() may legally return 0, we must set errno to 0 to detect errors correctly! |
|
106 ret = strtol(str.c_str(), NULL, 10); |
|
107 if (errno != 0) ERROR; |
|
108 if (ret < 0) ERROR; // the following code assumes that the first index will never be negative! |
|
109 if (ret > std::numeric_limits< int >::max()) ERROR; // output of this function is only an int!! |
|
110 |
|
111 return ret; |
|
112 } |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 |
|
118 |
|
119 |
70 |
120 |
71 |
121 |
72 |
122 |
73 /* compare the name of two __extensible__ function parameters. |
123 /* compare the name of two __extensible__ function parameters. |
74 * The usual use case is to have one of the parameters as used |
124 * The usual use case is to have one of the parameters as used |
128 symbol_c *sym = list->elements[i]; |
178 symbol_c *sym = list->elements[i]; |
129 extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(sym); |
179 extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(sym); |
130 if (extensible_parameter != NULL) { |
180 if (extensible_parameter != NULL) { |
131 sym = extensible_parameter->var_name; |
181 sym = extensible_parameter->var_name; |
132 current_param_is_extensible = true; |
182 current_param_is_extensible = true; |
133 _first_extensible_param_index = extract_integer(extensible_parameter->first_index); |
183 _first_extensible_param_index = extract_first_index_value(extensible_parameter->first_index); |
134 } |
184 } |
135 identifier_c *variable_name = dynamic_cast<identifier_c *>(sym); |
185 identifier_c *variable_name = dynamic_cast<identifier_c *>(sym); |
136 if (variable_name == NULL) ERROR; |
186 if (variable_name == NULL) ERROR; |
137 |
187 |
138 if (!current_param_is_extensible) |
188 if (!current_param_is_extensible) |
165 case search_op: |
215 case search_op: |
166 extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(var_name); |
216 extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(var_name); |
167 if (extensible_parameter != NULL) { |
217 if (extensible_parameter != NULL) { |
168 var_name = extensible_parameter->var_name; |
218 var_name = extensible_parameter->var_name; |
169 current_param_is_extensible = true; |
219 current_param_is_extensible = true; |
170 _first_extensible_param_index = extract_integer(extensible_parameter->first_index); |
220 _first_extensible_param_index = extract_first_index_value(extensible_parameter->first_index); |
171 } |
221 } |
172 identifier_c *variable_name = dynamic_cast<identifier_c *>(var_name); |
222 identifier_c *variable_name = dynamic_cast<identifier_c *>(var_name); |
173 if (variable_name == NULL) ERROR; |
223 if (variable_name == NULL) ERROR; |
174 |
224 |
175 if (!current_param_is_extensible) |
225 if (!current_param_is_extensible) |
204 void function_param_iterator_c::reset(void) { |
254 void function_param_iterator_c::reset(void) { |
205 next_param = param_count = 0; |
255 next_param = param_count = 0; |
206 _first_extensible_param_index = -1; |
256 _first_extensible_param_index = -1; |
207 current_param_is_extensible = false; |
257 current_param_is_extensible = false; |
208 current_param_name = NULL; |
258 current_param_name = NULL; |
209 current_param_type = current_param_default_value = NULL; |
259 current_param_type = NULL; |
|
260 current_param_default_value = NULL; |
|
261 last_returned_parameter = NULL; /* the last parameter returned by search() or next() */ |
210 } |
262 } |
211 |
263 |
212 |
264 |
213 /* initialise the iterator object. |
265 /* initialise the iterator object. |
214 * We must be given a reference to one of the following |
266 * We must be given a reference to one of the following |
221 /* do some consistency checks... */ |
273 /* do some consistency checks... */ |
222 function_declaration_c * f_decl = dynamic_cast<function_declaration_c *>(pou_decl); |
274 function_declaration_c * f_decl = dynamic_cast<function_declaration_c *>(pou_decl); |
223 function_block_declaration_c *fb_decl = dynamic_cast<function_block_declaration_c *>(pou_decl); |
275 function_block_declaration_c *fb_decl = dynamic_cast<function_block_declaration_c *>(pou_decl); |
224 program_declaration_c * p_decl = dynamic_cast<program_declaration_c *>(pou_decl); |
276 program_declaration_c * p_decl = dynamic_cast<program_declaration_c *>(pou_decl); |
225 |
277 |
226 if ((NULL == f_decl) && (NULL == fb_decl) && (NULL == p_decl)) ERROR; |
278 if ((NULL == f_decl) && (NULL == fb_decl) && (NULL == p_decl)) |
|
279 ERROR; |
227 |
280 |
228 /* OK. Now initialise this object... */ |
281 /* OK. Now initialise this object... */ |
229 this->f_decl = pou_decl; |
282 this->f_decl = pou_decl; |
230 reset(); |
283 reset(); |
231 } |
284 } |
259 symbol_c *sym = (symbol_c *)res; |
313 symbol_c *sym = (symbol_c *)res; |
260 extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(sym); |
314 extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(sym); |
261 if (extensible_parameter != NULL) { |
315 if (extensible_parameter != NULL) { |
262 sym = extensible_parameter->var_name; |
316 sym = extensible_parameter->var_name; |
263 current_param_is_extensible = true; |
317 current_param_is_extensible = true; |
264 _first_extensible_param_index = extract_integer(extensible_parameter->first_index); |
318 _first_extensible_param_index = extract_first_index_value(extensible_parameter->first_index); |
265 current_extensible_param_index = _first_extensible_param_index; |
319 current_extensible_param_index = _first_extensible_param_index; |
266 } |
320 } |
267 identifier = dynamic_cast<identifier_c *>(sym); |
321 identifier = dynamic_cast<identifier_c *>(sym); |
268 if (identifier == NULL) |
322 if (identifier == NULL) |
269 ERROR; |
323 ERROR; |
270 current_param_name = identifier; |
324 current_param_name = identifier; |
|
325 last_returned_parameter = current_param_name; |
271 return current_param_name; |
326 return current_param_name; |
272 } |
327 } |
273 |
328 |
274 /* Search for the value passed to the parameter named <param_name>... */ |
329 /* Search for the value passed to the parameter named <param_name>... */ |
275 identifier_c *function_param_iterator_c::search(symbol_c *param_name) { |
330 identifier_c *function_param_iterator_c::search(symbol_c *param_name) { |
279 en_eno_param_implicit = false; |
334 en_eno_param_implicit = false; |
280 current_param_is_extensible = false; |
335 current_param_is_extensible = false; |
281 current_operation = function_param_iterator_c::search_op; |
336 current_operation = function_param_iterator_c::search_op; |
282 void *res = f_decl->accept(*this); |
337 void *res = f_decl->accept(*this); |
283 identifier_c *res_param_name = dynamic_cast<identifier_c *>((symbol_c *)res); |
338 identifier_c *res_param_name = dynamic_cast<identifier_c *>((symbol_c *)res); |
|
339 last_returned_parameter = res_param_name; |
284 return res_param_name; |
340 return res_param_name; |
285 } |
341 } |
|
342 |
|
343 identifier_c *function_param_iterator_c::search(const char *param_name) { |
|
344 identifier_c param_name_id(param_name); |
|
345 return search(¶m_name_id); |
|
346 } |
|
347 |
|
348 |
286 |
349 |
287 /* Returns the currently referenced parameter's default value, |
350 /* Returns the currently referenced parameter's default value, |
288 * or NULL if none is specified in the function declrataion itself. |
351 * or NULL if none is specified in the function declrataion itself. |
289 */ |
352 */ |
290 symbol_c *function_param_iterator_c::default_value(void) { |
353 symbol_c *function_param_iterator_c::default_value(void) { |
|
354 if (NULL == last_returned_parameter) |
|
355 return NULL; |
291 return current_param_default_value; |
356 return current_param_default_value; |
292 } |
357 } |
293 |
358 |
294 /* Returns the currently referenced parameter's type name. */ |
359 /* Returns the currently referenced parameter's type name. */ |
295 symbol_c *function_param_iterator_c::param_type(void) { |
360 symbol_c *function_param_iterator_c::param_type(void) { |
|
361 if (NULL == last_returned_parameter) |
|
362 return NULL; |
296 return current_param_type; |
363 return current_param_type; |
297 } |
364 } |
298 |
365 |
299 /* Returns if currently referenced parameter is an implicit defined EN/ENO parameter. */ |
366 /* Returns if currently referenced parameter is an implicit defined EN/ENO parameter. */ |
300 bool function_param_iterator_c::is_en_eno_param_implicit(void) { |
367 bool function_param_iterator_c::is_en_eno_param_implicit(void) { |
|
368 if (NULL == last_returned_parameter) |
|
369 ERROR; |
301 return en_eno_param_implicit; |
370 return en_eno_param_implicit; |
302 } |
371 } |
303 |
372 |
304 /* Returns if currently referenced parameter is an extensible parameter. */ |
373 /* Returns if currently referenced parameter is an extensible parameter. */ |
305 /* extensible paramters only occur in some standard functions, e.g. AND(word#34, word#44, word#65); */ |
374 /* extensible paramters only occur in some standard functions, e.g. AND(word#34, word#44, word#65); */ |
306 bool function_param_iterator_c::is_extensible_param(void) { |
375 bool function_param_iterator_c::is_extensible_param(void) { |
|
376 if (NULL == last_returned_parameter) |
|
377 ERROR; |
307 return current_param_is_extensible; |
378 return current_param_is_extensible; |
308 } |
379 } |
309 |
380 |
310 /* Returns the index of the current extensible parameter. */ |
381 /* Returns the index of the current extensible parameter. */ |
311 /* If the current parameter is not an extensible paramter, returns -1 */ |
382 /* If the current parameter is not an extensible paramter, returns -1 */ |
312 int function_param_iterator_c::extensible_param_index(void) { |
383 int function_param_iterator_c::extensible_param_index(void) { |
|
384 if (NULL == last_returned_parameter) |
|
385 ERROR; |
313 return (current_param_is_extensible? current_extensible_param_index : -1); |
386 return (current_param_is_extensible? current_extensible_param_index : -1); |
314 } |
387 } |
315 |
388 |
316 /* Returns the index of the first extensible parameter, or -1 if no extensible parameter found. */ |
389 /* Returns the index of the first extensible parameter, or -1 if no extensible parameter found. */ |
317 /* WARNING: Will only return the correct value _after_ an extensible parameter has been found! */ |
390 /* WARNING: Will only return the correct value _after_ an extensible parameter has been found! */ |
321 |
394 |
322 /* Returns the currently referenced parameter's data passing direction. |
395 /* Returns the currently referenced parameter's data passing direction. |
323 * i.e. VAR_INPUT, VAR_OUTPUT or VAR_INOUT |
396 * i.e. VAR_INPUT, VAR_OUTPUT or VAR_INOUT |
324 */ |
397 */ |
325 function_param_iterator_c::param_direction_t function_param_iterator_c::param_direction(void) { |
398 function_param_iterator_c::param_direction_t function_param_iterator_c::param_direction(void) { |
|
399 if (NULL == last_returned_parameter) |
|
400 ERROR; |
326 return current_param_direction; |
401 return current_param_direction; |
327 } |
402 } |
328 |
403 |
329 void *function_param_iterator_c::visit(implicit_definition_c *symbol) { |
404 void *function_param_iterator_c::visit(implicit_definition_c *symbol) { |
330 en_eno_param_implicit = true; |
405 en_eno_param_implicit = true; |