diff -r ba80c3ceb6fb -r 2c3c4dc34979 stage3/visit_expression_type.cc --- a/stage3/visit_expression_type.cc Mon Jul 11 09:47:27 2011 +0100 +++ b/stage3/visit_expression_type.cc Fri Jul 29 16:03:28 2011 +0100 @@ -604,7 +604,7 @@ } - +#if 0 #define is_num_type is_ANY_NUM_compatible #define is_integer_type is_ANY_INT_compatible #define is_real_type is_ANY_REAL_compatible @@ -633,7 +633,7 @@ #undef is_nbinary_type #undef is_integer_type #undef is_num_type - +#endif @@ -720,12 +720,20 @@ /* A helper function... */ /* check the semantics of a FB or Function non-formal call */ /* e.g. foo(1, 2, 3, 4); */ -void visit_expression_type_c::check_nonformal_call(symbol_c *f_call, symbol_c *f_decl, bool use_il_defvar) { +/* If error_count pointer is != NULL, we do not really print out the errors, + * but rather only count how many errors were found. + * This is used to support overloaded functions, where we have to check each possible + * function, one at a time, untill we find a function call without any errors. + */ +void visit_expression_type_c::check_nonformal_call(symbol_c *f_call, symbol_c *f_decl, bool use_il_defvar, int *error_count) { symbol_c *call_param_value, *call_param_type, *param_type; identifier_c *param_name; function_param_iterator_c fp_iterator(f_decl); function_call_param_iterator_c fcp_iterator(f_call); - + int extensible_parameter_highest_index = -1; + + /* reset error counter */ + if (error_count != NULL) *error_count = 0; /* if use_il_defvar, then the first parameter for the call comes from the il_default_variable */ if (use_il_defvar) { /* The first parameter of the function corresponds to the il_default_variable_type of the function call */ @@ -740,20 +748,48 @@ } while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0)); /* If the function does not have any parameters (param_name == NULL) * then we cannot compare its type with the il_default_variable_type. + * + * However, I (Mario) think this is invalid syntax, as it seems to me all functions must + * have at least one parameter. + * However, we will make this semantic verification consider it possible, as later + * versions of the standard may change that syntax. + * So, instead of generating a syntax error message, we simply check whether the call + * is passing any more parameters besides the default variable (the il default variable may be ignored + * in this case, and not consider it as being a parameter being passed to the function). + * If it does, then we have found a semantic error, otherwise the function call is + * correct, and we simply return. */ - if(param_name != NULL) { + if(param_name == NULL) { + if (fcp_iterator.next_nf() != NULL) + STAGE3_ERROR(f_call, f_call, "Too many parameters in function/FB call."); + return; + } else { + /* param_name != NULL */ param_type = fp_iterator.param_type(); - if(!is_valid_assignment(param_type, il_default_variable_type)) - STAGE3_ERROR(f_call, f_call, "In function/FB call, first parameter has invalid data type."); + if(!is_valid_assignment(param_type, il_default_variable_type)) { + if (error_count != NULL) (*error_count)++; + else STAGE3_ERROR(f_call, f_call, "In function/FB call, first parameter has invalid data type."); + } + } + + /* the fisrt parameter (il_def_variable) is correct */ + if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) { + extensible_parameter_highest_index = fp_iterator.extensible_param_index(); } } // if (use_il_defvar) + + /* Iterating through the non-formal parameters of the function call */ while((call_param_value = fcp_iterator.next_nf()) != NULL) { /* Obtaining the type of the value being passed in the function call */ call_param_type = base_type((symbol_c*)call_param_value->accept(*this)); if (call_param_type == NULL) { - STAGE3_ERROR(call_param_value, call_param_value, "Could not determine data type of value being passed in function/FB call."); + if (error_count != NULL) (*error_count)++; + /* the following error will usually occur when ST code uses an identifier, that could refer to an enumerated constant, + * but was not actually used as a constant in any definitions of an enumerated data type + */ + else STAGE3_ERROR(call_param_value, call_param_value, "Could not determine data type of value being passed in function/FB call."); continue; } @@ -762,17 +798,43 @@ */ do { param_name = fp_iterator.next(); - /* If there is no parameter declared with that name */ - if(param_name == NULL) {STAGE3_ERROR(f_call, f_call, "Too many parameters in function/FB call."); break;} + /* If there is no other parameter declared, then we are passing too many parameters... */ + if(param_name == NULL) { + if (error_count != NULL) (*error_count)++; + /* Note: We don't want to print out the follwoing error message multiple times, so we return instead of continuing with 'break' */ + else STAGE3_ERROR(f_call, f_call, "Too many parameters in function/FB call."); return; + } } while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0)); - if(param_name != NULL) { - /* Get the parameter type */ - param_type = base_type(fp_iterator.param_type()); - /* If the declared parameter and the parameter from the function call do no have the same type */ - if(!is_valid_assignment(param_type, call_param_type)) STAGE3_ERROR(call_param_value, call_param_value, "Type mismatch in function/FB call parameter."); + /* Get the parameter type */ + param_type = base_type(fp_iterator.param_type()); + /* If the declared parameter and the parameter from the function call do not have the same type */ + if(!is_valid_assignment(param_type, call_param_type)) { + if (error_count != NULL) (*error_count)++; + else STAGE3_ERROR(call_param_value, call_param_value, "Type mismatch in function/FB call parameter."); } - } + + if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) { + extensible_parameter_highest_index = fp_iterator.extensible_param_index(); + } + } + + /* The function call may not have any errors! */ + /* In the case of a call to an extensible function, we store the highest index + * of the extensible parameters this particular call uses, in the symbol_c object + * of the function call itself! + * In calls to non-extensible functions, this value will be set to -1. + * This information is later used in stage4 to correctly generate the + * output code. + */ + int extensible_param_count = -1; + if (extensible_parameter_highest_index >=0) /* if call to extensible function */ + extensible_param_count = 1 + extensible_parameter_highest_index - fp_iterator.first_extensible_param_index(); + il_function_call_c *il_function_call = dynamic_cast(f_call); + function_invocation_c *function_invocation = dynamic_cast(f_call); + if (il_function_call != NULL) il_function_call ->extensible_param_count = extensible_param_count; + else if (function_invocation != NULL) function_invocation->extensible_param_count = extensible_param_count; + // else ERROR; /* this function is also called by Function Blocks, so this is not an error! */ } @@ -814,12 +876,22 @@ /* A helper function... */ /* check the semantics of a FB or Function formal call */ /* e.g. foo(IN1 := 1, OUT1 =>x, EN := true); */ -void visit_expression_type_c::check_formal_call(symbol_c *f_call, symbol_c *f_decl) { +/* If error_count pointer is != NULL, we do not really print out the errors, + * but rather only count how many errors were found. + * This is used to support overloaded functions, where we have to check each possible + * function, one at a time, untill we find a function call without any errors. + */ +void visit_expression_type_c::check_formal_call(symbol_c *f_call, symbol_c *f_decl, int *error_count) { symbol_c *call_param_value, *call_param_type, *call_param_name, *param_type; symbol_c *verify_duplicate_param; identifier_c *param_name; function_param_iterator_c fp_iterator(f_decl); function_call_param_iterator_c fcp_iterator(f_call); + int extensible_parameter_highest_index = -1; + identifier_c *extensible_parameter_name; + + /* reset error counter */ + if (error_count != NULL) *error_count = 0; /* Iterating through the formal parameters of the function call */ while((call_param_name = fcp_iterator.next_f()) != NULL) { @@ -832,13 +904,15 @@ /* Checking if there are duplicated parameter values */ verify_duplicate_param = fcp_iterator.search_f(call_param_name); if(verify_duplicate_param != call_param_value){ - STAGE3_ERROR(call_param_name, verify_duplicate_param, "Duplicated parameter values."); + if (error_count != NULL) (*error_count)++; + else STAGE3_ERROR(call_param_name, verify_duplicate_param, "Duplicated parameter values."); } /* Obtaining the type of the value being passed in the function call */ call_param_type = (symbol_c*)call_param_value->accept(*this); if (call_param_type == NULL) { - STAGE3_ERROR(call_param_name, call_param_value, "Could not determine data type of value being passed in function/FB call."); + if (error_count != NULL) (*error_count)++; + else STAGE3_ERROR(call_param_name, call_param_value, "Could not determine data type of value being passed in function/FB call."); /* The data value being passed is possibly any enumerated type value. * We do not yet handle semantic verification of enumerated types. */ @@ -850,14 +924,58 @@ /* Find the corresponding parameter of the function being called */ param_name = fp_iterator.search(call_param_name); if(param_name == NULL) { - STAGE3_ERROR(call_param_name, call_param_name, "Invalid parameter in function/FB call."); + if (error_count != NULL) (*error_count)++; + else STAGE3_ERROR(call_param_name, call_param_name, "Invalid parameter in function/FB call."); } else { /* Get the parameter type */ param_type = base_type(fp_iterator.param_type()); /* If the declared parameter and the parameter from the function call have the same type */ - if(!is_valid_assignment(param_type, call_param_type)) STAGE3_ERROR(call_param_name, call_param_value, "Type mismatch function/FB call parameter."); + if(!is_valid_assignment(param_type, call_param_type)) { + if (error_count != NULL) (*error_count)++; + else STAGE3_ERROR(call_param_name, call_param_value, "Type mismatch function/FB call parameter."); + } + if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) { + extensible_parameter_highest_index = fp_iterator.extensible_param_index(); + extensible_parameter_name = param_name; + } } } + + /* In the case of a call to an extensible function, we store the highest index + * of the extensible parameters this particular call uses, in the symbol_c object + * of the function call itself! + * In calls to non-extensible functions, this value will be set to -1. + * This information is later used in stage4 to correctly generate the + * output code. + */ + int extensible_param_count = -1; + if (extensible_parameter_highest_index >=0) /* if call to extensible function */ + extensible_param_count = 1 + extensible_parameter_highest_index - fp_iterator.first_extensible_param_index(); + il_formal_funct_call_c *il_formal_funct_call = dynamic_cast(f_call); + function_invocation_c *function_invocation = dynamic_cast(f_call); + if (il_formal_funct_call != NULL) il_formal_funct_call->extensible_param_count = extensible_param_count; + else if (function_invocation != NULL) function_invocation->extensible_param_count = extensible_param_count; +// else ERROR; /* this function is also called by Function Blocks, so this is not an error! */ + + /* We have iterated through all the formal parameters of the function call, + * and everything seems fine. + * If the function being called in an extensible function, we now check + * whether the extensible paramters in the formal invocation do not skip + * any indexes... + * + * f(in1:=0, in2:=0, in4:=0) --> ERROR!! + */ + if (extensible_parameter_highest_index >=0) { /* if call to extensible function */ + for (int i=fp_iterator.first_extensible_param_index(); i < extensible_parameter_highest_index; i++) { + char tmp[256]; + if (snprintf(tmp, 256, "%s%d", extensible_parameter_name->value, i) >= 256) ERROR; + if (fcp_iterator.search_f(tmp) == NULL) { + /* error in invocation of extensible function */ + if (error_count != NULL) (*error_count)++; + else STAGE3_ERROR(f_call, f_call, "Missing extensible parameters in call to extensible function."); + } + } + } } @@ -990,58 +1108,51 @@ if (il_error) return NULL; + symbol_c *return_data_type = NULL; + /* First find the declaration of the function being called! */ - function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name); - - symbol_c *return_data_type = NULL; - - if (f_decl == function_symtable.end_value()) { - function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name); - if (current_function_type == function_none) ERROR; - /* This code is for the functions that the user did not declare and that are - * part of the IL or ST languagem (built-in functions). - * For now we won't do the semantics analysis for that kind of functions. - */ - /* - return_data_type = (symbol_c *)search_expression_type->compute_standard_function_default(NULL, symbol); - if (NULL == return_data_type) ERROR; - - function_call_param_iterator_c fcp_iterator(symbol); - - int nb_param = 0; - if (symbol->il_param_list != NULL) - nb_param += ((list_c *)symbol->il_param_list)->n; - - identifier_c en_param_name("EN");*/ - /* Get the value from EN param */ - /*symbol_c *EN_param_value = fcp_iterator.search(&en_param_name); - if (EN_param_value == NULL) - EN_param_value = (symbol_c*)(new boolean_literal_c((symbol_c*)(new bool_type_name_c()), new boolean_true_c())); - else - nb_param --; - ADD_PARAM_LIST(EN_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_in) - - identifier_c eno_param_name("EN0");*/ - /* Get the value from ENO param */ - /*symbol_c *ENO_param_value = fcp_iterator.search(&eno_param_name); - if (ENO_param_value != NULL) - nb_param --; - ADD_PARAM_LIST(ENO_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_out) + function_symtable_t::iterator lower = function_symtable.lower_bound(symbol->function_name); + function_symtable_t::iterator upper = function_symtable.upper_bound(symbol->function_name); + if (lower == function_symtable.end()) ERROR; + + int error_count = 0; + int *error_count_ptr = NULL; + + function_symtable_t::iterator second = lower; + second++; + if (second != upper) + /* This is a call to an overloaded function... */ + error_count_ptr = &error_count; + + for(; lower != upper; lower++) { + function_declaration_c *f_decl = function_symtable.get_value(lower); - #include "st_code_gen.c" - */ - } else { - /* determine the base data type returned by the function being called... */ - return_data_type = base_type(f_decl->type_name); - /* If the following occurs, then we must have some big bug in the syntax parser (stage 2)... */ - if (NULL == return_data_type) ERROR; - - /* check semantics of data passed in the function call... */ - check_nonformal_call(symbol, f_decl, true); - - /* set the new ddata type of the default variable for the following verifications... */ - il_default_variable_type = return_data_type; - } + check_nonformal_call(symbol, f_decl, true, error_count_ptr); + + if (0 == error_count) { + /* Either: + * (i) we have a call to a non-overloaded function (error_cnt_ptr is NULL!, so error_count won't change!) + * (ii) we have a call to an overloaded function, with no errors! + */ + + /* Store the pointer to the declaration of the function being called. + * This data will be used by stage 4 to call the correct function. + * Mostly needed to disambiguate overloaded functions... + * See comments in absyntax.def for more details + */ + symbol->called_function_declaration = f_decl; + /* determine the base data type returned by the function being called... */ + return_data_type = base_type(f_decl->type_name); + /* If the following occurs, then we must have some big bug in the syntax parser (stage 2)... */ + if (NULL == return_data_type) ERROR; + /* set the new data type of the default variable for the following verifications... */ + il_default_variable_type = return_data_type; + return NULL; + } + } + + /* No compatible function was found for this function call */ + STAGE3_ERROR(symbol, symbol, "Call to an overloaded function with invalid parameter type."); return NULL; } @@ -1161,58 +1272,55 @@ if (il_error) return NULL; - function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name); - symbol_c *return_data_type = NULL; - - if (f_decl == function_symtable.end_value()) { + function_symtable_t::iterator lower = function_symtable.lower_bound(symbol->function_name); + function_symtable_t::iterator upper = function_symtable.upper_bound(symbol->function_name); + + if (lower == function_symtable.end()) { function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name); if (current_function_type == function_none) ERROR; - - /* This code is for the functions that the user did not declare and that are - * part of the IL or ST languagem (built-in functions). - * For now we won't do the semantics analysis for that kind of functions. - */ - #if 0 - return_data_type = (symbol_c *)search_expression_type->compute_standard_function_default(NULL, symbol); - if (NULL == return_data_type) ERROR; - - function_call_param_iterator_c fcp_iterator(symbol); - - int nb_param = 0; - if (symbol->il_param_list != NULL) - nb_param += ((list_c *)symbol->il_param_list)->n; - - identifier_c en_param_name("EN"); - /* Get the value from EN param */ - symbol_c *EN_param_value = fcp_iterator.search(&en_param_name); - if (EN_param_value == NULL) - EN_param_value = (symbol_c*)(new boolean_literal_c((symbol_c*)(new bool_type_name_c()), new boolean_true_c())); - else - nb_param --; - ADD_PARAM_LIST(EN_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_in) - - identifier_c eno_param_name("EN0"); - /* Get the value from ENO param */ - symbol_c *ENO_param_value = fcp_iterator.search(&eno_param_name); - if (ENO_param_value != NULL) - nb_param --; - ADD_PARAM_LIST(ENO_param_value, (symbol_c*)(new bool_type_name_c()), function_param_iterator_c::direction_out) - - #include "st_code_gen.c" - #endif - } else { - /* determine the base data type returned by the function being called... */ - return_data_type = base_type(f_decl->type_name); - /* the following should never occur. If it does, then we have a bug in the syntax parser (stage 2)... */ - if (NULL == return_data_type) ERROR; - + return NULL; + } + + int error_count = 0; + int *error_count_ptr = NULL; + + function_symtable_t::iterator second = lower; + second++; + if (second != upper) + /* This is a call to an overloaded function... */ + error_count_ptr = &error_count; + + for(; lower != upper; lower++) { + function_declaration_c *f_decl = function_symtable.get_value(lower); + /* check semantics of data passed in the function call... */ - check_formal_call(symbol, f_decl); - - /* the data type of the data returned by the function, and stored in the il default variable... */ - il_default_variable_type = return_data_type; - } + check_formal_call(symbol, f_decl, error_count_ptr); + + if (0 == error_count) { + /* Either: + * (i) we have a call to a non-overloaded function (error_cnt_ptr is NULL!, so error_count won't change!) + * (ii) we have a call to an overloaded function, with no errors! + */ + + /* Store the pointer to the declaration of the function being called. + * This data will be used by stage 4 to call the correct function. + * Mostly needed to disambiguate overloaded functions... + * See comments in absyntax.def for more details + */ + symbol->called_function_declaration = f_decl; + /* determine the base data type returned by the function being called... */ + return_data_type = base_type(f_decl->type_name); + /* the following should never occur. If it does, then we have a bug in the syntax parser (stage 2)... */ + if (NULL == return_data_type) ERROR; + /* the data type of the data returned by the function, and stored in the il default variable... */ + il_default_variable_type = return_data_type; + return NULL; + } + } + + /* No compatible function was found for this function call */ + STAGE3_ERROR(symbol, symbol, "Call to an overloaded function with invalid parameter type."); return NULL; } @@ -1961,22 +2069,52 @@ void *visit_expression_type_c::visit(function_invocation_c *symbol) { - function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name); - if (f_decl == function_symtable.end_value()) { - /* TODO: the following code is for standard library functions. We do not yet support this... */ - void *res = compute_standard_function_default(symbol); - if (res != NULL) return res; - ERROR; - } - - /* now check the semantics of the function call... */ - /* If the syntax parser is working correctly, exactly one of the - * following two symbols will be NULL, while the other is != NULL. - */ - if (symbol-> formal_param_list != NULL) check_formal_call (symbol, f_decl); - if (symbol->nonformal_param_list != NULL) check_nonformal_call(symbol, f_decl); - - return base_type(f_decl->type_name); + function_symtable_t::iterator lower = function_symtable.lower_bound(symbol->function_name); + function_symtable_t::iterator upper = function_symtable.upper_bound(symbol->function_name); + if (lower == function_symtable.end()) ERROR; + + function_symtable_t::iterator second = lower; + second++; + if (second == upper) { + /* call to a function that is not overloaded. */ + /* now check the semantics of the function call... */ + /* If the syntax parser is working correctly, exactly one of the + * following two symbols will be NULL, while the other is != NULL. + */ + function_declaration_c *f_decl = function_symtable.get_value(lower); + if (symbol-> formal_param_list != NULL) check_formal_call (symbol, f_decl); + if (symbol->nonformal_param_list != NULL) check_nonformal_call(symbol, f_decl); + /* Store the pointer to the declaration of the function being called. + * This data will be used by stage 4 to call the correct function. + * Mostly needed to disambiguate overloaded functions... + * See comments in absyntax.def for more details + */ + symbol->called_function_declaration = f_decl; + return base_type(f_decl->type_name); + } + + /* This is a call to an overloaded function... */ + if (debug) printf("visit_expression_type_c::visit(function_invocation_c *symbol): FOUND CALL TO OVERLOADED FUNCTION!!\n"); + for(; lower != upper; lower++) { + if (debug) printf("visit_expression_type_c::visit(function_invocation_c *symbol): FOUND CALL TO OVERLOADED FUNCTION!! iterating...\n"); + int error_count = 0; + function_declaration_c *f_decl = function_symtable.get_value(lower); + if (symbol-> formal_param_list != NULL) check_formal_call (symbol, f_decl, &error_count); + if (symbol->nonformal_param_list != NULL) check_nonformal_call(symbol, f_decl, false, &error_count); + if (0 == error_count) { + /* Store the pointer to the declaration of the function being called. + * This data will be used by stage 4 to call the correct function. + * Mostly needed to disambiguate overloaded functions... + * See comments in absyntax.def for more details + */ + symbol->called_function_declaration = f_decl; + return base_type(f_decl->type_name); + } + } + + /* No compatible function was found for this function call */ + STAGE3_ERROR(symbol, symbol, "Call to an overloaded function with invalid parameter type."); + return NULL; } /********************/