# HG changeset patch # User Mario de Sousa # Date 1329668205 0 # Node ID 3c6225521059585dfc95b9120a136d212e87d6e5 # Parent 1bd18fc0691123c776116c868c985f55252a0189 Semantic verification: Add compatibility check for parameter direction in function invocation. diff -r 1bd18fc06911 -r 3c6225521059 absyntax_utils/function_call_param_iterator.cc --- a/absyntax_utils/function_call_param_iterator.cc Sat Feb 18 21:03:01 2012 +0000 +++ b/absyntax_utils/function_call_param_iterator.cc Sun Feb 19 16:16:45 2012 +0000 @@ -184,6 +184,7 @@ */ symbol_c *function_call_param_iterator_c::next_f(void) { current_value = NULL; + current_assign_direction = assign_none; param_count = 0; iterate_f_next_param++; current_operation = function_call_param_iterator_c::iterate_f_op; @@ -201,6 +202,7 @@ */ symbol_c *function_call_param_iterator_c::next_nf(void) { current_value = NULL; + current_assign_direction = assign_none; param_count = 0; iterate_nf_next_param++; current_operation = function_call_param_iterator_c::iterate_nf_op; @@ -212,6 +214,7 @@ /* Search for the value passed to the parameter named ... */ symbol_c *function_call_param_iterator_c::search_f(symbol_c *param_name) { current_value = NULL; + current_assign_direction = assign_none; if (NULL == param_name) ERROR; search_param_name = dynamic_cast(param_name); if (NULL == search_param_name) ERROR; @@ -233,6 +236,12 @@ return current_value; } +/* Returns the value being passed to the current parameter. */ +function_call_param_iterator_c::assign_direction_t function_call_param_iterator_c::get_assign_direction(void) { + return current_assign_direction; +} + + /********************************/ /* B 1.7 Configuration elements */ /********************************/ @@ -339,6 +348,7 @@ if (NULL == symb_var) ERROR; + current_assign_direction = assign_in; return handle_parameter_assignment(symb_var->var_name, symbol->prog_data_source); } @@ -355,6 +365,7 @@ if (NULL == symb_var) ERROR; + current_assign_direction = assign_out; return handle_parameter_assignment(symb_var->var_name, symbol->data_sink); } @@ -459,6 +470,7 @@ // since we do not yet support it, it is best to simply stop than to fail silently... if (NULL != symbol->simple_instr_list) ERROR; + current_assign_direction = assign_in; return handle_parameter_assignment((symbol_c *)symbol->il_assign_operator->accept(*this), symbol->il_operand); } @@ -466,6 +478,7 @@ // SYM_REF2(il_param_out_assignment_c, il_assign_out_operator, variable); void *function_call_param_iterator_c::visit(il_param_out_assignment_c *symbol) { TRACE("il_param_out_assignment_c"); + current_assign_direction = assign_out; return handle_parameter_assignment((symbol_c *)symbol->il_assign_out_operator->accept(*this), symbol->variable); } @@ -564,6 +577,7 @@ // SYM_REF2(input_variable_param_assignment_c, variable_name, expression) void *function_call_param_iterator_c::visit(input_variable_param_assignment_c *symbol) { TRACE("input_variable_param_assignment_c"); + current_assign_direction = assign_in; return handle_parameter_assignment(symbol->variable_name, symbol->expression); } @@ -574,6 +588,7 @@ // TODO : Handle not_param !!! if (NULL != symbol->not_param) ERROR; // we do not yet support it, so it is best to simply stop than to fail silently... + current_assign_direction = assign_out; return handle_parameter_assignment(symbol->variable_name, symbol->variable); } diff -r 1bd18fc06911 -r 3c6225521059 absyntax_utils/function_call_param_iterator.hh --- a/absyntax_utils/function_call_param_iterator.hh Sat Feb 18 21:03:01 2012 +0000 +++ b/absyntax_utils/function_call_param_iterator.hh Sun Feb 19 16:16:45 2012 +0000 @@ -51,6 +51,58 @@ class function_call_param_iterator_c : public null_visitor_c { private: + void *search_list(list_c *list); + void *handle_parameter_assignment(symbol_c *variable_name, symbol_c *expression) ; + + + public: + /* start off at the first parameter once again... */ + void reset(void); + + /* initialise the iterator object. + * We must be given a reference to the function/program/function block call + * that will be analysed... + */ + function_call_param_iterator_c(symbol_c *f_call); + + /* Skip to the next formal parameter. After object creation, + * the object references on parameter _before_ the first, so + * this function must be called once to get the object to + * reference the first parameter... + * + * Returns the paramater name to which a value is being passed! + * You can determine the value being passed by calling + * function_call_param_iterator_c::search_f() + */ + symbol_c *next_f(void); + + /* Skip to the next non-formal parameter. After object creation, + * the object references on parameter _before_ the first, so + * this function must be called once to get the object to + * reference the first parameter... + * + * Returns whatever is being passed to the parameter! + */ + symbol_c *next_nf(void); + + /* Search for the value passed to the parameter named ... */ + symbol_c *search_f(symbol_c *param_name); + symbol_c *search_f(const char *param_name); + + /* Returns the value being passed to the current parameter. */ + symbol_c *get_current_value(void); + + /* A type to specify how the current parameter was assigned. + * param_name := var -> assign_in + * param_name => var -> assign_out + * -> assign_none (used when handling non formal calls, when no assignment type is used) + */ + typedef enum {assign_in, assign_out, assign_none} assign_direction_t ; + /* Returns the assignment direction of the current parameter. */ + assign_direction_t get_assign_direction(void); + + + private: /* a pointer to the function call * (or function block or program call!) */ @@ -58,6 +110,7 @@ int iterate_f_next_param, iterate_nf_next_param, param_count; identifier_c *search_param_name; symbol_c *current_value; + assign_direction_t current_assign_direction; /* Which operation of the class was called: * - iterate to the next non-formal parameter. @@ -67,49 +120,7 @@ typedef enum {iterate_nf_op, iterate_f_op, search_f_op} operation_t; operation_t current_operation; - private: - void *search_list(list_c *list); - void *handle_parameter_assignment(symbol_c *variable_name, symbol_c *expression) ; - - - public: - /* start off at the first parameter once again... */ - void reset(void); - - /* initialise the iterator object. - * We must be given a reference to the function/program/function block call - * that will be analysed... - */ - function_call_param_iterator_c(symbol_c *f_call); - - /* Skip to the next formal parameter. After object creation, - * the object references on parameter _before_ the first, so - * this function must be called once to get the object to - * reference the first parameter... - * - * Returns the paramater name to which a value is being passed! - * You can determine the value being passed by calling - * function_call_param_iterator_c::search_f() - */ - symbol_c *next_f(void); - - /* Skip to the next non-formal parameter. After object creation, - * the object references on parameter _before_ the first, so - * this function must be called once to get the object to - * reference the first parameter... - * - * Returns whatever is being passed to the parameter! - */ - symbol_c *next_nf(void); - - /* Search for the value passed to the parameter named ... */ - symbol_c *search_f(symbol_c *param_name); - symbol_c *search_f(const char *param_name); - - /* Returns the value being passed to the current parameter. */ - symbol_c *get_current_value(void); - - + private: /********************************/ /* B 1.7 Configuration elements */ diff -r 1bd18fc06911 -r 3c6225521059 stage3/fill_candidate_datatypes.cc --- a/stage3/fill_candidate_datatypes.cc Sat Feb 18 21:03:01 2012 +0000 +++ b/stage3/fill_candidate_datatypes.cc Sun Feb 19 16:16:45 2012 +0000 @@ -73,7 +73,7 @@ * beginning of the parameter list BEFORE calling handle_function_call(). */ bool fill_candidate_datatypes_c::match_nonformal_call(symbol_c *f_call, symbol_c *f_decl) { - symbol_c *call_param_value, *param_type; + symbol_c *call_param_value, *param_datatype; identifier_c *param_name; function_param_iterator_c fp_iterator(f_decl); function_call_param_iterator_c fcp_iterator(f_call); @@ -92,10 +92,10 @@ } while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0)); /* Get the parameter type */ - param_type = base_type(fp_iterator.param_type()); + param_datatype = base_type(fp_iterator.param_type()); /* 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_type, call_param_value->candidate_datatypes) < 0) + if (search_in_candidate_datatype_list(param_datatype, call_param_value->candidate_datatypes) < 0) return false; /* return false if param_type not in the list! */ } /* call is compatible! */ @@ -107,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) { - symbol_c *call_param_value, *call_param_name, *param_type; + symbol_c *call_param_value, *call_param_name, *param_datatype; symbol_c *verify_duplicate_param; identifier_c *param_name; function_param_iterator_c fp_iterator(f_decl); @@ -118,12 +118,14 @@ /* 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... */ if (NULL == call_param_value) ERROR; + /* Obtaining the assignment direction: := (assign_in) or => (assign_out) */ + function_call_param_iterator_c::assign_direction_t call_param_dir = fcp_iterator.get_assign_direction(); + /* Checking if there are duplicated parameter values */ verify_duplicate_param = fcp_iterator.search_f(call_param_name); if(verify_duplicate_param != call_param_value) @@ -135,10 +137,23 @@ /* Find the corresponding parameter in function declaration */ param_name = fp_iterator.search(call_param_name); if(param_name == NULL) return false; - /* Get the parameter type */ - param_type = base_type(fp_iterator.param_type()); + /* Get the parameter data type */ + param_datatype = base_type(fp_iterator.param_type()); + /* Get the parameter direction: IN, OUT, IN_OUT */ + function_param_iterator_c::param_direction_t param_dir = fp_iterator.param_direction(); + + /* check whether direction (IN, OUT, IN_OUT) and assignment types (:= , =>) are compatible !!! */ + if (function_call_param_iterator_c::assign_in == call_param_dir) { + if ((function_param_iterator_c::direction_in != param_dir) && + (function_param_iterator_c::direction_inout != param_dir)) + return false; + } else if (function_call_param_iterator_c::assign_out == call_param_dir) { + if ((function_param_iterator_c::direction_out != param_dir)) + return false; + } else ERROR; + /* 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_type, call_param_types) < 0) + if (search_in_candidate_datatype_list(param_datatype, call_param_types) < 0) return false; /* return false if param_type not in the list! */ } /* call is compatible! */ diff -r 1bd18fc06911 -r 3c6225521059 stage3/print_datatypes_error.cc --- a/stage3/print_datatypes_error.cc Sat Feb 18 21:03:01 2012 +0000 +++ b/stage3/print_datatypes_error.cc Sun Feb 19 16:16:45 2012 +0000 @@ -124,7 +124,6 @@ ERROR; } if (NULL == f_decl) { - STAGE3_ERROR(0, fcall, fcall, "Unable to resolve which overloaded %s '%s' is being invoked.", POU_str, ((identifier_c *)fcall_data.function_name)->value); /* we now try to find any function declaration with the same name, just so we can provide some relevant error messages */ function_symtable_t::iterator lower = function_symtable.lower_bound(fcall_data.function_name); if (lower == function_symtable.end()) ERROR; @@ -136,22 +135,46 @@ 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(); + + /* Check if there are duplicate parameter values */ + if(fcp_iterator.search_f(param_name) != param_value) { + function_invocation_error = true; + STAGE3_ERROR(0, param_name, param_name, "Duplicate parameter '%s' when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + continue; /* jump to next parameter */ + } + /* Find the corresponding parameter in function declaration */ if (NULL == fp_iterator.search(param_name)) { - STAGE3_ERROR(0, param_name, param_name, "Invalid parameter '%s' when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); - } else if (NULL == param_value->datatype) { + function_invocation_error = true; + STAGE3_ERROR(0, param_name, param_name, "Invalid parameter '%s' when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + continue; /* jump to next parameter */ + } + + /* check whether direction (IN, OUT, IN_OUT) and assignment types (:= , =>) are compatible !!! */ + /* Obtaining the assignment direction: := (assign_in) or => (assign_out) */ + function_call_param_iterator_c::assign_direction_t call_param_dir = fcp_iterator.get_assign_direction(); + /* Get the parameter direction: IN, OUT, IN_OUT */ + function_param_iterator_c::param_direction_t param_dir = fp_iterator.param_direction(); + if (function_call_param_iterator_c::assign_in == call_param_dir) { + if ((function_param_iterator_c::direction_in != param_dir) && + (function_param_iterator_c::direction_inout != param_dir)) { + function_invocation_error = true; + STAGE3_ERROR(0, param_name, param_name, "Invalid assignment syntax ':=' used for parameter '%s', when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + continue; /* jump to next parameter */ + } + } else if (function_call_param_iterator_c::assign_out == call_param_dir) { + if ((function_param_iterator_c::direction_out != param_dir)) { + function_invocation_error = true; + STAGE3_ERROR(0, param_name, param_name, "Invalid assignment syntax '=>' used for parameter '%s', when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + continue; /* jump to next parameter */ + } + } else ERROR; + + if (NULL == param_value->datatype) { function_invocation_error = true; STAGE3_ERROR(0, param_value, param_value, "Data type incompatibility between parameter '%s' and value being passed, when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + continue; /* jump to next parameter */ } } } @@ -167,6 +190,11 @@ } } + if (NULL == fcall_data.called_function_declaration) { + function_invocation_error = true; + STAGE3_ERROR(0, fcall, fcall, "Unable to resolve which overloaded %s '%s' is being invoked.", POU_str, ((identifier_c *)fcall_data.function_name)->value); + } + if (function_invocation_error) { /* No compatible function exists */ STAGE3_ERROR(2, fcall, fcall, "Invalid parameters when invoking %s '%s'", POU_str, ((identifier_c *)fcall_data.function_name)->value);