114 symbol_c *desired_datatype = base_type(fp_iterator.param_type()); |
114 symbol_c *desired_datatype = base_type(fp_iterator.param_type()); |
115 if ((NULL != param_name) && (NULL == desired_datatype)) ERROR; |
115 if ((NULL != param_name) && (NULL == desired_datatype)) ERROR; |
116 if ((NULL == param_name) && (NULL != desired_datatype)) ERROR; |
116 if ((NULL == param_name) && (NULL != desired_datatype)) ERROR; |
117 |
117 |
118 /* NOTE: When we are handling a nonformal function call made from IL, the first parameter is the 'default' or 'current' |
118 /* NOTE: When we are handling a nonformal function call made from IL, the first parameter is the 'default' or 'current' |
119 * il value. However, a pointer to the prev_il_instruction is pre-pended into the operand list (done in fill_candidate_datatypes_c, |
119 * il value. However, a pointer to a copy of the prev_il_instruction is pre-pended into the operand list, so |
120 * and later undone in print_datatypes_error_c - this class is run after the first, and before the latter!), so |
|
121 * the call |
120 * the call |
122 * call_param_value->accept(*this); |
121 * call_param_value->accept(*this); |
123 * may actually be calling an object of the il_instruction_c class. |
122 * may actually be calling an object of the base symbol_c . |
124 * If that is the case, that same il_instruction_c object will be called again inside the for() loop |
|
125 * of void *narrow_candidate_datatypes_c::visit(instruction_list_c *symbol); |
|
126 * Since this is not safe (the prev_il_instruction variable will be overwritten with a wrong value!), |
|
127 * we only do the recursive call if this parameter does not point to a il_instruction_c object. |
|
128 * Actually, it is easier to check whether it is not the same as the prev_il_instruction. |
|
129 */ |
123 */ |
130 set_datatype(desired_datatype, call_param_value); |
124 set_datatype(desired_datatype, call_param_value); |
131 if (call_param_value != prev_il_instruction) |
125 call_param_value->accept(*this); |
132 call_param_value->accept(*this); |
|
133 |
126 |
134 if (NULL != param_name) |
127 if (NULL != param_name) |
135 if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) |
128 if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) |
136 extensible_parameter_highest_index = fp_iterator.extensible_param_index(); |
129 extensible_parameter_highest_index = fp_iterator.extensible_param_index(); |
137 } |
130 } |
180 if ((NULL == param_name) && (NULL != desired_datatype)) ERROR; |
173 if ((NULL == param_name) && (NULL != desired_datatype)) ERROR; |
181 |
174 |
182 /* set the desired data type for this parameter */ |
175 /* set the desired data type for this parameter */ |
183 set_datatype(desired_datatype, call_param_value); |
176 set_datatype(desired_datatype, call_param_value); |
184 /* And recursively call that parameter/expression, so it can propagate that info */ |
177 /* And recursively call that parameter/expression, so it can propagate that info */ |
185 /* However, when handling an implicit IL FB call, the first parameter is fake, and points to the prev_il_instruction. |
178 /* However, when handling an implicit IL FB call, the first parameter is fake (a copy of the prev_il_instruction). |
186 * In this case, we do not propagate this info down, as that prev_il_instruction will be called later |
179 * so the call call_param_value->accept(*this) may actually be calling an object of the base symbol_c . |
187 * (remember, we iterate backwards through the IL instructions) by the for() loop in the instruction_list_c. |
|
188 */ |
180 */ |
189 if (call_param_value != prev_il_instruction) |
181 call_param_value->accept(*this); |
190 call_param_value->accept(*this); |
|
191 |
182 |
192 if (NULL != param_name) |
183 if (NULL != param_name) |
193 if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) |
184 if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) |
194 extensible_parameter_highest_index = fp_iterator.extensible_param_index(); |
185 extensible_parameter_highest_index = fp_iterator.extensible_param_index(); |
195 } |
186 } |
277 */ |
268 */ |
278 return; |
269 return; |
279 if (NULL == prev_il_instruction) { |
270 if (NULL == prev_il_instruction) { |
280 /* This IL implicit FB call (e.g. CLK ton_var) is not preceded by another IL instruction |
271 /* This IL implicit FB call (e.g. CLK ton_var) is not preceded by another IL instruction |
281 * (or list of instructions) that will set the IL current/default value. |
272 * (or list of instructions) that will set the IL current/default value. |
282 * We cannot proceed verifying type compatibility of something that does not ecist. |
273 * We cannot proceed verifying type compatibility of something that does not exist. |
283 */ |
274 */ |
284 return; |
275 return; |
285 } |
276 } |
286 |
277 |
|
278 /* The value being passed to the 'param_name' parameter is actually the prev_il_instruction. |
|
279 * However, we do not place that object directly in the fake il_param_list_c that we will be |
|
280 * creating, since the visit(il_fb_call_c *) method will recursively call every object in that list. |
|
281 * The il_prev_intruction object will be visited once we have handled this implici IL FB call |
|
282 * (called from the instruction_list_c for() loop that works backwards). We DO NOT want to visit it twice. |
|
283 * (Anyway, if we let the visit(il_fb_call_c *) recursively visit the current prev_il_instruction, this pointer |
|
284 * would be changed to the IL instruction coming before the current prev_il_instruction! => things would get all messed up!) |
|
285 * The easiest way to work around this is to simply use a new object, and copy the relevant details to that object! |
|
286 */ |
|
287 symbol_c param_value = *prev_il_instruction; |
|
288 |
287 identifier_c variable_name(param_name); |
289 identifier_c variable_name(param_name); |
288 // SYM_REF1(il_assign_operator_c, variable_name) |
290 // SYM_REF1(il_assign_operator_c, variable_name) |
289 il_assign_operator_c il_assign_operator(&variable_name); |
291 il_assign_operator_c il_assign_operator(&variable_name); |
290 // SYM_REF3(il_param_assignment_c, il_assign_operator, il_operand, simple_instr_list) |
292 // SYM_REF3(il_param_assignment_c, il_assign_operator, il_operand, simple_instr_list) |
291 il_param_assignment_c il_param_assignment(&il_assign_operator, prev_il_instruction/*il_operand*/, NULL); |
293 il_param_assignment_c il_param_assignment(&il_assign_operator, ¶m_value/*il_operand*/, NULL); |
292 il_param_list_c il_param_list; |
294 il_param_list_c il_param_list; |
293 il_param_list.add_element(&il_param_assignment); |
295 il_param_list.add_element(&il_param_assignment); |
294 // SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration) |
296 // SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration) |
295 il_fb_call_c il_fb_call(NULL, il_operand, NULL, &il_param_list); |
297 il_fb_call_c il_fb_call(NULL, il_operand, NULL, &il_param_list); |
296 |
298 |
301 * |
303 * |
302 * The above will be done by the visit(il_fb_call_c *) method, so we must make sure to |
304 * The above will be done by the visit(il_fb_call_c *) method, so we must make sure to |
303 * correctly set up the il_fb_call.datatype variable! |
305 * correctly set up the il_fb_call.datatype variable! |
304 */ |
306 */ |
305 copy_candidate_datatype_list(il_instruction/*from*/, &il_fb_call/*to*/); |
307 copy_candidate_datatype_list(il_instruction/*from*/, &il_fb_call/*to*/); |
306 il_fb_call.datatype = il_instruction->datatype; |
|
307 il_fb_call.accept(*this); |
308 il_fb_call.accept(*this); |
308 il_instruction->datatype = il_fb_call.datatype; |
309 |
|
310 /* set the required datatype of the previous IL instruction! */ |
|
311 /* NOTE: |
|
312 * When handling these implicit IL calls, the parameter_value being passed to the FB parameter |
|
313 * is actually the prev_il_instruction. |
|
314 * |
|
315 * However, since the FB call does not change the value in the current/default IL variable, this value |
|
316 * must also be used ny the IL instruction coming after this FB call. |
|
317 * |
|
318 * This means that we have two consumers/users for the same value. |
|
319 * We must therefore check whether the datatype required by the IL instructions following this FB call |
|
320 * is the same as that required for the first parameter. If not, then we have a semantic error, |
|
321 * and we set it to NULL. |
|
322 * |
|
323 * However, we only do that if: |
|
324 * - The IL instruction that comes after this IL FB call actually asked this FB call for a specific |
|
325 * datatype in the current/default vairable, once this IL FB call returns. |
|
326 * However, sometimes, (for e.g., this FB call is the last in the IL list) the subsequent FB to not aks this |
|
327 * FB call for any datatype. In that case, then the datatype required to pass to the first parameter of the |
|
328 * FB call must be left unchanged! |
|
329 */ |
|
330 // if (NULL != prev_il_instruction) /* already checked above! */ |
|
331 if (is_type_equal(param_value.datatype, il_instruction->datatype)) { |
|
332 prev_il_instruction->datatype = param_value.datatype; |
|
333 } else { |
|
334 prev_il_instruction->datatype = NULL; |
|
335 } |
|
336 |
309 } |
337 } |
310 |
338 |
311 |
339 |
312 /* a helper function... */ |
340 /* a helper function... */ |
313 symbol_c *narrow_candidate_datatypes_c::base_type(symbol_c *symbol) { |
341 symbol_c *narrow_candidate_datatypes_c::base_type(symbol_c *symbol) { |
491 |
519 |
492 /* | function_name [il_operand_list] */ |
520 /* | function_name [il_operand_list] */ |
493 /* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */ |
521 /* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */ |
494 // SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;) |
522 // SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;) |
495 void *narrow_candidate_datatypes_c::visit(il_function_call_c *symbol) { |
523 void *narrow_candidate_datatypes_c::visit(il_function_call_c *symbol) { |
|
524 /* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction) |
|
525 * In order to be able to handle this without coding special cases, we will simply prepend that symbol |
|
526 * to the il_operand_list, and remove it after calling handle_function_call(). |
|
527 * However, since handle_function_call() will be recursively calling all parameter, and we don't want |
|
528 * to do that for the prev_il_instruction (since it has already been visited by the fill_candidate_datatypes_c) |
|
529 * we create a new ____ symbol_c ____ object, and copy the relevant info to/from that object before/after |
|
530 * the call to handle_function_call(). |
|
531 * |
|
532 * However, if no further paramters are given, then il_operand_list will be NULL, and we will |
|
533 * need to create a new object to hold the pointer to prev_il_instruction. |
|
534 * This change will also be undone later in print_datatypes_error_c. |
|
535 */ |
|
536 symbol_c param_value; |
|
537 if (NULL == symbol->il_operand_list) symbol->il_operand_list = new il_operand_list_c; |
|
538 if (NULL == symbol->il_operand_list) ERROR; |
|
539 |
|
540 if (NULL != prev_il_instruction) |
|
541 param_value = *prev_il_instruction; |
|
542 ((list_c *)symbol->il_operand_list)->insert_element(¶m_value, 0); |
|
543 |
496 generic_function_call_t fcall_param = { |
544 generic_function_call_t fcall_param = { |
497 /* fcall_param.function_name = */ symbol->function_name, |
545 /* fcall_param.function_name = */ symbol->function_name, |
498 /* fcall_param.nonformal_operand_list = */ symbol->il_operand_list, |
546 /* fcall_param.nonformal_operand_list = */ symbol->il_operand_list, |
499 /* fcall_param.formal_operand_list = */ NULL, |
547 /* fcall_param.formal_operand_list = */ NULL, |
500 /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_function, |
548 /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_function, |
501 /* fcall_param.candidate_functions = */ symbol->candidate_functions, |
549 /* fcall_param.candidate_functions = */ symbol->candidate_functions, |
502 /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, |
550 /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, |
503 /* fcall_param.extensible_param_count = */ symbol->extensible_param_count |
551 /* fcall_param.extensible_param_count = */ symbol->extensible_param_count |
504 }; |
552 }; |
505 |
553 |
506 /* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction) |
|
507 * In order to be able to handle this without coding special cases, we simply prepend that symbol |
|
508 * to the il_operand_list (done in fill_candidate_datatypes_c), and remove it later (in the print_datatypes_error_c). |
|
509 * |
|
510 * Since this class is executed after fill_candidate_datatypes_c, and before print_datatypes_error_c, |
|
511 * the following code is actually correct! |
|
512 */ |
|
513 narrow_function_invocation(symbol, fcall_param); |
554 narrow_function_invocation(symbol, fcall_param); |
514 /* The desired datatype of the previous il instruction was already set by narrow_function_invocation() */ |
555 if (NULL != prev_il_instruction) |
|
556 prev_il_instruction->datatype = param_value.datatype; |
|
557 |
|
558 /* Undo the changes to the abstract syntax tree we made above... */ |
|
559 ((list_c *)symbol->il_operand_list)->remove_element(0); |
|
560 if (((list_c *)symbol->il_operand_list)->n == 0) { |
|
561 /* if the list becomes empty, then that means that it did not exist before we made these changes, so we delete it! */ |
|
562 delete symbol->il_operand_list; |
|
563 symbol->il_operand_list = NULL; |
|
564 } |
|
565 |
515 return NULL; |
566 return NULL; |
516 } |
567 } |
517 |
568 |
518 /* MJS: Manuele, could you please not delete the following 2 lines of comments. They help me understand where this class is used |
569 /* MJS: Manuele, could you please not delete the following 2 lines of comments. They help me understand where this class is used |
519 * and when it is created by bison - syntax parse, and how it can show up in the abstract syntax tree. |
570 * and when it is created by bison - syntax parse, and how it can show up in the abstract syntax tree. |
535 * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')' |
586 * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')' |
536 */ |
587 */ |
537 /* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */ |
588 /* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */ |
538 // SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration) |
589 // SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration) |
539 void *narrow_candidate_datatypes_c::visit(il_fb_call_c *symbol) { |
590 void *narrow_candidate_datatypes_c::visit(il_fb_call_c *symbol) { |
540 /* set the desired datatype of the previous il instruction */ |
|
541 /* NOTE 1: |
|
542 * A FB call does not return any datatype, but the IL instructions that come after this |
|
543 * FB call may require a specific datatype in the il current/default variable, |
|
544 * so we must pass this information up to the IL instruction before the FB call, since it will |
|
545 * be that IL instruction that will be required to produce the desired dtataype. |
|
546 * NOTE 2: |
|
547 * Copying the required datatype must be done before calling narrow_[non]formal_call(). |
|
548 * Note that this visit(il_fb_call_c *) method will be called from narrow_implicit_il_fb_call(). |
|
549 * This means that we must also be able to handle implicit IL FB calls (e.g. CU counter_var) |
|
550 * correctly in this visitor class. |
|
551 * When handling these implicit IL calls, the parameter_value being passed to the FB parameter |
|
552 * (in the previous example, the 'CU' parameter) is actually the prev_il_instruction. |
|
553 * In this case, the prev_il_instruction->datatype will be set by the arrow_[non]formal_call(), |
|
554 * using the prama_value pointer to this same object. |
|
555 * If we were to have the following line of code after calling arrow_[non]formal_call(), |
|
556 * we would then be overwriting the datatype with the wrong value! |
|
557 */ |
|
558 if (NULL != prev_il_instruction) |
|
559 prev_il_instruction->datatype = symbol->datatype; |
|
560 |
|
561 /* Note: We do not use the symbol->called_fb_declaration value (set in fill_candidate_datatypes_c) |
591 /* Note: We do not use the symbol->called_fb_declaration value (set in fill_candidate_datatypes_c) |
562 * because we try to identify any other datatype errors in the expressions used in the |
592 * because we try to identify any other datatype errors in the expressions used in the |
563 * parameters to the FB call. e.g. |
593 * parameters to the FB call. e.g. |
564 * fb_var( |
594 * fb_var( |
565 * in1 := var1, |
595 * in1 := var1, |
577 /* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */ |
607 /* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */ |
578 if (NULL == fb_decl) ERROR; |
608 if (NULL == fb_decl) ERROR; |
579 if (NULL != symbol->il_operand_list) narrow_nonformal_call(symbol, fb_decl); |
609 if (NULL != symbol->il_operand_list) narrow_nonformal_call(symbol, fb_decl); |
580 if (NULL != symbol-> il_param_list) narrow_formal_call(symbol, fb_decl); |
610 if (NULL != symbol-> il_param_list) narrow_formal_call(symbol, fb_decl); |
581 |
611 |
582 /* NOTE: |
612 /* An IL FB call does not change the default value in the current/default IL variable, so we pass the |
583 * When handling these implicit IL calls, the parameter_value being passed to the FB parameter |
613 * required datatype up to the previous IL instruction |
584 * (in the previous example, the 'CU' parameter) is actually the prev_il_instruction. |
|
585 * In this case, the prev_il_instruction->datatype will be set by the narrow_[non]formal_call(), |
|
586 * using the param_value pointer to this same object. |
|
587 * |
|
588 * We must check that the datatype required by the IL instructions following this FB call |
|
589 * is the same as that required for the first parameter. If not, then we have a semantic error, |
|
590 * and we set it to NULL. |
|
591 * |
|
592 * However, we only do that if: |
|
593 * - There really exists an il_prev_instruction |
|
594 * (if it does not exist, it will be a semantic error. But that will be caught by the print_datatypes_error_c) |
|
595 * - The IL instruction that comes after this IL FB call actually asked this FB call for a specific |
|
596 * datatype in the current/default vairable, once this IL FB call returns. |
|
597 * However, sometimes, (for e.g., this FB call is the last in the IL list) the subsequent FB to not aks this |
|
598 * FB call for any datatype. In that case, then the datatype required to pass to the first parameter of the |
|
599 * FB call must be left unchanged! |
|
600 */ |
614 */ |
601 if ((NULL != prev_il_instruction) && (NULL != symbol->datatype)) |
615 if (NULL != prev_il_instruction) |
602 if (!is_type_equal(prev_il_instruction->datatype, symbol->datatype)) { |
616 prev_il_instruction->datatype = symbol->datatype; |
603 prev_il_instruction->datatype = NULL; |
|
604 } |
|
605 return NULL; |
617 return NULL; |
606 } |
618 } |
607 |
619 |
608 |
620 |
609 /* | function_name '(' eol_list [il_param_list] ')' */ |
621 /* | function_name '(' eol_list [il_param_list] ')' */ |