Add support for semantic verification for implict FB calls in IL (e.g. PV ton_var)
authorMario de Sousa <msousa@fe.up.pt>
Sat, 18 Feb 2012 21:03:01 +0000
changeset 448 1bd18fc06911
parent 447 aad0f3e5df33
child 449 3c6225521059
Add support for semantic verification for implict FB calls in IL (e.g. PV ton_var)
absyntax_utils/function_param_iterator.cc
absyntax_utils/function_param_iterator.hh
stage3/fill_candidate_datatypes.cc
stage3/flow_control_analysis.cc
stage3/narrow_candidate_datatypes.cc
stage3/narrow_candidate_datatypes.hh
stage3/print_datatypes_error.cc
stage3/print_datatypes_error.hh
--- a/absyntax_utils/function_param_iterator.cc	Fri Feb 17 19:47:58 2012 +0000
+++ b/absyntax_utils/function_param_iterator.cc	Sat Feb 18 21:03:01 2012 +0000
@@ -290,6 +290,13 @@
   return res_param_name;
 }
 
+identifier_c *function_param_iterator_c::search(const char *param_name) {
+  identifier_c   param_name_id(param_name);
+  return search(&param_name_id);
+}
+
+
+
 /* Returns the currently referenced parameter's default value,
  * or NULL if none is specified in the function declrataion itself.
  */
--- a/absyntax_utils/function_param_iterator.hh	Fri Feb 17 19:47:58 2012 +0000
+++ b/absyntax_utils/function_param_iterator.hh	Sat Feb 18 21:03:01 2012 +0000
@@ -146,6 +146,7 @@
      * of the found parameter.
      */
     identifier_c *search(symbol_c *param_name);
+    identifier_c *search(const char *param_name);
 
     /* Returns the currently referenced parameter's default value,
      * or NULL if none is specified in the function declrataion itself.
--- a/stage3/fill_candidate_datatypes.cc	Fri Feb 17 19:47:58 2012 +0000
+++ b/stage3/fill_candidate_datatypes.cc	Sat Feb 18 21:03:01 2012 +0000
@@ -118,7 +118,7 @@
 
 	/* Iterating through the formal parameters of the function call */
 	while((call_param_name = fcp_iterator.next_f()) != NULL) {
-
+/* TODO: check whether direction (IN, OUT, IN_OUT) and assignment types (:= , =>) are compatible !!! */
 		/* Obtaining the value being passed in the function call */
 		call_param_value = fcp_iterator.get_current_value();
 		/* the following should never occur. If it does, then we have a bug in our code... */
@@ -238,13 +238,17 @@
 
 
 /* handle implicit FB call in IL.
- * e.g.  CLK ton_car
+ * e.g.  CLK ton_var
  *        CU counter_var
  *
  * The algorithm will be to build a fake il_fb_call_c equivalent to the implicit IL FB call, and let 
  * the visit(il_fb_call_c *) method handle it!
  */
 void fill_candidate_datatypes_c::handle_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name, symbol_c *&called_fb_declaration) {
+	if (NULL == il_operand)
+		/* No FB to call was specified. There is nothing we can do... */
+		return;
+
 	symbol_c *fb_type_id = search_varfb_instance_type->get_basetype_id(il_operand);
 	/* This is a call to a non-declared FB/Variable is a semantic error (which is currently caught by stage 2, so this should never occur)
 	 * or no operand was given (il_operand == NULL). In this case, we just give up!
@@ -260,6 +264,13 @@
 		 */
 		return;
 
+	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.
+		 */
+		return;
+	}
 
 	identifier_c variable_name(param_name);
 	// SYM_REF1(il_assign_operator_c, variable_name)
@@ -785,14 +796,17 @@
 // SYM_REF2(il_instruction_c, label, il_instruction)
 // void *visit(instruction_list_c *symbol);
 void *fill_candidate_datatypes_c::visit(il_instruction_c *symbol) {
-	if (NULL == symbol->il_instruction)
-		return NULL;
-
-	prev_il_instruction = symbol->prev_il_instruction;
-	symbol->il_instruction->accept(*this);
-	/* This object has (inherits) the same candidate datatypes as the il_instruction */
-	copy_candidate_datatype_list(symbol->il_instruction /*from*/, symbol /*to*/);	
-	prev_il_instruction = NULL;
+	if (NULL == symbol->il_instruction) {
+		/* This object has (inherits) the same candidate datatypes as the prev_il_instruction */
+		copy_candidate_datatype_list(symbol->prev_il_instruction /*from*/, symbol /*to*/);	
+	} else {
+		prev_il_instruction = symbol->prev_il_instruction;
+		symbol->il_instruction->accept(*this);
+		prev_il_instruction = NULL;
+
+		/* This object has (inherits) the same candidate datatypes as the il_instruction */
+		copy_candidate_datatype_list(symbol->il_instruction /*from*/, symbol /*to*/);	
+	}
 
 	return NULL;
 }
--- a/stage3/flow_control_analysis.cc	Fri Feb 17 19:47:58 2012 +0000
+++ b/stage3/flow_control_analysis.cc	Sat Feb 18 21:03:01 2012 +0000
@@ -112,8 +112,9 @@
 /*| instruction_list il_instruction */
 // SYM_LIST(instruction_list_c)
 void *flow_control_analysis_c::visit(instruction_list_c *symbol) {
-	for(int i = 1; i < symbol->n; i++) {
-		prev_il_instruction = symbol->elements[i-1];
+	for(int i = 0; i < symbol->n; i++) {
+		prev_il_instruction = NULL;
+		if (i > 0) prev_il_instruction = symbol->elements[i-1];
 		symbol->elements[i]->accept(*this);
 	}
 	return NULL;
--- a/stage3/narrow_candidate_datatypes.cc	Fri Feb 17 19:47:58 2012 +0000
+++ b/stage3/narrow_candidate_datatypes.cc	Sat Feb 18 21:03:01 2012 +0000
@@ -254,6 +254,54 @@
 
 
 
+
+/* narrow implicit FB call in IL.
+ * e.g.  CLK ton_var
+ *        CU counter_var
+ *
+ * The algorithm will be to build a fake il_fb_call_c equivalent to the implicit IL FB call, and let 
+ * the visit(il_fb_call_c *) method handle it!
+ */
+void narrow_candidate_datatypes_c::narrow_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name, symbol_c *&called_fb_declaration) {
+	if (NULL == called_fb_declaration)
+		/* The fill_candidate_datatypes_c was not able to determine which FB is being called!
+		 * This may be because the il_operand is not the name of a FB instance, or no operand was given. 
+		 * In that case, we just give up!
+		 */
+		return;
+	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.
+		 */
+		return;
+	}
+
+	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_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)
+	il_fb_call_c il_fb_call(NULL, il_operand, NULL, &il_param_list);
+	
+	/* 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.
+	 *
+	 * The above will be done by the visit(il_fb_call_c *) method, so we must make sure to
+	 * 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;
+}
+
+
 /* a helper function... */
 symbol_c *narrow_candidate_datatypes_c::base_type(symbol_c *symbol) {
 	/* NOTE: symbol == NULL is valid. It will occur when, for e.g., an undefined/undeclared symbolic_variable is used
@@ -404,13 +452,16 @@
 // SYM_REF2(il_instruction_c, label, il_instruction)
 // void *visit(instruction_list_c *symbol);
 void *narrow_candidate_datatypes_c::visit(il_instruction_c *symbol) {
-	if (NULL == symbol->il_instruction)
-		return NULL;
-
-	prev_il_instruction = symbol->prev_il_instruction;
-	/* Tell the il_instruction the datatype that it must generate - this was chosen by the next il_instruction (we iterate backwards!) */
-	symbol->il_instruction->datatype = symbol->datatype;
-	symbol->il_instruction->accept(*this);
+	if (NULL == symbol->il_instruction) {
+		/* this empty/null il_instruction cannot generate the desired datatype. We pass on the request to the previous il instruction. */
+		if (NULL != symbol->prev_il_instruction)
+			symbol->prev_il_instruction->datatype = symbol->datatype;
+	} else {
+		prev_il_instruction = symbol->prev_il_instruction;
+		/* Tell the il_instruction the datatype that it must generate - this was chosen by the next il_instruction (remember: we are iterating backwards!) */
+		symbol->il_instruction->datatype = symbol->datatype;
+		symbol->il_instruction->accept(*this);
+	}
 	return NULL;
 }
 
@@ -505,6 +556,26 @@
 /* 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!
+	 */
+	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.
@@ -627,52 +698,76 @@
 	return NULL;
 }
 
-void *narrow_candidate_datatypes_c::visit(S_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(R_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(S1_operator_c *symbol) {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(R1_operator_c *symbol) {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(S_operator_c *symbol)  {
+  /* TODO: what if this is a FB call? */
+	return handle_il_instruction(symbol);
+}
+void *narrow_candidate_datatypes_c::visit(R_operator_c *symbol)  {
+  /* TODO: what if this is a FB call? */
+	return handle_il_instruction(symbol);
+}
+
+
+void *narrow_candidate_datatypes_c::visit(S1_operator_c *symbol) {
+	narrow_implicit_il_fb_call(symbol, "S1", symbol->called_fb_declaration);
+	return NULL;
+}
+
+void *narrow_candidate_datatypes_c::visit(R1_operator_c *symbol) {
+	narrow_implicit_il_fb_call(symbol, "R1", symbol->called_fb_declaration);
+	return NULL;
+}
 
 void *narrow_candidate_datatypes_c::visit(CLK_operator_c *symbol) {
+	narrow_implicit_il_fb_call(symbol, "CLK", symbol->called_fb_declaration);
 	return NULL;
 }
 
 void *narrow_candidate_datatypes_c::visit(CU_operator_c *symbol) {
+	narrow_implicit_il_fb_call(symbol, "CU", symbol->called_fb_declaration);
 	return NULL;
 }
 
 void *narrow_candidate_datatypes_c::visit(CD_operator_c *symbol) {
+	narrow_implicit_il_fb_call(symbol, "CD", symbol->called_fb_declaration);
 	return NULL;
 }
 
 void *narrow_candidate_datatypes_c::visit(PV_operator_c *symbol) {
+	narrow_implicit_il_fb_call(symbol, "PV", symbol->called_fb_declaration);
 	return NULL;
 }
 
 void *narrow_candidate_datatypes_c::visit(IN_operator_c *symbol) {
+	narrow_implicit_il_fb_call(symbol, "IN", symbol->called_fb_declaration);
 	return NULL;
 }
 
 void *narrow_candidate_datatypes_c::visit(PT_operator_c *symbol) {
-	return NULL;
-}
-
-void *narrow_candidate_datatypes_c::visit(AND_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(OR_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(XOR_operator_c *symbol)  {return handle_il_instruction(symbol);}
+	narrow_implicit_il_fb_call(symbol, "PT", symbol->called_fb_declaration);
+	return NULL;
+}
+
+
+
+void *narrow_candidate_datatypes_c::visit(AND_operator_c  *symbol)  {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(OR_operator_c   *symbol)  {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(XOR_operator_c  *symbol)  {return handle_il_instruction(symbol);}
 void *narrow_candidate_datatypes_c::visit(ANDN_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(ORN_operator_c *symbol)  {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(ORN_operator_c  *symbol)  {return handle_il_instruction(symbol);}
 void *narrow_candidate_datatypes_c::visit(XORN_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(ADD_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(SUB_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(MUL_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(DIV_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(MOD_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(GT_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(GE_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(EQ_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(LT_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(LE_operator_c *symbol)  {return handle_il_instruction(symbol);}
-void *narrow_candidate_datatypes_c::visit(NE_operator_c *symbol)  {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(ADD_operator_c  *symbol)  {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(SUB_operator_c  *symbol)  {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(MUL_operator_c  *symbol)  {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(DIV_operator_c  *symbol)  {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(MOD_operator_c  *symbol)  {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(GT_operator_c   *symbol)  {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(GE_operator_c   *symbol)  {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(EQ_operator_c   *symbol)  {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(LT_operator_c   *symbol)  {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(LE_operator_c   *symbol)  {return handle_il_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(NE_operator_c   *symbol)  {return handle_il_instruction(symbol);}
+
 
 void *narrow_candidate_datatypes_c::visit(CAL_operator_c *symbol) {
 	return NULL;
--- a/stage3/narrow_candidate_datatypes.hh	Fri Feb 17 19:47:58 2012 +0000
+++ b/stage3/narrow_candidate_datatypes.hh	Sat Feb 18 21:03:01 2012 +0000
@@ -49,7 +49,7 @@
     void narrow_function_invocation(symbol_c *f_call, generic_function_call_t fcall_data);
     void narrow_nonformal_call(symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count = NULL);
     void narrow_formal_call(symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count = NULL);
-    
+    void narrow_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name, symbol_c *&called_fb_declaration);
     void *handle_il_instruction(symbol_c *symbol);
 
   public:
--- a/stage3/print_datatypes_error.cc	Fri Feb 17 19:47:58 2012 +0000
+++ b/stage3/print_datatypes_error.cc	Sat Feb 18 21:03:01 2012 +0000
@@ -136,6 +136,15 @@
 		if (NULL != f_decl) {
 			function_param_iterator_c fp_iterator(f_decl);
 			while ((param_name = fcp_iterator.next_f()) != NULL) {
+#if 0
+/* TODO: check whether direction (IN, OUT, IN_OUT) and assignment types (:= , =>) are compatible !!! */
+
+
+/* TODO: Check if there are duplicat parameter values */
+		verify_duplicate_param = fcp_iterator.search_f(call_param_name);
+		if(verify_duplicate_param != call_param_value)
+			return false;
+#endif
 				param_value = fcp_iterator.get_current_value();
 				/* Find the corresponding parameter in function declaration */
 				if (NULL == fp_iterator.search(param_name)) {
@@ -166,8 +175,33 @@
 	return;
 }
 
-
-
+void print_datatypes_error_c::handle_implicit_il_fb_invocation(symbol_c *il_operator, const char *param_name, symbol_c *called_fb_declaration) {
+	if (NULL == il_operand) {
+		STAGE3_ERROR(0, il_operator, il_operator, "Missing operand for FB call operator '%s'.", param_name);
+		return;
+	}
+	if (NULL == called_fb_declaration) {
+		STAGE3_ERROR(0, il_operand, il_operand, "Operand of FB call operator '%s' is not a FB variable.", param_name);
+		return;
+	}
+	if (NULL == prev_il_instruction) {
+		STAGE3_ERROR(0, il_operator, il_operand, "FB invocation operator '%s' must be preceded by a 'LD' (or equivalent) operator.", param_name);	
+		return;
+	}
+	/* Find the corresponding parameter in function declaration */
+	function_param_iterator_c fp_iterator(called_fb_declaration);
+	if (NULL == fp_iterator.search(param_name)) {
+/* TODO: must also check whther it is an IN parameter!! */
+		STAGE3_ERROR(0, il_operator, il_operand, "FB called by '%s' operator does not have a parameter named '%s'", param_name, param_name);	
+		return;
+	}
+	if (NULL == prev_il_instruction->datatype) {
+		STAGE3_ERROR(0, il_operator, il_operand, "Data type incompatibility between parameter '%s' and value being passed, when invoking FB.", param_name);
+		return;
+	}
+
+	return;
+}
 
 
 /*********************/
@@ -432,7 +466,7 @@
  */
 void *print_datatypes_error_c::visit(structured_variable_c *symbol) {
 	if (symbol->candidate_datatypes.size() == 0)
-		STAGE3_ERROR(0, symbol, symbol, "Structure variable not declared in this scope.");
+		STAGE3_ERROR(0, symbol, symbol, "Undeclared structured/FB variable.");
 	return NULL;
 }
 
@@ -538,11 +572,16 @@
 		/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
 	};
 
+/* TODO: check what error message (if any) the compiler will give out if this function invocation
+ * is not preceded by a LD operator (or another equivalent operator or list of operators).
+ * I.e. if it is preceded by an operator or operator list that will set the 'current value'.
+ * I.e. if the prev_il_operand == NULL;
+ */
 	handle_function_invocation(symbol, fcall_param);
 	
 	/* 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. This is done in fill_candidate_datatypes_c.
+	 * In order to be able to handle this without coding special cases, we simply prepend that symbol
+	 * to the il_operand_list. This was done in fill_candidate_datatypes_c.
 	 * We now undo those changes!
 	 */  
 	((list_c *)symbol->il_operand_list)->remove_element(0);
@@ -662,6 +701,7 @@
 }
 
 void *print_datatypes_error_c::visit(S_operator_c *symbol) {
+  /* TODO: what if this is a FB call ?? */
 	il_operand->accept(*this);
 	if ((symbol->candidate_datatypes.size() == 0) 		&&
 		(il_operand->candidate_datatypes.size() > 0))
@@ -671,6 +711,7 @@
 }
 
 void *print_datatypes_error_c::visit(R_operator_c *symbol) {
+  /* TODO: what if this is a FB call ?? */
 	il_operand->accept(*this);
 	if ((symbol->candidate_datatypes.size() == 0) 		&&
 		(il_operand->candidate_datatypes.size() > 0))
@@ -680,50 +721,42 @@
 }
 
 void *print_datatypes_error_c::visit(S1_operator_c *symbol) {
-	il_operand->accept(*this);
-	if ((symbol->candidate_datatypes.size() == 0) 		&&
-		(il_operand->candidate_datatypes.size() > 0))
-		STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'S1' operator.");
-	prev_il_instruction = symbol;
+	handle_implicit_il_fb_invocation(symbol, "S1", symbol->called_fb_declaration);  
 	return NULL;
 }
 
 void *print_datatypes_error_c::visit(R1_operator_c *symbol) {
-	il_operand->accept(*this);
-	if ((symbol->candidate_datatypes.size() == 0) 		&&
-		(il_operand->candidate_datatypes.size() > 0))
-		STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'R1' operator.");
-	prev_il_instruction = symbol;
+	handle_implicit_il_fb_invocation(symbol, "R1", symbol->called_fb_declaration);  
 	return NULL;
 }
 
 void *print_datatypes_error_c::visit(CLK_operator_c *symbol) {
-	prev_il_instruction = symbol;
+	handle_implicit_il_fb_invocation(symbol, "CLK", symbol->called_fb_declaration);  
 	return NULL;
 }
 
 void *print_datatypes_error_c::visit(CU_operator_c *symbol) {
-	prev_il_instruction = symbol;
+	handle_implicit_il_fb_invocation(symbol, "CU", symbol->called_fb_declaration);  
 	return NULL;
 }
 
 void *print_datatypes_error_c::visit(CD_operator_c *symbol) {
-	prev_il_instruction = symbol;
+	handle_implicit_il_fb_invocation(symbol, "CD", symbol->called_fb_declaration);  
 	return NULL;
 }
 
 void *print_datatypes_error_c::visit(PV_operator_c *symbol) {
-	prev_il_instruction = symbol;
+	handle_implicit_il_fb_invocation(symbol, "PV", symbol->called_fb_declaration);  
 	return NULL;
 }
 
 void *print_datatypes_error_c::visit(IN_operator_c *symbol) {
-	prev_il_instruction = symbol;
+	handle_implicit_il_fb_invocation(symbol, "IN", symbol->called_fb_declaration);  
 	return NULL;
 }
 
 void *print_datatypes_error_c::visit(PT_operator_c *symbol) {
-	prev_il_instruction = symbol;
+	handle_implicit_il_fb_invocation(symbol, "PT", symbol->called_fb_declaration);  
 	return NULL;
 }
 
--- a/stage3/print_datatypes_error.hh	Fri Feb 17 19:47:58 2012 +0000
+++ b/stage3/print_datatypes_error.hh	Sat Feb 18 21:03:01 2012 +0000
@@ -84,6 +84,7 @@
     /* some helper functions... */
     symbol_c *base_type(symbol_c *symbol);
     void handle_function_invocation(symbol_c *fcall, generic_function_call_t fcall_data);
+    void handle_implicit_il_fb_invocation(symbol_c *il_operator, const char *param_name, symbol_c *called_fb_declaration);  
 
   public:
     print_datatypes_error_c(symbol_c *ignore);