# HG changeset patch # User Mario de Sousa # Date 1330197395 0 # Node ID 933c0dccc82fed449d3a899a20f8a2915d64d2e1 # Parent 099aa5d655dea024838eb8fb9e7048be23658bad Add support for semantic verification of CALC, CALCN, etc.. diff -r 099aa5d655de -r 933c0dccc82f stage3/fill_candidate_datatypes.cc --- 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, diff -r 099aa5d655de -r 933c0dccc82f stage3/fill_candidate_datatypes.hh --- 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); diff -r 099aa5d655de -r 933c0dccc82f stage3/narrow_candidate_datatypes.cc --- 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 */ diff -r 099aa5d655de -r 933c0dccc82f stage3/narrow_candidate_datatypes.hh --- 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); diff -r 099aa5d655de -r 933c0dccc82f stage3/print_datatypes_error.cc --- 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 */ diff -r 099aa5d655de -r 933c0dccc82f stage3/print_datatypes_error.hh --- 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);