# HG changeset patch # User Mario de Sousa # Date 1329598981 0 # Node ID 1bd18fc0691123c776116c868c985f55252a0189 # Parent aad0f3e5df33696db3de0bae71c6ef70f6a82836 Add support for semantic verification for implict FB calls in IL (e.g. PV ton_var) diff -r aad0f3e5df33 -r 1bd18fc06911 absyntax_utils/function_param_iterator.cc --- a/absyntax_utils/function_param_iterator.cc Fri Feb 17 19:47:58 2012 +0000 +++ b/absyntax_utils/function_param_iterator.cc Sat Feb 18 21:03:01 2012 +0000 @@ -290,6 +290,13 @@ return res_param_name; } +identifier_c *function_param_iterator_c::search(const char *param_name) { + identifier_c param_name_id(param_name); + return search(¶m_name_id); +} + + + /* Returns the currently referenced parameter's default value, * or NULL if none is specified in the function declrataion itself. */ diff -r aad0f3e5df33 -r 1bd18fc06911 absyntax_utils/function_param_iterator.hh --- a/absyntax_utils/function_param_iterator.hh Fri Feb 17 19:47:58 2012 +0000 +++ b/absyntax_utils/function_param_iterator.hh Sat Feb 18 21:03:01 2012 +0000 @@ -146,6 +146,7 @@ * of the found parameter. */ identifier_c *search(symbol_c *param_name); + identifier_c *search(const char *param_name); /* Returns the currently referenced parameter's default value, * or NULL if none is specified in the function declrataion itself. diff -r aad0f3e5df33 -r 1bd18fc06911 stage3/fill_candidate_datatypes.cc --- a/stage3/fill_candidate_datatypes.cc Fri Feb 17 19:47:58 2012 +0000 +++ b/stage3/fill_candidate_datatypes.cc Sat Feb 18 21:03:01 2012 +0000 @@ -118,7 +118,7 @@ /* 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... */ @@ -238,13 +238,17 @@ /* handle implicit FB call in IL. - * e.g. CLK ton_car + * 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! @@ -260,6 +264,13 @@ */ 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; + } identifier_c variable_name(param_name); // SYM_REF1(il_assign_operator_c, variable_name) @@ -785,14 +796,17 @@ // SYM_REF2(il_instruction_c, label, il_instruction) // void *visit(instruction_list_c *symbol); void *fill_candidate_datatypes_c::visit(il_instruction_c *symbol) { - if (NULL == symbol->il_instruction) - return NULL; - - prev_il_instruction = symbol->prev_il_instruction; - symbol->il_instruction->accept(*this); - /* This object has (inherits) the same candidate datatypes as the il_instruction */ - copy_candidate_datatype_list(symbol->il_instruction /*from*/, symbol /*to*/); - prev_il_instruction = NULL; + if (NULL == symbol->il_instruction) { + /* This object has (inherits) the same candidate datatypes as the prev_il_instruction */ + copy_candidate_datatype_list(symbol->prev_il_instruction /*from*/, symbol /*to*/); + } else { + prev_il_instruction = symbol->prev_il_instruction; + symbol->il_instruction->accept(*this); + prev_il_instruction = NULL; + + /* This object has (inherits) the same candidate datatypes as the il_instruction */ + copy_candidate_datatype_list(symbol->il_instruction /*from*/, symbol /*to*/); + } return NULL; } diff -r aad0f3e5df33 -r 1bd18fc06911 stage3/flow_control_analysis.cc --- a/stage3/flow_control_analysis.cc Fri Feb 17 19:47:58 2012 +0000 +++ b/stage3/flow_control_analysis.cc Sat Feb 18 21:03:01 2012 +0000 @@ -112,8 +112,9 @@ /*| instruction_list il_instruction */ // SYM_LIST(instruction_list_c) void *flow_control_analysis_c::visit(instruction_list_c *symbol) { - for(int i = 1; i < symbol->n; i++) { - prev_il_instruction = symbol->elements[i-1]; + for(int i = 0; i < symbol->n; i++) { + prev_il_instruction = NULL; + if (i > 0) prev_il_instruction = symbol->elements[i-1]; symbol->elements[i]->accept(*this); } return NULL; diff -r aad0f3e5df33 -r 1bd18fc06911 stage3/narrow_candidate_datatypes.cc --- a/stage3/narrow_candidate_datatypes.cc Fri Feb 17 19:47:58 2012 +0000 +++ b/stage3/narrow_candidate_datatypes.cc Sat Feb 18 21:03:01 2012 +0000 @@ -254,6 +254,54 @@ + +/* narrow 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 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; + 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; + } + + 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, prev_il_instruction/*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); + + /* 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 + * be that IL instruction that will be required to produce the desired dtataype. + * + * 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*/); + il_fb_call.datatype = il_instruction->datatype; + il_fb_call.accept(*this); + il_instruction->datatype = il_fb_call.datatype; +} + + /* a helper function... */ symbol_c *narrow_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 @@ -404,13 +452,16 @@ // SYM_REF2(il_instruction_c, label, il_instruction) // void *visit(instruction_list_c *symbol); void *narrow_candidate_datatypes_c::visit(il_instruction_c *symbol) { - if (NULL == symbol->il_instruction) - return NULL; - - prev_il_instruction = symbol->prev_il_instruction; - /* Tell the il_instruction the datatype that it must generate - this was chosen by the next il_instruction (we iterate backwards!) */ - symbol->il_instruction->datatype = symbol->datatype; - symbol->il_instruction->accept(*this); + if (NULL == symbol->il_instruction) { + /* this empty/null il_instruction cannot generate the desired datatype. We pass on the request to the previous il instruction. */ + if (NULL != symbol->prev_il_instruction) + symbol->prev_il_instruction->datatype = symbol->datatype; + } else { + prev_il_instruction = symbol->prev_il_instruction; + /* Tell the il_instruction the datatype that it must generate - this was chosen by the next il_instruction (remember: we are iterating backwards!) */ + symbol->il_instruction->datatype = symbol->datatype; + symbol->il_instruction->accept(*this); + } return NULL; } @@ -505,6 +556,26 @@ /* 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) { + /* set the desired datatype of the previous il instruction */ + /* NOTE 1: + * 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 + * be that IL instruction that will be required to produce the desired dtataype. + * NOTE 2: + * Copying the required datatype must be done before calling narrow_[non]formal_call(). + * Note that this visit(il_fb_call_c *) method will be called from narrow_implicit_il_fb_call(). + * This means that we must also be able to handle implicit IL FB calls (e.g. CU counter_var) + * correctly in this visitor class. + * When handling these implicit IL calls, the parameter_value being passed to the FB parameter + * (in the previous example, the 'CU' parameter) is actually the prev_il_instruction. + * In this case, the prev_il_instruction->datatype will be set by the arrow_[non]formal_call(), + * using the prama_value pointer to this same object. + * If we were to have the following line of code after calling arrow_[non]formal_call(), + * we would then be overwriting the datatype with the wrong value! + */ + prev_il_instruction->datatype = symbol->datatype; + /* 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. @@ -627,52 +698,76 @@ return NULL; } -void *narrow_candidate_datatypes_c::visit(S_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(R_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(S1_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(R1_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(S_operator_c *symbol) { + /* TODO: what if this is a FB call? */ + return handle_il_instruction(symbol); +} +void *narrow_candidate_datatypes_c::visit(R_operator_c *symbol) { + /* TODO: what if this is a FB call? */ + return handle_il_instruction(symbol); +} + + +void *narrow_candidate_datatypes_c::visit(S1_operator_c *symbol) { + narrow_implicit_il_fb_call(symbol, "S1", symbol->called_fb_declaration); + return NULL; +} + +void *narrow_candidate_datatypes_c::visit(R1_operator_c *symbol) { + narrow_implicit_il_fb_call(symbol, "R1", symbol->called_fb_declaration); + return NULL; +} void *narrow_candidate_datatypes_c::visit(CLK_operator_c *symbol) { + narrow_implicit_il_fb_call(symbol, "CLK", symbol->called_fb_declaration); return NULL; } void *narrow_candidate_datatypes_c::visit(CU_operator_c *symbol) { + narrow_implicit_il_fb_call(symbol, "CU", symbol->called_fb_declaration); return NULL; } void *narrow_candidate_datatypes_c::visit(CD_operator_c *symbol) { + narrow_implicit_il_fb_call(symbol, "CD", symbol->called_fb_declaration); return NULL; } void *narrow_candidate_datatypes_c::visit(PV_operator_c *symbol) { + narrow_implicit_il_fb_call(symbol, "PV", symbol->called_fb_declaration); return NULL; } void *narrow_candidate_datatypes_c::visit(IN_operator_c *symbol) { + narrow_implicit_il_fb_call(symbol, "IN", symbol->called_fb_declaration); return NULL; } void *narrow_candidate_datatypes_c::visit(PT_operator_c *symbol) { - return NULL; -} - -void *narrow_candidate_datatypes_c::visit(AND_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(OR_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(XOR_operator_c *symbol) {return handle_il_instruction(symbol);} + narrow_implicit_il_fb_call(symbol, "PT", symbol->called_fb_declaration); + return NULL; +} + + + +void *narrow_candidate_datatypes_c::visit(AND_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(OR_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(XOR_operator_c *symbol) {return handle_il_instruction(symbol);} void *narrow_candidate_datatypes_c::visit(ANDN_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(ORN_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(ORN_operator_c *symbol) {return handle_il_instruction(symbol);} void *narrow_candidate_datatypes_c::visit(XORN_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(ADD_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(SUB_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(MUL_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(DIV_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(MOD_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(GT_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(GE_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(EQ_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(LT_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(LE_operator_c *symbol) {return handle_il_instruction(symbol);} -void *narrow_candidate_datatypes_c::visit(NE_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(ADD_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(SUB_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(MUL_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(DIV_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(MOD_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(GT_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(GE_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(EQ_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(LT_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(LE_operator_c *symbol) {return handle_il_instruction(symbol);} +void *narrow_candidate_datatypes_c::visit(NE_operator_c *symbol) {return handle_il_instruction(symbol);} + void *narrow_candidate_datatypes_c::visit(CAL_operator_c *symbol) { return NULL; diff -r aad0f3e5df33 -r 1bd18fc06911 stage3/narrow_candidate_datatypes.hh --- a/stage3/narrow_candidate_datatypes.hh Fri Feb 17 19:47:58 2012 +0000 +++ b/stage3/narrow_candidate_datatypes.hh Sat Feb 18 21:03:01 2012 +0000 @@ -49,7 +49,7 @@ 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); - + 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); public: diff -r aad0f3e5df33 -r 1bd18fc06911 stage3/print_datatypes_error.cc --- a/stage3/print_datatypes_error.cc Fri Feb 17 19:47:58 2012 +0000 +++ b/stage3/print_datatypes_error.cc Sat Feb 18 21:03:01 2012 +0000 @@ -136,6 +136,15 @@ 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(); /* Find the corresponding parameter in function declaration */ if (NULL == fp_iterator.search(param_name)) { @@ -166,8 +175,33 @@ 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; + } + 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); + 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!! */ + 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); + return; + } + + return; +} /*********************/ @@ -432,7 +466,7 @@ */ void *print_datatypes_error_c::visit(structured_variable_c *symbol) { if (symbol->candidate_datatypes.size() == 0) - STAGE3_ERROR(0, symbol, symbol, "Structure variable not declared in this scope."); + STAGE3_ERROR(0, symbol, symbol, "Undeclared structured/FB variable."); return NULL; } @@ -538,11 +572,16 @@ /* fcall_param.extensible_param_count = */ symbol->extensible_param_count }; +/* TODO: check what error message (if any) the compiler will give out if this function invocation + * is not preceded by a LD operator (or another equivalent operator or list of operators). + * I.e. if it is preceded by an operator or operator list that will set the 'current value'. + * I.e. if the prev_il_operand == NULL; + */ 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. + * In order to be able to handle this without coding special cases, we simply prepend that symbol + * to the il_operand_list. This was done in fill_candidate_datatypes_c. * We now undo those changes! */ ((list_c *)symbol->il_operand_list)->remove_element(0); @@ -662,6 +701,7 @@ } void *print_datatypes_error_c::visit(S_operator_c *symbol) { + /* TODO: what if this is a FB call ?? */ il_operand->accept(*this); if ((symbol->candidate_datatypes.size() == 0) && (il_operand->candidate_datatypes.size() > 0)) @@ -671,6 +711,7 @@ } void *print_datatypes_error_c::visit(R_operator_c *symbol) { + /* TODO: what if this is a FB call ?? */ il_operand->accept(*this); if ((symbol->candidate_datatypes.size() == 0) && (il_operand->candidate_datatypes.size() > 0)) @@ -680,50 +721,42 @@ } void *print_datatypes_error_c::visit(S1_operator_c *symbol) { - il_operand->accept(*this); - if ((symbol->candidate_datatypes.size() == 0) && - (il_operand->candidate_datatypes.size() > 0)) - STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'S1' operator."); - prev_il_instruction = symbol; + handle_implicit_il_fb_invocation(symbol, "S1", symbol->called_fb_declaration); return NULL; } void *print_datatypes_error_c::visit(R1_operator_c *symbol) { - il_operand->accept(*this); - if ((symbol->candidate_datatypes.size() == 0) && - (il_operand->candidate_datatypes.size() > 0)) - STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'R1' operator."); - prev_il_instruction = symbol; + handle_implicit_il_fb_invocation(symbol, "R1", symbol->called_fb_declaration); return NULL; } void *print_datatypes_error_c::visit(CLK_operator_c *symbol) { - prev_il_instruction = symbol; + handle_implicit_il_fb_invocation(symbol, "CLK", symbol->called_fb_declaration); return NULL; } void *print_datatypes_error_c::visit(CU_operator_c *symbol) { - prev_il_instruction = symbol; + handle_implicit_il_fb_invocation(symbol, "CU", symbol->called_fb_declaration); return NULL; } void *print_datatypes_error_c::visit(CD_operator_c *symbol) { - prev_il_instruction = symbol; + handle_implicit_il_fb_invocation(symbol, "CD", symbol->called_fb_declaration); return NULL; } void *print_datatypes_error_c::visit(PV_operator_c *symbol) { - prev_il_instruction = symbol; + handle_implicit_il_fb_invocation(symbol, "PV", symbol->called_fb_declaration); return NULL; } void *print_datatypes_error_c::visit(IN_operator_c *symbol) { - prev_il_instruction = symbol; + handle_implicit_il_fb_invocation(symbol, "IN", symbol->called_fb_declaration); return NULL; } void *print_datatypes_error_c::visit(PT_operator_c *symbol) { - prev_il_instruction = symbol; + handle_implicit_il_fb_invocation(symbol, "PT", symbol->called_fb_declaration); return NULL; } diff -r aad0f3e5df33 -r 1bd18fc06911 stage3/print_datatypes_error.hh --- a/stage3/print_datatypes_error.hh Fri Feb 17 19:47:58 2012 +0000 +++ b/stage3/print_datatypes_error.hh Sat Feb 18 21:03:01 2012 +0000 @@ -84,6 +84,7 @@ /* some helper functions... */ 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); public: print_datatypes_error_c(symbol_c *ignore);