Add support for semantic verification of CALC, CALCN, etc..
--- 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, ¶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)
- 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);