# HG changeset patch # User laurent # Date 1310502028 -7200 # Node ID 9a2262fb79940ed238f4430e5f21650cd6c55d45 # Parent 229eb3e29216fa50a2f92d702de47156f12d7d7b Fix bug with inline function call in POU programmed in IL diff -r 229eb3e29216 -r 9a2262fb7994 stage4/generate_c/generate_c.cc --- a/stage4/generate_c/generate_c.cc Fri Jul 08 11:06:27 2011 +0200 +++ b/stage4/generate_c/generate_c.cc Tue Jul 12 22:20:28 2011 +0200 @@ -728,7 +728,7 @@ /* (A.6) Function Block inline function declaration for function invocation */ inlinedecl = new generate_c_inlinefcall_c(&s4o, symbol->fblock_name, symbol, FB_FUNCTION_PARAM"->"); - inlinedecl->print(symbol->fblock_body); + symbol->fblock_body->accept(*inlinedecl); delete inlinedecl; /* (B) Constructor */ @@ -918,7 +918,7 @@ /* (A.6) Function Block inline function declaration for function invocation */ inlinedecl = new generate_c_inlinefcall_c(&s4o, symbol->program_type_name, symbol, FB_FUNCTION_PARAM"->"); - inlinedecl->print(symbol->function_block_body); + symbol->function_block_body->accept(*inlinedecl); delete inlinedecl; /* (B) Constructor */ diff -r 229eb3e29216 -r 9a2262fb7994 stage4/generate_c/generate_c_inlinefcall.cc --- a/stage4/generate_c/generate_c_inlinefcall.cc Fri Jul 08 11:06:27 2011 +0200 +++ b/stage4/generate_c/generate_c_inlinefcall.cc Tue Jul 12 22:20:28 2011 +0200 @@ -37,13 +37,64 @@ private: + /* The initial value that should be given to the IL default variable + * imediately after a parenthesis is opened. + * This variable is only used to pass data from the + * il_expression_c visitor to the simple_instr_list_c visitor. + * + * e.g.: + * LD var1 + * AND ( var2 + * OR var3 + * ) + * + * In the above code sample, the line 'AND ( var2' constitutes + * an il_expression_c, where var2 should be loaded into the + * il default variable before continuing with the expression + * inside the parenthesis. + * Unfortunately, only the simple_instr_list_c may do the + * initial laoding of the var2 bariable following the parenthesis, + * so the il_expression_c visitor will have to pass 'var2' as a + * parameter to the simple_instr_list_c visitor. + * Ergo, the existance of the following parameter...! + */ + symbol_c *il_default_variable_init_value; + + /* Operand to the IL operation currently being processed... */ + /* These variables are used to pass data from the + * il_simple_operation_c and il_expression_c visitors + * to the il operator visitors (i.e. LD_operator_c, + * LDN_operator_c, ST_operator_c, STN_operator_c, ...) + */ + symbol_c *current_operand; + symbol_c *current_operand_type; + + /* The result of the comparison IL operations (GT, EQ, LT, ...) + * is a boolean variable. + * This class keeps track of the current data type stored in the + * il default variable. This is usually done by keeping a reference + * to the data type of the last operand. Nevertheless, in the case of + * the comparison IL operators, the data type of the result (a boolean) + * is not the data type of the operand. We therefore need an object + * of the boolean data type to keep as a reference of the current + * data type. + * The following object is it... + */ + bool_type_name_c bool_type; + lint_type_name_c lint_type; + lword_type_name_c lword_type; + lreal_type_name_c lreal_type; + /* The name of the IL default variable... */ #define IL_DEFVAR VAR_LEADER "IL_DEFVAR" + /* The name of the variable used to pass the result of a * parenthesised instruction list to the immediately preceding * scope ... */ - il_default_variable_c default_variable_name; + #define IL_DEFVAR_BACK VAR_LEADER "IL_DEFVAR_BACK" + il_default_variable_c default_variable_name; + il_default_variable_c default_variable_back_name; symbol_c* current_array_type; @@ -61,7 +112,8 @@ public: generate_c_inlinefcall_c(stage4out_c *s4o_ptr, symbol_c *name, symbol_c *scope, const char *variable_prefix = NULL) : generate_c_typedecl_c(s4o_ptr), - default_variable_name(IL_DEFVAR, NULL) + default_variable_name(IL_DEFVAR, NULL), + default_variable_back_name(IL_DEFVAR_BACK, NULL) { search_expression_type = new search_expression_type_c(scope); search_varfb_instance_type = new search_varfb_instance_type_c(scope); @@ -192,6 +244,49 @@ private: + /* A helper function... */ + void *CMP_operator_result_type() { + /* the data type resulting from this operation... */ + this->default_variable_name.current_type = &(this->bool_type); + return NULL; + } + + /* A helper function... */ + void *BYTE_operator_result_type(void) { + if (search_expression_type->is_literal_integer_type(this->default_variable_name.current_type)) { + if (search_expression_type->is_literal_integer_type(this->current_operand_type)) + this->default_variable_name.current_type = &(this->lword_type); + else + this->default_variable_name.current_type = this->current_operand_type; + } + else if (search_expression_type->is_literal_integer_type(this->current_operand_type)) + this->current_operand_type = this->default_variable_name.current_type; + return NULL; + } + + /* A helper function... */ + void *NUM_operator_result_type(void) { + if (search_expression_type->is_literal_real_type(this->default_variable_name.current_type)) { + if (search_expression_type->is_literal_integer_type(this->current_operand_type) || + search_expression_type->is_literal_real_type(this->current_operand_type)) + this->default_variable_name.current_type = &(this->lreal_type); + else + this->default_variable_name.current_type = this->current_operand_type; + } + else if (search_expression_type->is_literal_integer_type(this->default_variable_name.current_type)) { + if (search_expression_type->is_literal_integer_type(this->current_operand_type)) + this->default_variable_name.current_type = &(this->lint_type); + else if (search_expression_type->is_literal_real_type(this->current_operand_type)) + this->default_variable_name.current_type = &(this->lreal_type); + else + this->default_variable_name.current_type = this->current_operand_type; + } + else if (search_expression_type->is_literal_integer_type(this->current_operand_type) || + search_expression_type->is_literal_real_type(this->current_operand_type)) + this->current_operand_type = this->default_variable_name.current_type; + return NULL; + } + void *print_getter(symbol_c *symbol) { unsigned int vartype = search_varfb_instance_type->get_vartype(symbol); if (vartype == search_var_instance_decl_c::external_vt) @@ -340,6 +435,32 @@ /* B 2.1 Instructions and Operands */ /***********************************/ + /* | label ':' [il_incomplete_instruction] eol_list */ + // SYM_REF2(il_instruction_c, label, il_instruction) + void *visit(il_instruction_c *symbol) { + if (NULL != symbol->il_instruction) { + symbol->il_instruction->accept(*this); + } + return NULL; + } + /* | il_simple_operator [il_operand] */ + //SYM_REF2(il_simple_operation_c, il_simple_operator, il_operand) + void *visit(il_simple_operation_c *symbol) { + this->current_operand = symbol->il_operand; + if (NULL == this->current_operand) { + this->current_operand_type = NULL; + } else { + this->current_operand_type = search_expression_type->get_type(this->current_operand); + if (NULL == this->current_operand_type) ERROR; + } + + symbol->il_simple_operator->accept(*this); + + this->current_operand = NULL; + this->current_operand_type = NULL; + return NULL; + } + void *visit(il_function_call_c *symbol) { symbol_c* function_type_prefix = NULL; symbol_c* function_name = NULL; @@ -447,6 +568,53 @@ CLEAR_PARAM_LIST() + /* the data type resulting from this operation... */ + default_variable_name.current_type = function_type_prefix; + return NULL; + } + + /* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */ + //SYM_REF4(il_expression_c, il_expr_operator, il_operand, simple_instr_list, unused) + void *visit(il_expression_c *symbol) { + /* We will be recursevely interpreting an instruction list, + * so we store a backup of the data type of the value currently stored + * in the default variable, and set the current data type to NULL + */ + symbol_c *old_current_default_variable_data_type = this->default_variable_name.current_type; + this->default_variable_name.current_type = NULL; + + /* Pass the symbol->il_operand to the simple_instr_list visitor + * using the il_default_variable_init_value parameter... + * Note that the simple_instr_list_c visitor will set this parameter + * to NULL as soon as it does not require it any longer, + * so we don't do it here again after the + * symbol->simple_instr_list->accept(*this); + * returns... + */ + this->il_default_variable_init_value = symbol->il_operand; + + /* Now do the parenthesised instructions... */ + /* NOTE: the following code line will get the variable + * this->default_variable_name.current_type updated! + */ + symbol->simple_instr_list->accept(*this); + + /* Now do the operation, using the previous result! */ + /* NOTE: The result of the previous instruction list will be stored + * in a variable named IL_DEFVAR_BACK. This is done in the visitor + * to instruction_list_c objects... + */ + this->current_operand = &(this->default_variable_back_name); + this->current_operand_type = this->default_variable_back_name.current_type; + + this->default_variable_name.current_type = old_current_default_variable_data_type; + if (NULL == this->current_operand_type) ERROR; + + symbol->il_expr_operator->accept(*this); + + this->current_operand = NULL; + this->current_operand_type = NULL; + this->default_variable_back_name.current_type = NULL; return NULL; } @@ -557,6 +725,161 @@ CLEAR_PARAM_LIST() + /* the data type resulting from this operation... */ + default_variable_name.current_type = function_type_prefix; + return NULL; + } + + /* | simple_instr_list il_simple_instruction */ + // SYM_LIST(simple_instr_list_c) + void *visit(simple_instr_list_c *symbol) { + /* Check whether we should initiliase the il default variable... */ + if (NULL != this->il_default_variable_init_value) { + /* Yes, we must... */ + /* We will do it by instatiating a LD operator, and having this + * same generate_c_il_c class visiting it! + */ + LD_operator_c ld_oper; + il_simple_operation_c il_simple_oper(&ld_oper, this->il_default_variable_init_value); + + il_simple_oper.accept(*this); + } + + /* this parameter no longer required... */ + this->il_default_variable_init_value = NULL; + + iterator_visitor_c::visit(symbol); + + /* copy the result in the default variable to the variable + * used to pass the data out to the scope enclosing + * the current scope! + * + * We also need to update the data type currently stored within + * the variable used to pass the data to the outside scope... + */ + this->default_variable_back_name.current_type = this->default_variable_name.current_type; + return NULL; + } + + void *visit(LD_operator_c *symbol) { + /* the data type resulting from this operation... */ + this->default_variable_name.current_type = this->current_operand_type; + return NULL; + } + + void *visit(LDN_operator_c *symbol) { + /* the data type resulting from this operation... */ + this->default_variable_name.current_type = this->current_operand_type; + return NULL; + } + + void *visit(ADD_operator_c *symbol) { + if (search_expression_type->is_time_type(this->default_variable_name.current_type) && + search_expression_type->is_time_type(this->current_operand_type)) { + /* the data type resulting from this operation... */ + this->default_variable_name.current_type = this->current_operand_type; + return NULL; + } + if (search_expression_type->is_num_type(this->default_variable_name.current_type) && + search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) { + return NUM_operator_result_type(); + } + ERROR; + return NULL; + } + + void *visit(SUB_operator_c *symbol) { + if (search_expression_type->is_time_type(this->default_variable_name.current_type) && + search_expression_type->is_time_type(this->current_operand_type)) { + /* the data type resulting from this operation... */ + this->default_variable_name.current_type = this->current_operand_type; + return NULL; + } + if (search_expression_type->is_num_type(this->default_variable_name.current_type) && + search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) { + return NUM_operator_result_type(); + } + ERROR; + return NULL; + } + + void *visit(MUL_operator_c *symbol) { + if (search_expression_type->is_time_type(this->default_variable_name.current_type) && + search_expression_type->is_integer_type(this->current_operand_type)) { + return NULL; + } + if (search_expression_type->is_num_type(this->default_variable_name.current_type) && + search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) { + return NUM_operator_result_type(); + } + ERROR; + return NULL; + } + + void *visit(DIV_operator_c *symbol) { + if (search_expression_type->is_time_type(this->default_variable_name.current_type) && + search_expression_type->is_integer_type(this->current_operand_type)) { + return NULL; + } + if (search_expression_type->is_num_type(this->default_variable_name.current_type) && + search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) { + return NUM_operator_result_type(); + } + ERROR; + return NULL; + } + + void *visit(MOD_operator_c *symbol) { + if (search_expression_type->is_num_type(this->default_variable_name.current_type) && + search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) { + return NUM_operator_result_type(); + } + ERROR; + return NULL; + } + + void *visit(GT_operator_c *symbol) { + if (!search_base_type.type_is_enumerated(this->default_variable_name.current_type) && + search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) + return CMP_operator_result_type(); + ERROR; + return NULL; + } + + void *visit(GE_operator_c *symbol) { + if (!search_base_type.type_is_enumerated(this->default_variable_name.current_type) && + search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) + return CMP_operator_result_type(); + ERROR; + return NULL; + } + + void *visit(EQ_operator_c *symbol) { + if (search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) + return CMP_operator_result_type(); + ERROR; + return NULL; + } + + void *visit(LT_operator_c *symbol) { + if (!search_base_type.type_is_enumerated(this->default_variable_name.current_type) && + search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) + return CMP_operator_result_type(); + return NULL; + } + + void *visit(LE_operator_c *symbol) { + if (!search_base_type.type_is_enumerated(this->default_variable_name.current_type) && + search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) + return CMP_operator_result_type(); + ERROR; + return NULL; + } + + void *visit(NE_operator_c *symbol) { + if (search_expression_type->is_same_type(this->default_variable_name.current_type, this->current_operand_type)) + return CMP_operator_result_type(); + ERROR; return NULL; } @@ -567,6 +890,15 @@ /* B 3.1 - Expressions */ /***********************/ + void *visit(statement_list_c *symbol) { + function_call_iterator_c fc_iterator(symbol); + symbol_c* function_call; + while ((function_call = fc_iterator.next()) != NULL) { + function_call->accept(*this); + } + return NULL; + } + void *visit(function_invocation_c *symbol) { symbol_c* function_type_prefix = NULL; symbol_c* function_name = NULL; @@ -667,7 +999,7 @@ CLEAR_PARAM_LIST() - return NULL; + return NULL; } }; /* generate_c_inlinefcall_c */