# HG changeset patch # User Mario de Sousa # Date 1328900671 0 # Node ID 744b125d911eca3507e38bc9f71961955f8c8f76 # Parent 0e09a8840c92efe9c9f76adc61dec97043128af0 Add support for semantic verification of function calls in IL. diff -r 0e09a8840c92 -r 744b125d911e absyntax/absyntax.cc --- a/absyntax/absyntax.cc Wed Feb 08 18:33:01 2012 +0000 +++ b/absyntax/absyntax.cc Fri Feb 10 19:04:31 2012 +0000 @@ -131,18 +131,27 @@ /* To insert into the begining of list, call with pos=0 */ /* To insert into the end of list, call with pos=list->n */ void list_c::insert_element(symbol_c *elem, int pos) { - int i; if (pos > n) ERROR; /* add new element to end of list. Basically alocate required memory... */ /* will also increment n by 1 ! */ add_element(elem); /* if not inserting into end position, shift all elements up one position, to open up a slot in pos for new element */ - if (pos < (n-1)) for (i = n-2; i >= pos; i--) elements[i+1] = elements[i]; + if (pos < (n-1)) for (int i = n-2; i >= pos; i--) elements[i+1] = elements[i]; elements[pos] = elem; } +/* remove element at position pos. */ +void list_c::remove_element(int pos) { + if (pos > n) ERROR; + + /* Shift all elements down one position, starting at the entry to delete. */ + for (int i = pos; i < n-1; i++) elements[i] = elements[i+1]; + /* corrent the new size, and free unused memory */ + n--; + elements = (symbol_c **)realloc(elements, n * sizeof(symbol_c *)); +} #define SYM_LIST(class_name_c, ...) \ class_name_c::class_name_c( \ diff -r 0e09a8840c92 -r 744b125d911e absyntax/absyntax.def --- a/absyntax/absyntax.def Wed Feb 08 18:33:01 2012 +0000 +++ b/absyntax/absyntax.def Fri Feb 10 19:04:31 2012 +0000 @@ -920,10 +920,10 @@ SYM_REF2(il_simple_operation_c, il_simple_operator, il_operand) /* | function_name [il_operand_list] */ -/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. +/* NOTE: The parameter 'called_function_declaration', 'extensible_param_count' and 'candidate_functions' are used to pass data between the stage 3 and stage 4. * See the comment above function_invocation_c for more details */ -SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;) +SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count; std::vector candidate_functions;) /* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */ @@ -942,10 +942,10 @@ /* | function_name '(' eol_list [il_param_list] ')' */ -/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. - * See the comment above function_invocation_c for more details - */ -SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;) +/* NOTE: The parameter 'called_function_declaration', 'extensible_param_count' and 'candidate_functions' are used to pass data between the stage 3 and stage 4. + * See the comment above function_invocation_c for more details. + */ +SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count; std::vector candidate_functions;) /* | il_operand_list ',' il_operand */ SYM_LIST(il_operand_list_c) diff -r 0e09a8840c92 -r 744b125d911e absyntax/absyntax.hh --- a/absyntax/absyntax.hh Wed Feb 08 18:33:01 2012 +0000 +++ b/absyntax/absyntax.hh Fri Feb 10 19:04:31 2012 +0000 @@ -129,6 +129,8 @@ /* To insert into the begining of list, call with pos=0 */ /* To insert into the end of list, call with pos=list->n */ virtual void insert_element(symbol_c *elem, int pos = 0); + /* remove element at position pos. */ + virtual void remove_element(int pos = 0); }; diff -r 0e09a8840c92 -r 744b125d911e stage3/datatype_functions.hh --- a/stage3/datatype_functions.hh Wed Feb 08 18:33:01 2012 +0000 +++ b/stage3/datatype_functions.hh Fri Feb 10 19:04:31 2012 +0000 @@ -35,6 +35,21 @@ + +typedef struct { + symbol_c *function_name; + symbol_c *nonformal_operand_list; + symbol_c * formal_operand_list; + +//symbol_c &*datatype; +//std::vector &candidate_datatypes; + std::vector &candidate_functions; + symbol_c *&called_function_declaration; + int &extensible_param_count; +} generic_function_call_t; + + + /* A small helper class, to transform elementary data type to string. * this allows us to generate more relevant error messages... */ diff -r 0e09a8840c92 -r 744b125d911e stage3/fill_candidate_datatypes.cc --- a/stage3/fill_candidate_datatypes.cc Wed Feb 08 18:33:01 2012 +0000 +++ b/stage3/fill_candidate_datatypes.cc Fri Feb 10 19:04:31 2012 +0000 @@ -91,6 +91,10 @@ param_type = 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 */ + /* TODO + * call int search_in_datatype_list(symbol_c *datatype, std::vector candidate_datatypes); + * instead of using for loop! + */ for(i = 0; i < call_param_value->candidate_datatypes.size(); i++) { /* If found (correct data type being passed), then stop the search */ if(is_type_equal(param_type, call_param_value->candidate_datatypes[i])) break; @@ -138,6 +142,10 @@ /* Get the parameter type */ param_type = 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 */ + /* TODO + * call int search_in_datatype_list(symbol_c *datatype, std::vector candidate_datatypes); + * instead of using for loop! + */ for (i = 0; i < call_param_types.size(); i++) { /* If found (correct data type being passed), then stop the search */ if(is_type_equal(param_type, call_param_types[i])) break; @@ -153,6 +161,98 @@ +/* Handle a generic function call! + * Assumes that the parameter_list containing the values being passed in this function invocation + * has already had all the candidate_datatype lists filled in! + * + * All parameters being passed to the called function MUST be in the parameter list to which f_call points to! + * This means that, for non formal function calls in IL, de current (default value) must be artificially added to the + * beginning of the parameter list BEFORE calling handle_function_call(). + */ +/* +typedef struct { + symbol_c *function_name, + symbol_c *nonformal_operand_list, + symbol_c * formal_operand_list, + + std::vector &candidate_functions, + symbol_c &*called_function_declaration, + int &extensible_param_count +} generic_function_call_t; +*/ +/* +void narrow_candidate_datatypes_c::narrow_function_invocation(symbol_c *fcall, generic_function_call_t fcall_data) { +void *fill_candidate_datatypes_c::handle_function_call(symbol_c *f_call, symbol_c *function_name, invocation_type_t invocation_type, + std::vector *candidate_datatypes, + std::vector *candidate_functions) { + */ +void fill_candidate_datatypes_c::handle_function_call(symbol_c *fcall, generic_function_call_t fcall_data) { + function_declaration_c *f_decl; + list_c *parameter_list; + list_c *parameter_candidate_datatypes; + symbol_c *returned_parameter_type; + + if (debug) std::cout << "function()\n"; + + function_symtable_t::iterator lower = function_symtable.lower_bound(fcall_data.function_name); + function_symtable_t::iterator upper = function_symtable.upper_bound(fcall_data.function_name); + /* If the name of the function being called is not found in the function symbol table, then this is an invalid call */ + /* Since the lexical parser already checks for this, then if this occurs then we have an internal compiler error. */ + if (lower == function_symtable.end()) ERROR; + + /* Look for all compatible function declarations, and add their return datatypes + * to the candidate_datatype list of this function invocation. + * + * If only one function exists, we add its return datatype to the candidate_datatype list, + * even if the parameters passed to it are invalid. + * This guarantees that the remainder of the expression in which the function call is inserted + * is treated as if the function call returns correctly, and therefore does not generate + * spurious error messages. + * Even if the parameters to the function call are invalid, doing this is still safe, as the + * expressions inside the function call will themselves have erros and will guarantee that + * compilation is aborted in stage3 (in print_datatypes_error_c). + */ + if (function_symtable.multiplicity(fcall_data.function_name) == 1) { + f_decl = function_symtable.get_value(lower); + returned_parameter_type = base_type(f_decl->type_name); + fcall_data.candidate_functions.push_back(f_decl); + fcall-> candidate_datatypes.push_back(returned_parameter_type); + } + for(; lower != upper; lower++) { + bool compatible = false; + + f_decl = function_symtable.get_value(lower); + /* Check if function declaration in symbol_table is compatible with parameters */ + if (NULL != fcall_data.nonformal_operand_list) compatible=match_nonformal_call(fcall, f_decl); + if (NULL != fcall_data. formal_operand_list) compatible= match_formal_call(fcall, f_decl); + if (compatible) { + /* Add the data type returned by the called functions. + * However, only do this if this data type is not already present in the candidate_datatypes list_c + */ + /* TODO + * call int search_in_datatype_list(symbol_c *datatype, std::vector candidate_datatypes); + * instead of using for loop! + */ + unsigned int k; + returned_parameter_type = base_type(f_decl->type_name); + for(k = 0; k < fcall->candidate_datatypes.size(); k++) { + if (is_type_equal(returned_parameter_type, fcall->candidate_datatypes[k])) + break; + } + if (k >= fcall->candidate_datatypes.size()) { + fcall-> candidate_datatypes.push_back(returned_parameter_type); + fcall_data.candidate_functions.push_back(f_decl); + } + } + } + if (debug) std::cout << "end_function() [" << fcall->candidate_datatypes.size() << "] result.\n"; + return; +} + + + + + /* a helper function... */ symbol_c *fill_candidate_datatypes_c::base_type(symbol_c *symbol) { /* NOTE: symbol == NULL is valid. It will occur when, for e.g., an undefined/undeclared symbolic_variable is used @@ -667,15 +767,42 @@ return NULL; } + +/* | function_name [il_operand_list] */ +/* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */ +// SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;) void *fill_candidate_datatypes_c::visit(il_function_call_c *symbol) { -} - -/* MJS: Manuele, could you please not delete the following 2 lines of comments. They help me understand where this class is used - * and when it is created by bison - syntax parse, and how it can show up in the abstract syntax tree. - * - * Actually, it could be helpful if we could have all the similar comments already present in visit_expression_type_c - * in the 3 new classes fill/narrow/print candidate datatype - */ + /* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction) + * In order to be able to handle this without coding special cases, we will simply prepend that symbol + * to the il_operand_list, and remove it later (in the print_datatypes_error_c). + * + * However, if no further paramters are given, then il_operand_list will be NULL, and we will + * need to create a new object to hold the pointer to prev_il_instruction. + * This change will also be undone later in print_datatypes_error_c. + */ + if (NULL == symbol->il_operand_list) symbol->il_operand_list = new il_operand_list_c; + if (NULL == symbol->il_operand_list) ERROR; + + symbol->il_operand_list->accept(*this); + + if (NULL == prev_il_instruction) return NULL; + ((list_c *)symbol->il_operand_list)->insert_element(prev_il_instruction, 0); + + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ symbol->il_operand_list, + /* fcall_param.formal_operand_list = */ NULL, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + handle_function_call(symbol, fcall_param); + + if (debug) std::cout << "il_function_call_c [" << symbol->candidate_datatypes.size() << "] result.\n"; + return NULL; +} + + /* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */ // SYM_REF3(il_expression_c, il_expr_operator, il_operand, simple_instr_list); void *fill_candidate_datatypes_c::visit(il_expression_c *symbol) { @@ -717,8 +844,24 @@ void *fill_candidate_datatypes_c::visit(il_fb_call_c *symbol) { } +/* | function_name '(' eol_list [il_param_list] ')' */ +/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. */ +// SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;) void *fill_candidate_datatypes_c::visit(il_formal_funct_call_c *symbol) { - + symbol->il_param_list->accept(*this); + + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ NULL, + /* fcall_param.formal_operand_list = */ symbol->il_param_list, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + handle_function_call(symbol, fcall_param); + + if (debug) std::cout << "il_formal_funct_call_c [" << symbol->candidate_datatypes.size() << "] result.\n"; + return NULL; } /* @@ -1711,70 +1854,21 @@ void *fill_candidate_datatypes_c::visit(function_invocation_c *symbol) { - function_declaration_c *f_decl; - list_c *parameter_list; - list_c *parameter_candidate_datatypes; - symbol_c *returned_parameter_type; - - if (debug) std::cout << "function()\n"; - - 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 the name of the function being called is not found in the function symbol table, then this is an invalid call */ - /* Since the lexical parser already checks for this, then if this occurs then we have an internal compiler error. */ - if (lower == function_symtable.end()) ERROR; - - if (NULL != symbol->formal_param_list) - parameter_list = (list_c *)symbol->formal_param_list; - else if (NULL != symbol->nonformal_param_list) - parameter_list = (list_c *)symbol->nonformal_param_list; + if (NULL != symbol->formal_param_list) symbol-> formal_param_list->accept(*this); + else if (NULL != symbol->nonformal_param_list) symbol->nonformal_param_list->accept(*this); else ERROR; - - /* Fill in the candidate_datatypes lists of all the expressions used in the function call parameters */ - parameter_list->accept(*this); - - /* Look for all compatible function declarations, and add their return datatypes - * to the candidate_datatype list of this function invocation. - * - * If only one function exists, we add its return datatype to the candidate_datatype list, - * even if the parameters passed to it are invalid. - * This guarantees that the remainder of the expression in which the function call is inserted - * is treated as if the function call returns correctly, and therefore does not generate - * spurious error messages. - * Even if the parameters to the function call are invalid, doing this is still safe, as the - * expressions inside the function call will themselves have erros and will guarantee that - * compilation is aborted in stage3 (in print_datatypes_error_c). - */ - if (function_symtable.multiplicity(symbol->function_name) == 1) { - f_decl = function_symtable.get_value(lower); - returned_parameter_type = base_type(f_decl->type_name); - symbol->candidate_functions.push_back(f_decl); - symbol->candidate_datatypes.push_back(returned_parameter_type); - } - for(; lower != upper; lower++) { - bool compatible = false; - - f_decl = function_symtable.get_value(lower); - /* Check if function declaration in symbol_table is compatible with parameters */ - if (NULL != symbol->nonformal_param_list) compatible=match_nonformal_call(symbol, f_decl); - if (NULL != symbol-> formal_param_list) compatible= match_formal_call(symbol, f_decl); - if (compatible) { - /* Add the data type returned by the called functions. - * However, only do this if this data type is not already present in the candidate_datatypes list_c - */ - unsigned int k; - returned_parameter_type = base_type(f_decl->type_name); - for(k = 0; k < symbol->candidate_datatypes.size(); k++) { - if (is_type_equal(returned_parameter_type, symbol->candidate_datatypes[k])) - break; - } - if (k >= symbol->candidate_datatypes.size()) { - symbol->candidate_datatypes.push_back(returned_parameter_type); - symbol->candidate_functions.push_back(f_decl); - } - } - } - if (debug) std::cout << "end_function() [" << symbol->candidate_datatypes.size() << "] result.\n"; + + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ symbol->nonformal_param_list, + /* fcall_param.formal_operand_list = */ symbol->formal_param_list, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + handle_function_call(symbol, fcall_param); + + if (debug) std::cout << "function_invocation_c [" << symbol->candidate_datatypes.size() << "] result.\n"; return NULL; } diff -r 0e09a8840c92 -r 744b125d911e stage3/fill_candidate_datatypes.hh --- a/stage3/fill_candidate_datatypes.hh Wed Feb 08 18:33:01 2012 +0000 +++ b/stage3/fill_candidate_datatypes.hh Fri Feb 10 19:04:31 2012 +0000 @@ -34,6 +34,7 @@ #include "../absyntax_utils/absyntax_utils.hh" +#include "datatype_functions.hh" class fill_candidate_datatypes_c: public iterator_visitor_c { @@ -80,20 +81,20 @@ symbol_c *il_operand; symbol_c *widening_conversion(symbol_c *left_type, symbol_c *right_type, const struct widen_entry widen_table[]); - public: - fill_candidate_datatypes_c(symbol_c *ignore); - virtual ~fill_candidate_datatypes_c(void); - /* 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); - - void *compute_standard_function_default(function_invocation_c *st_symbol, il_formal_funct_call_c *il_symbol); - void *compute_standard_function_il(il_function_call_c *symbol, symbol_c *param_data_type); + void handle_function_call(symbol_c *fcall, generic_function_call_t fcall_data); /* a helper function... */ symbol_c *base_type(symbol_c *symbol); + + + public: + fill_candidate_datatypes_c(symbol_c *ignore); + virtual ~fill_candidate_datatypes_c(void); + /*********************/ /* B 1.2 - Constants */ diff -r 0e09a8840c92 -r 744b125d911e stage3/narrow_candidate_datatypes.cc --- a/stage3/narrow_candidate_datatypes.cc Wed Feb 08 18:33:01 2012 +0000 +++ b/stage3/narrow_candidate_datatypes.cc Fri Feb 10 19:04:31 2012 +0000 @@ -182,6 +182,59 @@ } +/* +typedef struct { + symbol_c *function_name, + symbol_c *nonformal_operand_list, + symbol_c * formal_operand_list, + + std::vector &candidate_functions, + symbol_c &*called_function_declaration, + int &extensible_param_count +} generic_function_call_t; +*/ +void narrow_candidate_datatypes_c::narrow_function_invocation(symbol_c *fcall, generic_function_call_t fcall_data) { + /* set the called_function_declaration. */ + fcall_data.called_function_declaration = NULL; + + /* set the called_function_declaration taking into account the datatype that we need to return */ + for(unsigned int i = 0; i < fcall->candidate_datatypes.size(); i++) { + if (is_type_equal(fcall->candidate_datatypes[i], fcall->datatype)) { + fcall_data.called_function_declaration = fcall_data.candidate_functions[i]; + break; + } + } + + /* NOTE: If we can't figure out the declaration of the function being called, this is not + * necessarily an internal compiler error. It could be because the symbol->datatype is NULL + * (because the ST code being analysed has an error _before_ this function invocation). + * However, we don't just give, up, we carry on recursivly analysing the code, so as to be + * able to print out any error messages related to the parameters being passed in this function + * invocation. + */ + /* if (NULL == symbol->called_function_declaration) ERROR; */ + if (fcall->candidate_datatypes.size() == 1) { + /* If only one function declaration, then we use that (even if symbol->datatypes == NULL) + * so we can check for errors in the expressions used to pass parameters in this + * function invocation. + */ + fcall_data.called_function_declaration = fcall_data.candidate_functions[0]; + } + + /* If an overloaded function is being invoked, and we cannot determine which version to use, + * then we can not meaningfully verify the expressions used inside that function invocation. + * We simply give up! + */ + if (NULL == fcall_data.called_function_declaration) + return; + + if (NULL != fcall_data.nonformal_operand_list) narrow_nonformal_call(fcall, fcall_data.called_function_declaration, &(fcall_data.extensible_param_count)); + if (NULL != fcall_data. formal_operand_list) narrow_formal_call(fcall, fcall_data.called_function_declaration, &(fcall_data.extensible_param_count)); + + return; +} + + /* a helper function... */ symbol_c *narrow_candidate_datatypes_c::base_type(symbol_c *symbol) { @@ -324,7 +377,27 @@ return NULL; } +/* | function_name [il_operand_list] */ +/* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */ +// SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;) void *narrow_candidate_datatypes_c::visit(il_function_call_c *symbol) { + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ symbol->il_operand_list, + /* fcall_param.formal_operand_list = */ NULL, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + + /* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction) + * In order to be able to handle this without coding special cases, we simply prepend that symbol + * to the il_operand_list (done in fill_candidate_datatypes_c), and remove it later (in the print_datatypes_error_c). + * + * Since this class is executed after fill_candidate_datatypes_c, and before print_datatypes_error_c, + * the following code is actually correct! + */ + narrow_function_invocation(symbol, fcall_param); return NULL; } @@ -345,7 +418,20 @@ return NULL; } +/* | function_name '(' eol_list [il_param_list] ')' */ +/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. */ +// SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;) void *narrow_candidate_datatypes_c::visit(il_formal_funct_call_c *symbol) { + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ NULL, + /* fcall_param.formal_operand_list = */ symbol->il_param_list, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + + narrow_function_invocation(symbol, fcall_param); return NULL; } @@ -1020,47 +1106,22 @@ } + +/* NOTE: The parameter 'called_function_declaration', 'extensible_param_count' and 'candidate_functions' are used to pass data between the stage 3 and stage 4. */ +/* formal_param_list -> may be NULL ! */ +/* nonformal_param_list -> may be NULL ! */ +// SYM_REF3(function_invocation_c, function_name, formal_param_list, nonformal_param_list, symbol_c *called_function_declaration; int extensible_param_count; std::vector candidate_functions;) void *narrow_candidate_datatypes_c::visit(function_invocation_c *symbol) { - int ext_parm_count; - - /* set the called_function_declaration. */ - symbol->called_function_declaration = NULL; - - /* set the called_function_declaration taking into account the datatype that we need to return */ - for(unsigned int i = 0; i < symbol->candidate_datatypes.size(); i++) { - if (is_type_equal(symbol->candidate_datatypes[i], symbol->datatype)) { - symbol->called_function_declaration = symbol->candidate_functions[i]; - break; - } - } - - /* NOTE: If we can't figure out the declaration of the function being called, this is not - * necessarily an internal compiler error. It could be because the symbol->datatype is NULL - * (because the ST code being analysed has an error _before_ this function invocation). - * However, we don't just give, up, we carry on recursivly analysing the code, so as to be - * able to print out any error messages related to the parameters being passed in this function - * invocation. - */ - /* if (NULL == symbol->called_function_declaration) ERROR; */ - if (symbol->candidate_datatypes.size() == 1) { - /* If only one function declaration, then we use that (even if symbol->datatypes == NULL) - * so we can check for errors in the expressions used to pass parameters in this - * function invocation. - */ - symbol->called_function_declaration = symbol->candidate_functions[0]; - } - - /* If an overloaded function is being invoked, and we cannot determine which version to use, - * then we can not meaningfully verify the expressions used inside that function invocation. - * We simply give up! - */ - if (NULL == symbol->called_function_declaration) - return NULL; - - if (NULL != symbol->nonformal_param_list) narrow_nonformal_call(symbol, symbol->called_function_declaration, &ext_parm_count); - if (NULL != symbol-> formal_param_list) narrow_formal_call(symbol, symbol->called_function_declaration, &ext_parm_count); - symbol->extensible_param_count = ext_parm_count; - + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ symbol->nonformal_param_list, + /* fcall_param.formal_operand_list = */ symbol->formal_param_list, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + + narrow_function_invocation(symbol, fcall_param); return NULL; } diff -r 0e09a8840c92 -r 744b125d911e stage3/narrow_candidate_datatypes.hh --- a/stage3/narrow_candidate_datatypes.hh Wed Feb 08 18:33:01 2012 +0000 +++ b/stage3/narrow_candidate_datatypes.hh Fri Feb 10 19:04:31 2012 +0000 @@ -34,6 +34,7 @@ #include "../absyntax_utils/absyntax_utils.hh" +#include "datatype_functions.hh" class narrow_candidate_datatypes_c: public iterator_visitor_c { @@ -47,11 +48,13 @@ bool is_widening_compatible(symbol_c *left_type, symbol_c *right_type, symbol_c *result_type, const struct widen_entry widen_table[]); + void narrow_function_invocation(symbol_c *f_call, generic_function_call_t fcall_data); + void narrow_nonformal_call(symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count = NULL); + void narrow_formal_call(symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count = NULL); + public: narrow_candidate_datatypes_c(symbol_c *ignore); virtual ~narrow_candidate_datatypes_c(void); - void narrow_nonformal_call(symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count = NULL); - void narrow_formal_call(symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count = NULL); symbol_c *base_type(symbol_c *symbol); diff -r 0e09a8840c92 -r 744b125d911e stage3/print_datatypes_error.cc --- a/stage3/print_datatypes_error.cc Wed Feb 08 18:33:01 2012 +0000 +++ b/stage3/print_datatypes_error.cc Fri Feb 10 19:04:31 2012 +0000 @@ -90,6 +90,76 @@ return (symbol_c *)symbol->accept(search_base_type); } + + + +/* +typedef struct { + symbol_c *function_name, + symbol_c *nonformal_operand_list, + symbol_c * formal_operand_list, + + std::vector &candidate_functions, + symbol_c &*called_function_declaration, + int &extensible_param_count +} generic_function_call_t; +*/ +void print_datatypes_error_c::handle_function_invocation(symbol_c *fcall, generic_function_call_t fcall_data) { + symbol_c *param_value, *param_name; + function_call_param_iterator_c fcp_iterator(fcall); + bool function_invocation_error = false; + + if ((NULL != fcall_data.formal_operand_list) && (NULL != fcall_data.nonformal_operand_list)) + ERROR; + + symbol_c *f_decl = fcall_data.called_function_declaration; + if (NULL == f_decl) { + STAGE3_ERROR(0, fcall, fcall, "Unable to resolve which overloaded function '%s' is being invoked.", ((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; + f_decl = function_symtable.get_value(lower); + } + + if (NULL != fcall_data.formal_operand_list) { + fcall_data.formal_operand_list->accept(*this); + if (NULL != f_decl) { + function_param_iterator_c fp_iterator(f_decl); + while ((param_name = fcp_iterator.next_f()) != NULL) { + param_value = fcp_iterator.get_current_value(); + /* Find the corresponding parameter in function declaration */ + if (NULL == fp_iterator.search(param_name)) { + STAGE3_ERROR(0, fcall, fcall, "Invalid parameter '%s' when invoking function '%s'", ((identifier_c *)param_name)->value, ((identifier_c *)fcall_data.function_name)->value); + } else if (NULL == param_value->datatype) { + function_invocation_error = true; + STAGE3_ERROR(0, fcall, fcall, "Data type incompatibility between parameter '%s' and value being passed, when invoking function '%s'", ((identifier_c *)param_name)->value, ((identifier_c *)fcall_data.function_name)->value); + } + } + } + } + if (NULL != fcall_data.nonformal_operand_list) { + fcall_data.nonformal_operand_list->accept(*this); + if (f_decl) + for (int i = 1; (param_value = fcp_iterator.next_nf()) != NULL; i++) { + if (NULL == param_value->datatype) { + function_invocation_error = true; + STAGE3_ERROR(0, fcall, fcall, "Data type incompatibility for value passed in position %d when invoking function '%s'", i, ((identifier_c *)fcall_data.function_name)->value); + } + } + } + + if (function_invocation_error) { + /* No compatible function exists */ + STAGE3_ERROR(2, fcall, fcall, "Invalid parameters when invoking function '%s'", ((identifier_c *)fcall_data.function_name)->value); + } + + return; +} + + + + + /*********************/ /* B 1.2 - Constants */ /*********************/ @@ -444,7 +514,33 @@ return NULL; } +/* | function_name [il_operand_list] */ +/* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */ +// SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;) void *print_datatypes_error_c::visit(il_function_call_c *symbol) { + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ symbol->il_operand_list, + /* fcall_param.formal_operand_list = */ NULL, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + + handle_function_invocation(symbol, fcall_param); + + /* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction) + * In order to be able to handle this without coding special cases, we will simply prepend that symbol + * to the il_operand_list. This is done in fill_candidate_datatypes_c. + * We now undo those changes! + */ + ((list_c *)symbol->il_operand_list)->remove_element(0); + if (((list_c *)symbol->il_operand_list)->n == 0) { + /* if the list becomes empty, then that means that it did not exist before we made these changes, so we delete it! */ + delete symbol->il_operand_list; + symbol->il_operand_list = NULL; + } + return NULL; } @@ -456,7 +552,20 @@ return NULL; } +/* | function_name '(' eol_list [il_param_list] ')' */ +/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. */ +// SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;) void *print_datatypes_error_c::visit(il_formal_funct_call_c *symbol) { + generic_function_call_t fcall_param = { + /* fcall_param.function_name = */ symbol->function_name, + /* fcall_param.nonformal_operand_list = */ NULL, + /* fcall_param.formal_operand_list = */ symbol->il_param_list, + /* fcall_param.candidate_functions = */ symbol->candidate_functions, + /* fcall_param.called_function_declaration = */ symbol->called_function_declaration, + /* fcall_param.extensible_param_count = */ symbol->extensible_param_count + }; + + handle_function_invocation(symbol, fcall_param); return NULL; } diff -r 0e09a8840c92 -r 744b125d911e stage3/print_datatypes_error.hh --- a/stage3/print_datatypes_error.hh Wed Feb 08 18:33:01 2012 +0000 +++ b/stage3/print_datatypes_error.hh Fri Feb 10 19:04:31 2012 +0000 @@ -34,6 +34,8 @@ #include "../absyntax_utils/absyntax_utils.hh" +#include "datatype_functions.hh" + class print_datatypes_error_c: public iterator_visitor_c { @@ -78,14 +80,15 @@ symbol_c *il_operand_type; symbol_c *il_operand; + /* some helper functions... */ + symbol_c *base_type(symbol_c *symbol); + void handle_function_invocation(symbol_c *fcall, generic_function_call_t fcall_data); public: print_datatypes_error_c(symbol_c *ignore); virtual ~print_datatypes_error_c(void); int get_error_found(); - /* a helper function... */ - symbol_c *base_type(symbol_c *symbol); /*********************/ /* B 1.2 - Constants */