214 fcall_data.nonformal_operand_list->accept(*this); |
214 fcall_data.nonformal_operand_list->accept(*this); |
215 if (f_decl) |
215 if (f_decl) |
216 for (int i = 1; (param_value = fcp_iterator.next_nf()) != NULL; i++) { |
216 for (int i = 1; (param_value = fcp_iterator.next_nf()) != NULL; i++) { |
217 /* TODO: verify if it is lvalue when INOUT or OUTPUT parameters! */ |
217 /* TODO: verify if it is lvalue when INOUT or OUTPUT parameters! */ |
218 |
218 |
219 if (NULL == param_value->datatype) { |
219 /* This handle_function_invocation() will be called to handle IL function calls, where the first parameter comes from the previous IL instruction. |
|
220 * In this case, the previous IL instruction will be artifically (and temporarily) added to the begining ot the parameter list |
|
221 * so we (in this function) can handle this situation like all the other function calls. |
|
222 * However, |
|
223 * a) if NO previous IL function exists, then we get a fake previous IL function, with no location data (i.e. not found anywhere in the source code. |
|
224 * b) the function call may actually have several prev IL instructions (if several JMP instructions jump directly to the il function call). |
|
225 * In order to handle these situations gracefully, we first check whether the first parameter is really an IL istruction! |
|
226 */ |
|
227 il_instruction_c *il_instruction_symbol = dynamic_cast<il_instruction_c *>(param_value); |
|
228 if ((NULL != il_instruction_symbol) && (i == 1)) { |
|
229 /* We are in a situation where an IL function call is passed the first parameter, which is actually the previous IL instruction */ |
|
230 /* However, this is really a fake previous il instruction (see visit(il_instruction_c *) ) |
|
231 * We will iterate through all the real previous IL instructions, and analyse each of them one by one */ |
|
232 if (il_instruction_symbol->prev_il_instruction.size() == 0) { |
|
233 function_invocation_error = true; |
|
234 STAGE3_ERROR(0, fcall, fcall, "No available data to pass to first parameter of IL function %s. Missing a previous LD instruction?", ((identifier_c *)fcall_data.function_name)->value); |
|
235 } |
|
236 #if 0 |
|
237 /* NOTE: We currently comment out this code... |
|
238 * This does not currently work, since the narrow operation is currently done on the intersection |
|
239 * of all the previous IL instructions, so we currently either accept them all, or none at all. |
|
240 * In order to be able to produce these user freindly error messages, we will need to update the |
|
241 * narrow algorithm. We leave this untill somebody aks for it... |
|
242 * So, for now, we simply comment out this code. |
|
243 */ |
|
244 for (unsigned int p = 0; p < il_instruction_symbol->prev_il_instruction.size(); p++) { |
|
245 symbol_c *value = il_instruction_symbol->prev_il_instruction[p]; |
|
246 if (!is_type_valid(value->datatype)) { |
|
247 function_invocation_error = true; |
|
248 STAGE3_ERROR(0, fcall, fcall, "Data type incompatibility for value passed to first parameter when invoking function '%s'", ((identifier_c *)fcall_data.function_name)->value); |
|
249 STAGE3_ERROR(0, value, value, "This is the IL instruction producing the incompatible data type to first parameter of function '%s'", ((identifier_c *)fcall_data.function_name)->value); |
|
250 } |
|
251 } |
|
252 #else |
|
253 if (!is_type_valid(il_instruction_symbol->datatype)) { |
|
254 function_invocation_error = true; |
|
255 STAGE3_ERROR(0, fcall, fcall, "Data type incompatibility between value in IL 'accumulator' and first parameter of function '%s'", ((identifier_c *)fcall_data.function_name)->value); |
|
256 } |
|
257 #endif |
|
258 if (function_invocation_error) |
|
259 /* when handling a IL function call, and an error is found in the first parameter, then we bug out and do not print out any more error messages. */ |
|
260 return; |
|
261 } |
|
262 else if (!is_type_valid(param_value->datatype)) { |
220 function_invocation_error = true; |
263 function_invocation_error = true; |
221 STAGE3_ERROR(0, param_value, param_value, "Data type incompatibility for value passed in position %d when invoking %s '%s'", i, POU_str, ((identifier_c *)fcall_data.function_name)->value); |
264 STAGE3_ERROR(0, param_value, param_value, "Data type incompatibility for value passed in position %d when invoking %s '%s'", i, POU_str, ((identifier_c *)fcall_data.function_name)->value); |
222 } |
265 } |
223 } |
266 } |
224 } |
267 } |
628 /* | label ':' [il_incomplete_instruction] eol_list */ |
671 /* | label ':' [il_incomplete_instruction] eol_list */ |
629 // SYM_REF2(il_instruction_c, label, il_instruction) |
672 // SYM_REF2(il_instruction_c, label, il_instruction) |
630 void *print_datatypes_error_c::visit(il_instruction_c *symbol) { |
673 void *print_datatypes_error_c::visit(il_instruction_c *symbol) { |
631 if (NULL != symbol->il_instruction) { |
674 if (NULL != symbol->il_instruction) { |
632 il_instruction_c tmp_prev_il_instruction(NULL, NULL); |
675 il_instruction_c tmp_prev_il_instruction(NULL, NULL); |
|
676 #if 0 |
|
677 /* NOTE: The following is currently no longer needed. Since the following code is actually cool, |
|
678 * we don't delete it, but simply comment it out. It might just come in handy later on... |
|
679 */ |
633 /* When handling a il function call, this fake_prev_il_instruction may be used as a standard function call parameter, so it is important that |
680 /* When handling a il function call, this fake_prev_il_instruction may be used as a standard function call parameter, so it is important that |
634 * it contain some valid location info so error messages make sense. |
681 * it contain some valid location info so error messages make sense. |
635 */ |
682 */ |
636 if (symbol->prev_il_instruction.size() > 0) { |
683 if (symbol->prev_il_instruction.size() > 0) { |
637 /* since we don't want to copy all that data one variable at a time, we copy it all at once */ |
684 /* since we don't want to copy all that data one variable at a time, we copy it all at once */ |
648 tmp_prev_il_instruction.datatype = NULL; |
695 tmp_prev_il_instruction.datatype = NULL; |
649 /* We don't need to worry about the candidate_datatype list (which we don't want to copy just yet), since that will |
696 /* We don't need to worry about the candidate_datatype list (which we don't want to copy just yet), since that will |
650 * be reset to the correct value when we call intersect_prev_candidate_datatype_lists() later on... |
697 * be reset to the correct value when we call intersect_prev_candidate_datatype_lists() later on... |
651 */ |
698 */ |
652 } |
699 } |
653 /* the narrow algorithm will need access to the intersected candidate_datatype lists of all prev_il_instructions, as well as the |
700 #endif |
|
701 /* the print error algorithm will need access to the intersected candidate_datatype lists of all prev_il_instructions, as well as the |
654 * list of the prev_il_instructions. |
702 * list of the prev_il_instructions. |
655 * Instead of creating two 'global' (within the class) variables, we create a single il_instruction_c variable (fake_prev_il_instruction), |
703 * Instead of creating two 'global' (within the class) variables, we create a single il_instruction_c variable (fake_prev_il_instruction), |
656 * and shove that data into this single variable. |
704 * and shove that data into this single variable. |
657 */ |
705 */ |
658 tmp_prev_il_instruction.prev_il_instruction = symbol->prev_il_instruction; |
706 tmp_prev_il_instruction.prev_il_instruction = symbol->prev_il_instruction; |