--- a/stage3/fill_candidate_datatypes.cc Mon Feb 20 15:24:26 2012 +0000
+++ b/stage3/fill_candidate_datatypes.cc Mon Feb 20 17:52:01 2012 +0000
@@ -293,8 +293,7 @@
* The il_prev_intruction object has already been visited. We DO NOT want to visit it again.
* The easiest way to work around this is to simply use a new object, and copy the relevant details to that object!
*/
- symbol_c param_value;
- copy_candidate_datatype_list(prev_il_instruction/*from*/, ¶m_value/*to*/);
+ symbol_c param_value = *prev_il_instruction;
identifier_c variable_name(param_name);
// SYM_REF1(il_assign_operator_c, variable_name)
@@ -861,7 +860,7 @@
void *fill_candidate_datatypes_c::visit(il_function_call_c *symbol) {
/* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction)
* In order to be able to handle this without coding special cases, we will simply prepend that symbol
- * to the il_operand_list, and remove it later (in the print_datatypes_error_c).
+ * to the il_operand_list, and remove it after calling handle_function_call().
*
* However, if no further paramters are given, then il_operand_list will be NULL, and we will
* need to create a new object to hold the pointer to prev_il_instruction.
@@ -872,20 +871,31 @@
symbol->il_operand_list->accept(*this);
- if (NULL == prev_il_instruction) return NULL;
- ((list_c *)symbol->il_operand_list)->insert_element(prev_il_instruction, 0);
-
- generic_function_call_t fcall_param = {
- /* fcall_param.function_name = */ symbol->function_name,
- /* fcall_param.nonformal_operand_list = */ symbol->il_operand_list,
- /* fcall_param.formal_operand_list = */ NULL,
- /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_function,
- /* fcall_param.candidate_functions = */ symbol->candidate_functions,
- /* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
- /* fcall_param.extensible_param_count = */ symbol->extensible_param_count
- };
- handle_function_call(symbol, fcall_param);
-
+ if (NULL != prev_il_instruction) {
+ ((list_c *)symbol->il_operand_list)->insert_element(prev_il_instruction, 0);
+
+ generic_function_call_t fcall_param = {
+ /* fcall_param.function_name = */ symbol->function_name,
+ /* fcall_param.nonformal_operand_list = */ symbol->il_operand_list,
+ /* fcall_param.formal_operand_list = */ NULL,
+ /* enum {POU_FB, POU_function} POU_type = */ generic_function_call_t::POU_function,
+ /* fcall_param.candidate_functions = */ symbol->candidate_functions,
+ /* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
+ /* fcall_param.extensible_param_count = */ symbol->extensible_param_count
+ };
+ handle_function_call(symbol, fcall_param);
+
+ /* Undo the changes to the abstract syntax tree we made above... */
+ ((list_c *)symbol->il_operand_list)->remove_element(0);
+ }
+
+ /* Undo the changes to the abstract syntax tree we made above... */
+ if (((list_c *)symbol->il_operand_list)->n == 0) {
+ /* if the list becomes empty, then that means that it did not exist before we made these changes, so we delete it! */
+ delete symbol->il_operand_list;
+ symbol->il_operand_list = NULL;
+ }
+
if (debug) std::cout << "il_function_call_c [" << symbol->candidate_datatypes.size() << "] result.\n";
return NULL;
}
--- a/stage3/narrow_candidate_datatypes.cc Mon Feb 20 15:24:26 2012 +0000
+++ b/stage3/narrow_candidate_datatypes.cc Mon Feb 20 17:52:01 2012 +0000
@@ -116,20 +116,13 @@
if ((NULL == param_name) && (NULL != desired_datatype)) ERROR;
/* NOTE: When we are handling a nonformal function call made from IL, the first parameter is the 'default' or 'current'
- * il value. However, a pointer to the prev_il_instruction is pre-pended into the operand list (done in fill_candidate_datatypes_c,
- * and later undone in print_datatypes_error_c - this class is run after the first, and before the latter!), so
+ * il value. However, a pointer to a copy of the prev_il_instruction is pre-pended into the operand list, so
* the call
* call_param_value->accept(*this);
- * may actually be calling an object of the il_instruction_c class.
- * If that is the case, that same il_instruction_c object will be called again inside the for() loop
- * of void *narrow_candidate_datatypes_c::visit(instruction_list_c *symbol);
- * Since this is not safe (the prev_il_instruction variable will be overwritten with a wrong value!),
- * we only do the recursive call if this parameter does not point to a il_instruction_c object.
- * Actually, it is easier to check whether it is not the same as the prev_il_instruction.
+ * may actually be calling an object of the base symbol_c .
*/
set_datatype(desired_datatype, call_param_value);
- if (call_param_value != prev_il_instruction)
- call_param_value->accept(*this);
+ call_param_value->accept(*this);
if (NULL != param_name)
if (extensible_parameter_highest_index < fp_iterator.extensible_param_index())
@@ -182,12 +175,10 @@
/* set the desired data type for this parameter */
set_datatype(desired_datatype, call_param_value);
/* And recursively call that parameter/expression, so it can propagate that info */
- /* However, when handling an implicit IL FB call, the first parameter is fake, and points to the prev_il_instruction.
- * In this case, we do not propagate this info down, as that prev_il_instruction will be called later
- * (remember, we iterate backwards through the IL instructions) by the for() loop in the instruction_list_c.
+ /* However, when handling an implicit IL FB call, the first parameter is fake (a copy of the prev_il_instruction).
+ * so the call call_param_value->accept(*this) may actually be calling an object of the base symbol_c .
*/
- if (call_param_value != prev_il_instruction)
- call_param_value->accept(*this);
+ call_param_value->accept(*this);
if (NULL != param_name)
if (extensible_parameter_highest_index < fp_iterator.extensible_param_index())
@@ -279,16 +270,27 @@
if (NULL == prev_il_instruction) {
/* This IL implicit FB call (e.g. CLK ton_var) is not preceded by another IL instruction
* (or list of instructions) that will set the IL current/default value.
- * We cannot proceed verifying type compatibility of something that does not ecist.
+ * We cannot proceed verifying type compatibility of something that does not exist.
*/
return;
}
+ /* The value being passed to the 'param_name' parameter is actually the prev_il_instruction.
+ * However, we do not place that object directly in the fake il_param_list_c that we will be
+ * creating, since the visit(il_fb_call_c *) method will recursively call every object in that list.
+ * The il_prev_intruction object will be visited once we have handled this implici IL FB call
+ * (called from the instruction_list_c for() loop that works backwards). We DO NOT want to visit it twice.
+ * (Anyway, if we let the visit(il_fb_call_c *) recursively visit the current prev_il_instruction, this pointer
+ * would be changed to the IL instruction coming before the current prev_il_instruction! => things would get all messed up!)
+ * The easiest way to work around this is to simply use a new object, and copy the relevant details to that object!
+ */
+ symbol_c param_value = *prev_il_instruction;
+
identifier_c variable_name(param_name);
// SYM_REF1(il_assign_operator_c, variable_name)
il_assign_operator_c il_assign_operator(&variable_name);
// SYM_REF3(il_param_assignment_c, il_assign_operator, il_operand, simple_instr_list)
- il_param_assignment_c il_param_assignment(&il_assign_operator, prev_il_instruction/*il_operand*/, NULL);
+ il_param_assignment_c il_param_assignment(&il_assign_operator, ¶m_value/*il_operand*/, NULL);
il_param_list_c il_param_list;
il_param_list.add_element(&il_param_assignment);
// SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration)
@@ -303,9 +305,35 @@
* correctly set up the il_fb_call.datatype variable!
*/
copy_candidate_datatype_list(il_instruction/*from*/, &il_fb_call/*to*/);
- il_fb_call.datatype = il_instruction->datatype;
il_fb_call.accept(*this);
- il_instruction->datatype = il_fb_call.datatype;
+
+ /* set the required datatype of the previous IL instruction! */
+ /* NOTE:
+ * When handling these implicit IL calls, the parameter_value being passed to the FB parameter
+ * is actually the prev_il_instruction.
+ *
+ * However, since the FB call does not change the value in the current/default IL variable, this value
+ * must also be used ny the IL instruction coming after this FB call.
+ *
+ * This means that we have two consumers/users for the same value.
+ * We must therefore check whether the datatype required by the IL instructions following this FB call
+ * is the same as that required for the first parameter. If not, then we have a semantic error,
+ * and we set it to NULL.
+ *
+ * However, we only do that if:
+ * - The IL instruction that comes after this IL FB call actually asked this FB call for a specific
+ * datatype in the current/default vairable, once this IL FB call returns.
+ * However, sometimes, (for e.g., this FB call is the last in the IL list) the subsequent FB to not aks this
+ * FB call for any datatype. In that case, then the datatype required to pass to the first parameter of the
+ * FB call must be left unchanged!
+ */
+// if (NULL != prev_il_instruction) /* already checked above! */
+ if (is_type_equal(param_value.datatype, il_instruction->datatype)) {
+ prev_il_instruction->datatype = param_value.datatype;
+ } else {
+ prev_il_instruction->datatype = NULL;
+ }
+
}
@@ -493,6 +521,26 @@
/* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */
// SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;)
void *narrow_candidate_datatypes_c::visit(il_function_call_c *symbol) {
+ /* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction)
+ * In order to be able to handle this without coding special cases, we will simply prepend that symbol
+ * to the il_operand_list, and remove it after calling handle_function_call().
+ * However, since handle_function_call() will be recursively calling all parameter, and we don't want
+ * to do that for the prev_il_instruction (since it has already been visited by the fill_candidate_datatypes_c)
+ * we create a new ____ symbol_c ____ object, and copy the relevant info to/from that object before/after
+ * the call to handle_function_call().
+ *
+ * However, if no further paramters are given, then il_operand_list will be NULL, and we will
+ * need to create a new object to hold the pointer to prev_il_instruction.
+ * This change will also be undone later in print_datatypes_error_c.
+ */
+ symbol_c param_value;
+ if (NULL == symbol->il_operand_list) symbol->il_operand_list = new il_operand_list_c;
+ if (NULL == symbol->il_operand_list) ERROR;
+
+ if (NULL != prev_il_instruction)
+ param_value = *prev_il_instruction;
+ ((list_c *)symbol->il_operand_list)->insert_element(¶m_value, 0);
+
generic_function_call_t fcall_param = {
/* fcall_param.function_name = */ symbol->function_name,
/* fcall_param.nonformal_operand_list = */ symbol->il_operand_list,
@@ -503,15 +551,18 @@
/* fcall_param.extensible_param_count = */ symbol->extensible_param_count
};
- /* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction)
- * In order to be able to handle this without coding special cases, we simply prepend that symbol
- * to the il_operand_list (done in fill_candidate_datatypes_c), and remove it later (in the print_datatypes_error_c).
- *
- * Since this class is executed after fill_candidate_datatypes_c, and before print_datatypes_error_c,
- * the following code is actually correct!
- */
narrow_function_invocation(symbol, fcall_param);
- /* The desired datatype of the previous il instruction was already set by narrow_function_invocation() */
+ if (NULL != prev_il_instruction)
+ prev_il_instruction->datatype = param_value.datatype;
+
+ /* Undo the changes to the abstract syntax tree we made above... */
+ ((list_c *)symbol->il_operand_list)->remove_element(0);
+ if (((list_c *)symbol->il_operand_list)->n == 0) {
+ /* if the list becomes empty, then that means that it did not exist before we made these changes, so we delete it! */
+ delete symbol->il_operand_list;
+ symbol->il_operand_list = NULL;
+ }
+
return NULL;
}
@@ -537,27 +588,6 @@
/* 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 */
// SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration)
void *narrow_candidate_datatypes_c::visit(il_fb_call_c *symbol) {
- /* set the desired datatype of the previous il instruction */
- /* NOTE 1:
- * A FB call does not return any datatype, but the IL instructions that come after this
- * FB call may require a specific datatype in the il current/default variable,
- * so we must pass this information up to the IL instruction before the FB call, since it will
- * be that IL instruction that will be required to produce the desired dtataype.
- * NOTE 2:
- * Copying the required datatype must be done before calling narrow_[non]formal_call().
- * Note that this visit(il_fb_call_c *) method will be called from narrow_implicit_il_fb_call().
- * This means that we must also be able to handle implicit IL FB calls (e.g. CU counter_var)
- * correctly in this visitor class.
- * When handling these implicit IL calls, the parameter_value being passed to the FB parameter
- * (in the previous example, the 'CU' parameter) is actually the prev_il_instruction.
- * In this case, the prev_il_instruction->datatype will be set by the arrow_[non]formal_call(),
- * using the prama_value pointer to this same object.
- * If we were to have the following line of code after calling arrow_[non]formal_call(),
- * we would then be overwriting the datatype with the wrong value!
- */
- if (NULL != prev_il_instruction)
- prev_il_instruction->datatype = symbol->datatype;
-
/* Note: We do not use the symbol->called_fb_declaration value (set in fill_candidate_datatypes_c)
* because we try to identify any other datatype errors in the expressions used in the
* parameters to the FB call. e.g.
@@ -579,29 +609,11 @@
if (NULL != symbol->il_operand_list) narrow_nonformal_call(symbol, fb_decl);
if (NULL != symbol-> il_param_list) narrow_formal_call(symbol, fb_decl);
- /* NOTE:
- * When handling these implicit IL calls, the parameter_value being passed to the FB parameter
- * (in the previous example, the 'CU' parameter) is actually the prev_il_instruction.
- * In this case, the prev_il_instruction->datatype will be set by the narrow_[non]formal_call(),
- * using the param_value pointer to this same object.
- *
- * We must check that the datatype required by the IL instructions following this FB call
- * is the same as that required for the first parameter. If not, then we have a semantic error,
- * and we set it to NULL.
- *
- * However, we only do that if:
- * - There really exists an il_prev_instruction
- * (if it does not exist, it will be a semantic error. But that will be caught by the print_datatypes_error_c)
- * - The IL instruction that comes after this IL FB call actually asked this FB call for a specific
- * datatype in the current/default vairable, once this IL FB call returns.
- * However, sometimes, (for e.g., this FB call is the last in the IL list) the subsequent FB to not aks this
- * FB call for any datatype. In that case, then the datatype required to pass to the first parameter of the
- * FB call must be left unchanged!
+ /* An IL FB call does not change the default value in the current/default IL variable, so we pass the
+ * required datatype up to the previous IL instruction
*/
- if ((NULL != prev_il_instruction) && (NULL != symbol->datatype))
- if (!is_type_equal(prev_il_instruction->datatype, symbol->datatype)) {
- prev_il_instruction->datatype = NULL;
- }
+ if (NULL != prev_il_instruction)
+ prev_il_instruction->datatype = symbol->datatype;
return NULL;
}