Add support for semantic verification of CALC, CALCN, etc..
authorMario de Sousa <msousa@fe.up.pt>
Sat, 25 Feb 2012 19:16:35 +0000
changeset 455 933c0dccc82f
parent 454 099aa5d655de
child 456 ca8d98289ff9
Add support for semantic verification of CALC, CALCN, etc..
stage3/fill_candidate_datatypes.cc
stage3/fill_candidate_datatypes.hh
stage3/narrow_candidate_datatypes.cc
stage3/narrow_candidate_datatypes.hh
stage3/print_datatypes_error.cc
stage3/print_datatypes_error.hh
--- a/stage3/fill_candidate_datatypes.cc	Thu Feb 23 13:25:49 2012 +0000
+++ b/stage3/fill_candidate_datatypes.cc	Sat Feb 25 19:16:35 2012 +0000
@@ -91,6 +91,7 @@
 			if(param_name == NULL) return false;
 		} while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0));
 
+		/* TODO: verify if it is lvalue when INOUT or OUTPUT parameters! */
 		/* Get the parameter type */
 		param_datatype = base_type(fp_iterator.param_type());
 		
@@ -106,7 +107,7 @@
 
 /* returns true if compatible function/FB invocation, otherwise returns false */
 /* Assumes that the candidate_datatype lists of all the parameters being passed haved already been filled in */
-bool fill_candidate_datatypes_c::match_formal_call(symbol_c *f_call, symbol_c *f_decl) {
+bool fill_candidate_datatypes_c::match_formal_call(symbol_c *f_call, symbol_c *f_decl, symbol_c **first_param_datatype) {
 	symbol_c *call_param_value, *call_param_name, *param_datatype;
 	symbol_c *verify_duplicate_param;
 	identifier_c *param_name;
@@ -115,6 +116,7 @@
 	int extensible_parameter_highest_index = -1;
 	identifier_c *extensible_parameter_name;
 	unsigned int i;
+	bool is_first_param = true;
 
 	/* Iterating through the formal parameters of the function call */
 	while((call_param_name = fcp_iterator.next_f()) != NULL) {
@@ -155,6 +157,12 @@
 		/* check whether one of the candidate_data_types of the value being passed is the same as the param_type */
 		if (search_in_candidate_datatype_list(param_datatype, call_param_types) < 0)
 			return false; /* return false if param_type not in the list! */
+		
+		/* If this is the first parameter, then copy the datatype to *first_param_datatype */
+		if (is_first_param)
+			if (NULL != first_param_datatype)
+				*first_param_datatype = param_datatype;
+		is_first_param = false;
 	}
 	/* call is compatible! */
 	return true;
@@ -255,59 +263,30 @@
 /* handle 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 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!
-	 */
-	if (NULL == fb_type_id)
-		return;
+  	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
+	if (NULL == fb_type_id) ERROR;
 
 	function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(fb_type_id);
 	if (function_block_type_symtable.end_value() == fb_decl)
 		/* The il_operand is not the name of a FB instance. Most probably it is the name of a variable of some other type.
-		 * this is a smeantic error, so there is no way we can evaluate the rest of the code. We simply give up, and leave
-		 * the candidate_datatype_list empty, and the called_fb_declaration pointing to NULL
+		 * this is a semantic error.
 		 */
-		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;
-	}
-
-	/* 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 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!
+		fb_decl = NULL;
+	
+	/* The narrow_candidate_datatypes_c does not rely on this called_fb_declaration pointer being == NULL to conclude that
+	 * we have a datatype incompatibility error, so we set it to fb_decl to allow the print_datatype_error_c to print out
+	 * more informative error messages!
 	 */
-	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, &param_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)
-	il_fb_call_c il_fb_call(NULL, il_operand, NULL, &il_param_list);
-	
-	il_fb_call.accept(*this);
-	copy_candidate_datatype_list(&il_fb_call/*from*/, il_instruction/*to*/);
-	called_fb_declaration = il_fb_call.called_fb_declaration;
+	called_fb_declaration = fb_decl;
+
+	/* This implicit FB call does not change the value stored in the current/default IL variable */
+	if (NULL != prev_il_instruction)
+		copy_candidate_datatype_list(prev_il_instruction/*from*/, il_instruction/*to*/);
+
+	if (debug) std::cout << "handle_implicit_il_fb_call() [" << prev_il_instruction->candidate_datatypes.size() << "] ==> " << il_instruction->candidate_datatypes.size() << " result.\n";
 }
 
 
@@ -723,10 +702,7 @@
 /* subscript_list ',' subscript */
 // SYM_LIST(subscript_list_c)
 /* NOTE: we inherit from iterator visitor, so we do not need to implement this method... */
-#if 0
-void *fill_candidate_datatypes_c::visit(subscript_list_c *symbol) {
-}
-#endif
+// void *fill_candidate_datatypes_c::visit(subscript_list_c *symbol)
 
 
 /*  record_variable '.' field_selector */
@@ -796,10 +772,8 @@
 /* B 1.7 Configuration elements */
 /********************************/
 void *fill_candidate_datatypes_c::visit(configuration_declaration_c *symbol) {
-#if 0
 	// TODO !!!
 	/* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */
-#endif
 	return NULL;
 }
 
@@ -945,19 +919,24 @@
 /* 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 *fill_candidate_datatypes_c::visit(il_fb_call_c *symbol) {
-	bool compatible = false;
-	symbol_c *fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name);
+	/* We do not call
+	 * fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name);
+	 * because we want to make sure it is a FB instance, and not some other data type...
+	 */
+	symbol_c *fb_type_id = search_varfb_instance_type->get_basetype_id(symbol->fb_name);
+	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
+	if (NULL == fb_type_id) ERROR;
+
+ 	function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(fb_type_id);
+	if (function_block_type_symtable.end_value() == fb_decl) 
+		/* The fb_name not the name of a FB instance. Most probably it is the name of a variable of some other type. */
+		fb_decl = NULL;
+
 	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
 	if (NULL == fb_decl) ERROR;
 
-	if (symbol->  il_param_list != NULL) {
-		symbol->il_param_list->accept(*this);
-		compatible = match_formal_call(symbol, fb_decl);
-	}
-	if (symbol->il_operand_list != NULL) {
-		symbol->il_operand_list->accept(*this);
-		compatible = match_nonformal_call(symbol, fb_decl);
-	}
+	if (symbol->  il_param_list != NULL) symbol->il_param_list->accept(*this);
+	if (symbol->il_operand_list != NULL) symbol->il_operand_list->accept(*this);
 
 	/* The print_datatypes_error_c does not rely on this called_fb_declaration pointer being != NULL to conclude that
 	 * we have a datat type incompatibility error, so setting it to the correct fb_decl is actually safe,
@@ -965,8 +944,15 @@
 	 */
 	symbol->called_fb_declaration = fb_decl;
 
-	/* This object has the same candidate datatypes as the prev_il_instruction, since it does not change the value stored in the current/default IL variable. */
-	copy_candidate_datatype_list(prev_il_instruction/*from*/, symbol/*to*/);
+	/* Let the il_call_operator (CAL, CALC, or CALCN) determine the candidate datatypes of the il_fb_call_c... */
+	/* NOTE: We ignore whether the call is 'compatible' or not when filling in the candidate datatypes list.
+	 *       Even if it is not compatible, we fill in the candidate datatypes list correctly so that the following
+	 *       IL instructions may be handled correctly and debuged.
+	 *       Doing this is actually safe, as the parameter_list will still contain errors that will be found by
+	 *       print_datatypes_error_c, so the code will never reach stage 4!
+	 */
+	symbol->il_call_operator->accept(*this);
+	copy_candidate_datatype_list(symbol->il_call_operator/*from*/, symbol/*to*/);
 
 	if (debug) std::cout << "FB [] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
 	return NULL;
@@ -2002,19 +1988,20 @@
 /* B 3.2.2 Subprogram Control Statements */
 /*****************************************/
 void *fill_candidate_datatypes_c::visit(fb_invocation_c *symbol) {
-	bool compatible = false;
-	symbol_c *fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name);
+	symbol_c *fb_type_id = search_varfb_instance_type->get_basetype_id(symbol->fb_name);
+	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
+	if (NULL == fb_type_id) ERROR;
+
+	function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(fb_type_id);
+	if (function_block_type_symtable.end_value() == fb_decl) 
+		/* The fb_name not the name of a FB instance. Most probably it is the name of a variable of some other type. */
+		fb_decl = NULL;
+
 	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
 	if (NULL == fb_decl) ERROR;
-
-	if (symbol->   formal_param_list != NULL) {
-		symbol->formal_param_list->accept(*this);
-		compatible = match_formal_call(symbol, fb_decl);
-	}
-	if (symbol->nonformal_param_list != NULL) {
-		symbol->nonformal_param_list->accept(*this);
-		compatible = match_nonformal_call(symbol, fb_decl);
-	}
+	
+	if (symbol->   formal_param_list != NULL) symbol->formal_param_list->accept(*this);
+	if (symbol->nonformal_param_list != NULL) symbol->nonformal_param_list->accept(*this);
 
 	/* The print_datatypes_error_c does not rely on this called_fb_declaration pointer being != NULL to conclude that
 	 * we have a datat type incompatibility error, so setting it to the correct fb_decl is actually safe,
--- a/stage3/fill_candidate_datatypes.hh	Thu Feb 23 13:25:49 2012 +0000
+++ b/stage3/fill_candidate_datatypes.hh	Sat Feb 25 19:16:35 2012 +0000
@@ -84,7 +84,7 @@
     /* Match a function declaration with a function call through their parameters.*/
     /* returns true if compatible function/FB invocation, otherwise returns false */
     bool match_nonformal_call(symbol_c *f_call, symbol_c *f_decl);
-    bool match_formal_call   (symbol_c *f_call, symbol_c *f_decl);
+    bool match_formal_call   (symbol_c *f_call, symbol_c *f_decl, symbol_c **first_param_datatype = NULL);
     void handle_function_call(symbol_c *fcall, generic_function_call_t fcall_data);
     void handle_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name, symbol_c *&called_fb_declaration);
     
--- a/stage3/narrow_candidate_datatypes.cc	Thu Feb 23 13:25:49 2012 +0000
+++ b/stage3/narrow_candidate_datatypes.cc	Sat Feb 25 19:16:35 2012 +0000
@@ -175,11 +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 (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 .
-		 */
 		call_param_value->accept(*this);
 
+		/* set the extensible_parameter_highest_index, which will be needed in stage 4 */
+		/* This value says how many extensible parameters are being passed to the standard function */
 		if (NULL != param_name) 
 			if (extensible_parameter_highest_index < fp_iterator.extensible_param_index())
 				extensible_parameter_highest_index = fp_iterator.extensible_param_index();
@@ -261,12 +260,15 @@
  * 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;
+
+	/* set the datatype of the il_operand, this is, the FB being called! */
+	if (NULL != il_operand) {
+		/* only set it if it is in the candidate datatypes list! */  
+		set_datatype(called_fb_declaration, il_operand);
+		il_operand->accept(*this);
+	}
+	symbol_c *fb_decl = il_operand->datatype;
+
 	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.
@@ -275,6 +277,15 @@
 		return;
 	}
 
+	if (NULL == fb_decl) {
+		/* the il_operand is a not FB instance */
+		/* so we simply pass on the required datatype to the prev_il_instruction */
+		/* The invalid FB invocation will be caught by the print_datatypes_error_c by analysing NULL value in il_operand->datatype! */
+		prev_il_instruction->datatype = il_instruction->datatype;
+		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.
@@ -285,7 +296,7 @@
 	 * 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);  
@@ -294,8 +305,9 @@
 	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);
-	
+	CAL_operator_c CAL_operator;
+	il_fb_call_c il_fb_call(&CAL_operator, 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
@@ -304,9 +316,10 @@
 	 * 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*/);
+// 	copy_candidate_datatype_list(il_instruction/*from*/, &il_fb_call/*to*/);
+	il_fb_call.called_fb_declaration = called_fb_declaration;
 	il_fb_call.accept(*this);
-	
+
 	/* 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
@@ -327,13 +340,11 @@
 	 *     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;
-		}
-
+	if ((NULL == il_instruction->datatype) || (is_type_equal(param_value.datatype, il_instruction->datatype))) {
+		prev_il_instruction->datatype = param_value.datatype;
+	} else {
+		prev_il_instruction->datatype = NULL;
+	}
 }
 
 
@@ -592,32 +603,16 @@
 /* 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) {
-	/* 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.
-	 *          fb_var( 
-	 *             in1 := var1,
-	 *             in2 := (
-	 *                       LD 56
-	 *                       ADD 43
-	 *                    )
-	 *             )
-	 *       even it the call to the FB is invalid. 
-	 *       This makes sense because it may be errors in those expressions which are
-	 *       making this an invalid call, so it makes sense to point them out to the user!
-	 */
-	symbol_c *fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name);
-
+	symbol_c *fb_decl = symbol->called_fb_declaration;
+	
 	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
 	if (NULL == fb_decl) ERROR;
 	if (NULL != symbol->il_operand_list)  narrow_nonformal_call(symbol, fb_decl);
 	if (NULL != symbol->  il_param_list)     narrow_formal_call(symbol, fb_decl);
 
-	/* 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)
-		prev_il_instruction->datatype = symbol->datatype;
+	/* Let the il_call_operator (CAL, CALC, or CALCN) set the datatype of prev_il_instruction... */
+	symbol->il_call_operator->datatype = symbol->datatype;
+	symbol->il_call_operator->accept(*this);
 	return NULL;
 }
 
@@ -825,40 +820,90 @@
 void *narrow_candidate_datatypes_c::visit(NE_operator_c   *symbol)  {return handle_il_instruction(symbol);}
 
 
+// SYM_REF0(CAL_operator_c)
+/* called from il_fb_call_c (symbol->il_call_operator->accpet(*this) ) */
 void *narrow_candidate_datatypes_c::visit(CAL_operator_c *symbol) {
-	return NULL;
-}
-
+	/* set the desired datatype of the previous il instruction */
+	/* This FB call does not change the value in the current/default IL variable, so we pass the required datatype to the previous IL instruction */
+	if (NULL != prev_il_instruction)
+		prev_il_instruction->datatype = symbol->datatype;
+	return NULL;
+}
+
+
+void *narrow_candidate_datatypes_c::narrow_conditional_flow_control_IL_instruction(symbol_c *symbol) {
+	/* if the next IL instructions needs us to provide a datatype other than a bool, 
+	 * then we have an internal compiler error - most likely in fill_candidate_datatypes_c 
+	 */
+	if ((NULL != symbol->datatype) && (!is_type(symbol->datatype, bool_type_name_c))) ERROR;
+	if (symbol->candidate_datatypes.size() > 1) ERROR;
+
+	/* NOTE: If there is not IL instruction following this CALC, CALCN, JMPC, JMPC, ..., instruction,
+	 *       we must still provide a bool_type_name_c datatype (if possible, i.e. if it exists in the candidate datatype list).
+	 *       If it is not possible, we set it to NULL
+	 */
+	if (symbol->candidate_datatypes.size() == 0)    symbol->datatype = NULL;
+	else    symbol->datatype = symbol->candidate_datatypes[0]; /* i.e. a bool_type_name_c! */
+	if ((NULL != symbol->datatype) && (!is_type(symbol->datatype, bool_type_name_c))) ERROR;
+
+	/* set the required datatype of the previous IL instruction, i.e. a bool_type_name_c! */
+	if (NULL != prev_il_instruction)    prev_il_instruction->datatype = symbol->datatype;
+	return NULL;
+}
+
+
+// SYM_REF0(CALC_operator_c)
+/* called from il_fb_call_c (symbol->il_call_operator->accpet(*this) ) */
 void *narrow_candidate_datatypes_c::visit(CALC_operator_c *symbol) {
-	return NULL;
-}
-
+	return narrow_conditional_flow_control_IL_instruction(symbol);
+}
+
+
+// SYM_REF0(CALCN_operator_c)
+/* called from il_fb_call_c (symbol->il_call_operator->accpet(*this) ) */
 void *narrow_candidate_datatypes_c::visit(CALCN_operator_c *symbol) {
-	return NULL;
-}
+	return narrow_conditional_flow_control_IL_instruction(symbol);
+}
+
 
 void *narrow_candidate_datatypes_c::visit(RET_operator_c *symbol) {
+	/* set the desired datatype of the previous il instruction */
+	/* This RET instruction does not change the value in the current/default IL variable, so we pass the required datatype to the previous IL instruction.
+	 * Actually this should always be NULL, otherwise we have a bug in the flow_control_analysis_c
+	 * However, since that class has not yet been completely finished, we do not yet check this assertion!
+	 */
+// 	if (NULL != symbol->datatype) ERROR;
+	if (NULL != prev_il_instruction)
+		prev_il_instruction->datatype = symbol->datatype;
 	return NULL;
 }
 
 void *narrow_candidate_datatypes_c::visit(RETC_operator_c *symbol) {
-	return NULL;
+	return narrow_conditional_flow_control_IL_instruction(symbol);
 }
 
 void *narrow_candidate_datatypes_c::visit(RETCN_operator_c *symbol) {
-	return NULL;
+	return narrow_conditional_flow_control_IL_instruction(symbol);
 }
 
 void *narrow_candidate_datatypes_c::visit(JMP_operator_c *symbol) {
+	/* set the desired datatype of the previous il instruction */
+	/* This JMP instruction does not change the value in the current/default IL variable, so we pass the required datatype to the previous IL instruction.
+	 * Actually this should always be NULL, otherwise we have a bug in the flow_control_analysis_c
+	 * However, since that class has not yet been completely finished, we do not yet check this assertion!
+	 */
+// 	if (NULL != symbol->datatype) ERROR;
+	if (NULL != prev_il_instruction)
+		prev_il_instruction->datatype = symbol->datatype;
 	return NULL;
 }
 
 void *narrow_candidate_datatypes_c::visit(JMPC_operator_c *symbol) {
-	return NULL;
+	return narrow_conditional_flow_control_IL_instruction(symbol);
 }
 
 void *narrow_candidate_datatypes_c::visit(JMPCN_operator_c *symbol) {
-	return NULL;
+	return narrow_conditional_flow_control_IL_instruction(symbol);
 }
 
 /* Symbol class handled together with function call checks */
--- a/stage3/narrow_candidate_datatypes.hh	Thu Feb 23 13:25:49 2012 +0000
+++ b/stage3/narrow_candidate_datatypes.hh	Sat Feb 25 19:16:35 2012 +0000
@@ -51,6 +51,8 @@
     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);
+    void *narrow_conditional_flow_control_IL_instruction(symbol_c *symbol);
+
 
   public:
     narrow_candidate_datatypes_c(symbol_c *ignore);
--- a/stage3/print_datatypes_error.cc	Thu Feb 23 13:25:49 2012 +0000
+++ b/stage3/print_datatypes_error.cc	Sat Feb 25 19:16:35 2012 +0000
@@ -183,6 +183,8 @@
 		fcall_data.nonformal_operand_list->accept(*this);
 		if (f_decl)
 			for (int i = 1; (param_value = fcp_iterator.next_nf()) != NULL; i++) {
+		  		/* TODO: verify if it is lvalue when INOUT or OUTPUT parameters! */
+
 				if (NULL == param_value->datatype) {
 					function_invocation_error = true;
 					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);
@@ -203,31 +205,57 @@
 	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;
 	}
+	il_operand->accept(*this);
+	
 	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);
+		STAGE3_ERROR(0, il_operator, il_operand, "Invalid FB call: operand is not a FB instance.");
 		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!! */
+		/* TODO: must also check whther it is an IN parameter!! */
+		/* NOTE: although all standard FBs have the implicit FB calls defined as input parameters
+		*        (i.e., for all standard FBs, CLK, PT, IN, CU, CD, S1, R1, etc... is always an input parameter)
+		*        if a non-standard (i.e. a FB not defined in the standard library) FB is being called, then
+		*        this (CLK, PT, IN, CU, ...) parameter may just have been defined as OUT or INOUT,
+		*        which will not work for an implicit FB call!
+		*/
 		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);
+		STAGE3_ERROR(0, il_operator, il_operand, "Data type incompatibility between parameter '%s' and value being passed.", param_name);
 		return;
 	}
-
+	
+
+	/* NOTE: The error_level currently being used for errors in variables/constants etc... is rather high.
+	 *       However, in the case of an implicit FB call, if the datatype of the operand == NULL, this may be
+	 *       the __only__ indication of an error! So we test it here again, to make sure thtis error will really
+	 *       be printed out!
+	 */
+	if (NULL == il_operand->datatype) {
+		/* Note: the case of (NULL == fb_declaration) was already caught above! */
+// 		if (NULL != fb_declaration) {
+			STAGE3_ERROR(0, il_operator, il_operator, "Invalid FB call: Datatype incompatibility between the FB's '%s' parameter and value being passed, or paramater '%s' is not a 'VAR_INPUT' parameter.", param_name, param_name);
+			return;
+// 		}
+	}
+// 
 	return;
 }
 
@@ -552,10 +580,8 @@
 /* B 1.7 Configuration elements */
 /********************************/
 void *print_datatypes_error_c::visit(configuration_declaration_c *symbol) {
-#if 0
 	// TODO !!!
 	/* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */
-#endif
 	return NULL;
 }
 
@@ -681,6 +707,8 @@
 	};
   
 	handle_function_invocation(symbol, fcall_param);
+	/* check the semantics of the CALC, CALCN operators! */
+	symbol->il_call_operator->accept(*this);
 	return NULL;
 }
 
@@ -922,12 +950,19 @@
 	return NULL;
 }
 
+
+void *print_datatypes_error_c::handle_conditional_flow_control_IL_instruction(symbol_c *symbol, const char *oper) {
+	if (NULL == symbol->datatype)
+		STAGE3_ERROR(0, symbol, symbol, "%s operator must be preceded by an IL instruction producing a BOOL value.", oper);
+	return NULL;
+}
+
 void *print_datatypes_error_c::visit(CALC_operator_c *symbol) {
-	return NULL;
+	return handle_conditional_flow_control_IL_instruction(symbol, "CALC");
 }
 
 void *print_datatypes_error_c::visit(CALCN_operator_c *symbol) {
-	return NULL;
+	return handle_conditional_flow_control_IL_instruction(symbol, "CALCN");
 }
 
 void *print_datatypes_error_c::visit(RET_operator_c *symbol) {
@@ -935,11 +970,11 @@
 }
 
 void *print_datatypes_error_c::visit(RETC_operator_c *symbol) {
-	return NULL;
+	return handle_conditional_flow_control_IL_instruction(symbol, "RETC");
 }
 
 void *print_datatypes_error_c::visit(RETCN_operator_c *symbol) {
-	return NULL;
+	return handle_conditional_flow_control_IL_instruction(symbol, "RETCN");
 }
 
 void *print_datatypes_error_c::visit(JMP_operator_c *symbol) {
@@ -947,11 +982,11 @@
 }
 
 void *print_datatypes_error_c::visit(JMPC_operator_c *symbol) {
-	return NULL;
+	return handle_conditional_flow_control_IL_instruction(symbol, "JMPC");
 }
 
 void *print_datatypes_error_c::visit(JMPCN_operator_c *symbol) {
-	return NULL;
+	return handle_conditional_flow_control_IL_instruction(symbol, "JMPCN");
 }
 
 /* Symbol class handled together with function call checks */
--- a/stage3/print_datatypes_error.hh	Thu Feb 23 13:25:49 2012 +0000
+++ b/stage3/print_datatypes_error.hh	Sat Feb 25 19:16:35 2012 +0000
@@ -42,7 +42,7 @@
   private:
     /* The level of detail that the user wants us to display error messages. */
 //     #define error_level_default (1)
-    #define error_level_default (4)
+    #define error_level_default (1)
     #define error_level_nagging (4)
     unsigned int current_display_error_level;
     
@@ -85,7 +85,8 @@
     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);  
-
+    void *handle_conditional_flow_control_IL_instruction(symbol_c *symbol, const char *oper);
+  
   public:
     print_datatypes_error_c(symbol_c *ignore);
     virtual ~print_datatypes_error_c(void);