112 /* Note that if symbol is pointing to an expression (or simply a literal value), it will return a NULL. |
112 /* Note that if symbol is pointing to an expression (or simply a literal value), it will return a NULL. |
113 * Once we have implemented the check_assignment_to_expression() method, and abort calling the other checks (including this one) |
113 * Once we have implemented the check_assignment_to_expression() method, and abort calling the other checks (including this one) |
114 * when an expression is found, we may replace this check with an assertion... |
114 * when an expression is found, we may replace this check with an assertion... |
115 * if (NULL == struct_elem) ERROR; |
115 * if (NULL == struct_elem) ERROR; |
116 */ |
116 */ |
117 symbol_c *struct_elem = decompose_lvalue.next_part(); |
117 symbol_c *struct_elem = decompose_lvalue.get_next(); |
118 if (NULL == struct_elem) return; |
118 if (NULL == struct_elem) return; |
119 |
119 |
120 symbol_c *type_decl = search_var_instance_decl->get_decl(struct_elem); |
120 symbol_c *type_decl = search_var_instance_decl->get_decl(struct_elem); |
121 // symbol_c *type_id = spec_init_sperator_c::get_spec(type_decl); /* this is not required! search_base_type_c can handle spec_init symbols! */ |
121 // symbol_c *type_id = spec_init_sperator_c::get_spec(type_decl); /* this is not required! search_base_type_c can handle spec_init symbols! */ |
122 symbol_c *basetype_id = search_base_type_c::get_basetype_id(/*type_id*/ type_decl); |
122 symbol_c *basetype_id = search_base_type_c::get_basetype_id(/*type_id*/ type_decl); |
133 * will be of FB type, which means we can quit this check! |
133 * will be of FB type, which means we can quit this check! |
134 */ |
134 */ |
135 function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(basetype_id); |
135 function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(basetype_id); |
136 if (function_block_type_symtable.end_value() == fb_decl) return; |
136 if (function_block_type_symtable.end_value() == fb_decl) return; |
137 |
137 |
138 while (NULL != (struct_elem = decompose_lvalue.next_part())) { |
138 while (NULL != (struct_elem = decompose_lvalue.get_next())) { |
139 search_var_instance_decl_c fb_search_var_instance_decl(fb_decl); |
139 search_var_instance_decl_c fb_search_var_instance_decl(fb_decl); |
140 if (search_var_instance_decl_c::output_vt == fb_search_var_instance_decl.get_vartype(struct_elem)) { |
140 if (search_var_instance_decl_c::output_vt == fb_search_var_instance_decl.get_vartype(struct_elem)) { |
141 STAGE3_ERROR(0, struct_elem, struct_elem, "Assignment to FB output variable is not allowed."); |
141 STAGE3_ERROR(0, struct_elem, struct_elem, "Assignment to FB output variable is not allowed."); |
142 return; /* no need to carry on checking once the first error is found! */ |
142 return; /* no need to carry on checking once the first error is found! */ |
143 } |
143 } |
154 |
154 |
155 /* No writing to CONSTANTs */ |
155 /* No writing to CONSTANTs */ |
156 void lvalue_check_c::check_assignment_to_constant(symbol_c *lvalue) { |
156 void lvalue_check_c::check_assignment_to_constant(symbol_c *lvalue) { |
157 unsigned int option = search_var_instance_decl->get_option(lvalue); |
157 unsigned int option = search_var_instance_decl->get_option(lvalue); |
158 if (option == search_var_instance_decl_c::constant_opt) { |
158 if (option == search_var_instance_decl_c::constant_opt) { |
159 STAGE3_ERROR(0, lvalue, lvalue, "Assignment to CONSTANT variables is not be allowed."); |
159 STAGE3_ERROR(0, lvalue, lvalue, "Assignment to CONSTANT variables is not allowed."); |
160 } |
160 } |
161 } |
161 } |
162 |
162 |
163 |
163 |
164 /* No assigning values to expressions. */ |
164 /* No assigning values to expressions. */ |
165 void lvalue_check_c::check_assignment_to_expression(symbol_c *lvalue) { |
165 void lvalue_check_c::check_assignment_to_expression(symbol_c *lvalue) { |
166 /* This may occur in function invocations, when passing values (possibly an expression) to one |
|
167 * of the function's OUTPUT or IN_OUT parameters. |
|
168 */ |
|
169 /* This may occur in function invocations, when passing values (possibly an expression) to one |
166 /* This may occur in function invocations, when passing values (possibly an expression) to one |
170 * of the function's OUTPUT or IN_OUT parameters. |
167 * of the function's OUTPUT or IN_OUT parameters. |
171 */ |
168 */ |
172 if ( |
169 if ( |
173 /*********************/ |
170 /*********************/ |
231 (typeid( *lvalue ) == typeid( mod_expression_c )) || |
228 (typeid( *lvalue ) == typeid( mod_expression_c )) || |
232 (typeid( *lvalue ) == typeid( power_expression_c )) || |
229 (typeid( *lvalue ) == typeid( power_expression_c )) || |
233 (typeid( *lvalue ) == typeid( neg_expression_c )) || |
230 (typeid( *lvalue ) == typeid( neg_expression_c )) || |
234 (typeid( *lvalue ) == typeid( not_expression_c )) || |
231 (typeid( *lvalue ) == typeid( not_expression_c )) || |
235 (typeid( *lvalue ) == typeid( function_invocation_c ))) |
232 (typeid( *lvalue ) == typeid( function_invocation_c ))) |
236 STAGE3_ERROR(0, lvalue, lvalue, "Assigning an expression to an OUT or IN_OUT parameter is not allowed."); |
233 STAGE3_ERROR(0, lvalue, lvalue, "Assignment to an expression or a literal value is not allowed."); |
237 } |
234 } |
238 |
235 |
239 |
236 |
240 |
237 |
|
238 /* No assigning values to IL lists. */ |
|
239 void lvalue_check_c::check_assignment_to_il_list(symbol_c *lvalue) { |
|
240 /* This may occur in formal invocations in IL, where an embedded IL list may be used instead of a symbolic_variable |
|
241 * when passing an IN_OUT parameter! Note that it will never occur to OUT parameters, as the syntax does not allow it, |
|
242 * although this does not affect out algorithm here! |
|
243 */ |
|
244 if ( |
|
245 /****************************************/ |
|
246 /* B.2 - Language IL (Instruction List) */ |
|
247 /****************************************/ |
|
248 /***********************************/ |
|
249 /* B 2.1 Instructions and Operands */ |
|
250 /***********************************/ |
|
251 (typeid( *lvalue ) == typeid( simple_instr_list_c))) |
|
252 STAGE3_ERROR(0, lvalue, lvalue, "Assigning an IL list to an IN_OUT parameter is not allowed."); |
|
253 } |
241 |
254 |
242 |
255 |
243 |
256 |
244 |
257 |
245 void lvalue_check_c::verify_is_lvalue(symbol_c *lvalue) { |
258 void lvalue_check_c::verify_is_lvalue(symbol_c *lvalue) { |
|
259 if (NULL == lvalue) return; // missing operand in source code being compiled. Error will be caught and reported by datatype checking! |
246 int init_error_count = error_count; /* stop the checks once an error has been found... */ |
260 int init_error_count = error_count; /* stop the checks once an error has been found... */ |
247 if (error_count == init_error_count) check_assignment_to_expression(lvalue); |
261 if (error_count == init_error_count) check_assignment_to_expression(lvalue); |
|
262 if (error_count == init_error_count) check_assignment_to_il_list (lvalue); |
248 if (error_count == init_error_count) check_assignment_to_controlvar(lvalue); |
263 if (error_count == init_error_count) check_assignment_to_controlvar(lvalue); |
249 if (error_count == init_error_count) check_assignment_to_output(lvalue); |
264 if (error_count == init_error_count) check_assignment_to_output (lvalue); |
250 if (error_count == init_error_count) check_assignment_to_constant(lvalue); |
265 if (error_count == init_error_count) check_assignment_to_constant (lvalue); |
251 } |
266 } |
252 |
267 |
253 |
268 |
254 |
269 |
255 |
270 |
259 * This means that, for non formal function calls in IL, de current (default value) must be artificially added to the |
274 * This means that, for non formal function calls in IL, de current (default value) must be artificially added to the |
260 * beginning of the parameter list BEFORE calling handle_function_call(). |
275 * beginning of the parameter list BEFORE calling handle_function_call(). |
261 */ |
276 */ |
262 #include <string.h> /* required for strcmp() */ |
277 #include <string.h> /* required for strcmp() */ |
263 void lvalue_check_c::check_nonformal_call(symbol_c *f_call, symbol_c *f_decl) { |
278 void lvalue_check_c::check_nonformal_call(symbol_c *f_call, symbol_c *f_decl) { |
|
279 /* if data type semantic verification was unable to determine which function is being called, |
|
280 * then it does not make sense to go ahead and check for lvalues to unknown parameters. |
|
281 * We simply bug out! |
|
282 */ |
|
283 if (NULL == f_decl) return; |
|
284 |
264 symbol_c *call_param_value; |
285 symbol_c *call_param_value; |
265 identifier_c *param_name; |
286 identifier_c *param_name; |
266 function_param_iterator_c fp_iterator(f_decl); |
287 function_param_iterator_c fp_iterator(f_decl); |
267 function_call_param_iterator_c fcp_iterator(f_call); |
288 function_call_param_iterator_c fcp_iterator(f_call); |
268 |
289 |
284 /* We only process the parameter value if the paramater itself is valid... */ |
305 /* We only process the parameter value if the paramater itself is valid... */ |
285 if (param_name != NULL) { |
306 if (param_name != NULL) { |
286 /* If the parameter is either OUT or IN_OUT, we check if 'call_param_value' is a valid lvalue */ |
307 /* If the parameter is either OUT or IN_OUT, we check if 'call_param_value' is a valid lvalue */ |
287 if ((function_param_iterator_c::direction_out == param_direction) || (function_param_iterator_c::direction_inout == param_direction)) |
308 if ((function_param_iterator_c::direction_out == param_direction) || (function_param_iterator_c::direction_inout == param_direction)) |
288 verify_is_lvalue(call_param_value); |
309 verify_is_lvalue(call_param_value); |
289 /* parameter values to IN parameters may be expressions with function invocations that must also be checked! */ |
310 /* parameter values to IN parameters may be expressions with function invocations that must also be checked! */ |
290 if (function_param_iterator_c::direction_in == param_direction) |
311 /* parameter values to OUT or IN_OUT parameters may contain arrays, whose subscripts contain expressions that must be checked! */ |
291 call_param_value->accept(*this); |
312 call_param_value->accept(*this); |
292 } |
313 } |
293 } |
314 } |
294 } |
315 } |
295 |
316 |
296 |
317 |
324 /* We only process the parameter value if the paramater itself is valid... */ |
345 /* We only process the parameter value if the paramater itself is valid... */ |
325 if (param_name != NULL) { |
346 if (param_name != NULL) { |
326 /* If the parameter is either OUT or IN_OUT, we check if 'call_param_value' is a valid lvalue */ |
347 /* If the parameter is either OUT or IN_OUT, we check if 'call_param_value' is a valid lvalue */ |
327 if ((function_param_iterator_c::direction_out == param_direction) || (function_param_iterator_c::direction_inout == param_direction)) |
348 if ((function_param_iterator_c::direction_out == param_direction) || (function_param_iterator_c::direction_inout == param_direction)) |
328 verify_is_lvalue(call_param_value); |
349 verify_is_lvalue(call_param_value); |
329 /* parameter values to IN parameters may be expressions with function invocations that must also be checked! */ |
350 /* parameter values to IN parameters may be expressions with function invocations that must also be checked! */ |
330 if (function_param_iterator_c::direction_in == param_direction) |
351 /* parameter values to OUT or IN_OUT parameters may contain arrays, whose subscripts contain expressions that must be checked! */ |
331 call_param_value->accept(*this); |
352 call_param_value->accept(*this); |
332 |
|
333 } |
353 } |
334 } |
354 } |
335 } |
355 } |
336 |
356 |
337 |
357 |