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 |
58 |
57 |
59 //#define DEBUG |
58 //#define DEBUG |
60 #ifdef DEBUG |
59 #ifdef DEBUG |
61 #define TRACE(classname) printf("\n____%s____\n",classname); |
60 #define TRACE(classname) printf("\n____%s____\n",classname); |
62 #else |
61 #else |
65 |
64 |
66 |
65 |
67 #define ERROR error_exit(__FILE__,__LINE__) |
66 #define ERROR error_exit(__FILE__,__LINE__) |
68 /* function defined in main.cc */ |
67 /* function defined in main.cc */ |
69 extern void error_exit(const char *file_name, int line_no); |
68 extern void error_exit(const char *file_name, int line_no); |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 /* NOTE: The following function is not really needed, as we could get the value that constant_folding_c determined for this |
|
75 * integer. Remember that currently constant_folding_c runs before this class is ever used/called! |
|
76 * However, I (Mario) do not currently feel it would be a good idea to restrict the use of this |
|
77 * abstract syntax utility to only after the constant_folding_c has had a chance to fill in the constant value |
|
78 * of this symbol. |
|
79 * For this reason only, I have opted to let this abstract syntax utility have its own private copy of the |
|
80 * extract_integer() function. |
|
81 * Another aspect that makes this OK is that this function will only be used to extract the integer value of the |
|
82 * index for the first extensible paramater (examples follow shortly). Since this is an extension to IEC 61131-3 |
|
83 * that we created to allow us to handle extensible functions with very little hard coding, it is OK if we |
|
84 * impose extra/different limits on how an integer may be legally be formated in this case. This will also |
|
85 * only show up in code that describes the interface to the standard function of IEC 61131-3, which the user |
|
86 * will not ever get to see. We write that IEC 61131-3 code ourselves! |
|
87 * |
|
88 * Example of source code we will be parsing and analysing: |
|
89 * |
|
90 * FUNCTION ADD : REAL VAR_INPUT IN 1 .. : REAL; END_VAR RETURN; END_FUNCTION |
|
91 * ^^^ |
|
92 * |
|
93 * FUNCTION MUX : REAL VAR_INPUT K : USINT; IN 0 .. : REAL; END_VAR RETURN; END_FUNCTION |
|
94 * ^^^ |
|
95 * |
|
96 * Basically, currently this will only be either a '0' or a '1' !! |
|
97 */ |
|
98 |
|
99 /* NOTE: it must ignore underscores! */ |
|
100 static int extract_first_index_value(symbol_c *sym) { |
|
101 std::string str = ""; |
|
102 integer_c *integer; |
|
103 long int ret; |
|
104 |
|
105 if ((integer = dynamic_cast<integer_c *>(sym)) == NULL) ERROR; |
|
106 for(unsigned int i = 0; i < strlen(integer->value); i++) |
|
107 if (integer->value[i] != '_') str += integer->value[i]; |
|
108 |
|
109 errno = 0; // since strtoXX() may legally return 0, we must set errno to 0 to detect errors correctly! |
|
110 ret = strtol(str.c_str(), NULL, 10); |
|
111 if (errno != 0) ERROR; |
|
112 if (ret < 0) ERROR; // the following code assumes that the first index will never be negative! |
|
113 if (ret > std::numeric_limits< int >::max()) ERROR; // output of this function is only an int!! |
|
114 |
|
115 return ret; |
|
116 } |
|
117 |
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
70 |
124 |
71 |
125 |
72 |
126 |
73 /* compare the name of two __extensible__ function parameters. |
127 /* compare the name of two __extensible__ function parameters. |
74 * The usual use case is to have one of the parameters as used |
128 * The usual use case is to have one of the parameters as used |
128 symbol_c *sym = list->elements[i]; |
182 symbol_c *sym = list->elements[i]; |
129 extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(sym); |
183 extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(sym); |
130 if (extensible_parameter != NULL) { |
184 if (extensible_parameter != NULL) { |
131 sym = extensible_parameter->var_name; |
185 sym = extensible_parameter->var_name; |
132 current_param_is_extensible = true; |
186 current_param_is_extensible = true; |
133 _first_extensible_param_index = extract_int64_value(extensible_parameter->first_index); |
187 _first_extensible_param_index = extract_first_index_value(extensible_parameter->first_index); |
134 } |
188 } |
135 identifier_c *variable_name = dynamic_cast<identifier_c *>(sym); |
189 identifier_c *variable_name = dynamic_cast<identifier_c *>(sym); |
136 if (variable_name == NULL) ERROR; |
190 if (variable_name == NULL) ERROR; |
137 |
191 |
138 if (!current_param_is_extensible) |
192 if (!current_param_is_extensible) |
165 case search_op: |
219 case search_op: |
166 extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(var_name); |
220 extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(var_name); |
167 if (extensible_parameter != NULL) { |
221 if (extensible_parameter != NULL) { |
168 var_name = extensible_parameter->var_name; |
222 var_name = extensible_parameter->var_name; |
169 current_param_is_extensible = true; |
223 current_param_is_extensible = true; |
170 _first_extensible_param_index = extract_int64_value(extensible_parameter->first_index); |
224 _first_extensible_param_index = extract_first_index_value(extensible_parameter->first_index); |
171 } |
225 } |
172 identifier_c *variable_name = dynamic_cast<identifier_c *>(var_name); |
226 identifier_c *variable_name = dynamic_cast<identifier_c *>(var_name); |
173 if (variable_name == NULL) ERROR; |
227 if (variable_name == NULL) ERROR; |
174 |
228 |
175 if (!current_param_is_extensible) |
229 if (!current_param_is_extensible) |
263 symbol_c *sym = (symbol_c *)res; |
317 symbol_c *sym = (symbol_c *)res; |
264 extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(sym); |
318 extensible_input_parameter_c *extensible_parameter = dynamic_cast<extensible_input_parameter_c *>(sym); |
265 if (extensible_parameter != NULL) { |
319 if (extensible_parameter != NULL) { |
266 sym = extensible_parameter->var_name; |
320 sym = extensible_parameter->var_name; |
267 current_param_is_extensible = true; |
321 current_param_is_extensible = true; |
268 _first_extensible_param_index = extract_int64_value(extensible_parameter->first_index); |
322 _first_extensible_param_index = extract_first_index_value(extensible_parameter->first_index); |
269 current_extensible_param_index = _first_extensible_param_index; |
323 current_extensible_param_index = _first_extensible_param_index; |
270 } |
324 } |
271 identifier = dynamic_cast<identifier_c *>(sym); |
325 identifier = dynamic_cast<identifier_c *>(sym); |
272 if (identifier == NULL) |
326 if (identifier == NULL) |
273 ERROR; |
327 ERROR; |