# HG changeset patch # User Mario de Sousa # Date 1351185628 -3600 # Node ID 6156ee2b4e329e0473e24eb58676660d7b989be4 # Parent 45c35d829db912c0ec0e0daaddb5d7a357e99c1e Correctly generate C code for IL expressions, i.e. IL instructions inside parenthesis. diff -r 45c35d829db9 -r 6156ee2b4e32 absyntax/absyntax.def --- a/absyntax/absyntax.def Thu Oct 25 18:12:51 2012 +0100 +++ b/absyntax/absyntax.def Thu Oct 25 18:20:28 2012 +0100 @@ -928,6 +928,12 @@ /* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */ +/* WARNING + * The semantics of the il_expression_c.il_operand member is NOT what you may expect! + * In order to simplify processing of the IL code, stage2 will prepend an artifical (and equivalent) 'LD ' IL instruction into the simple_instr_list + * The il_expression_c.il_operand is maintained, in case we really need to handle it as a special case! + * See the comments in iec_bison.yy for details and an example. + */ SYM_REF3(il_expression_c, il_expr_operator, il_operand, simple_instr_list) /* il_jump_operator label */ diff -r 45c35d829db9 -r 6156ee2b4e32 stage1_2/iec_bison.yy --- a/stage1_2/iec_bison.yy Thu Oct 25 18:12:51 2012 +0100 +++ b/stage1_2/iec_bison.yy Thu Oct 25 18:20:28 2012 +0100 @@ -6366,6 +6366,26 @@ il_expression: // il_expr_operator '(' [il_operand] EOL {EOL} [simple_instr_list] ')' +/* IMPORTANT NOTE: + * When the exists, and to make it easier to handle the as a general case (i.e. without C++ code handling this as a special case), + * we will create an equivalent LD IL instruction, and prepend it into the . + * The remainder of the compiler may from now on assume that the code being compiled does not contain any IL code like + * LD 1 + * ADD ( 2 + * SUB 3 + * ) + * + * but instead, the equivalent code + * LD 1 + * ADD ( + * LD 2 + * SUB 3 + * ) + * + * Note, however, that in the first case, we still store in the il_expression_c a pointer to the (the literal '2' in the above example), in case + * somewhere further on in the compiler we really want to handle it as a special case. To handle it as a special case, it should be easy to simply delete the first + * artificial entry in with il_expression->simple_instr_list->remove_element(0) !! + */ /* * Note: Bison is getting confused with the use of il_expr_operator, * i.e. it is finding conflicts where there seemingly are really none. @@ -6375,17 +6395,29 @@ il_expr_operator_noclash '(' eol_list ')' {$$ = new il_expression_c($1, NULL, NULL, locloc(@$));} | il_expr_operator_noclash '(' il_operand eol_list ')' - {$$ = new il_expression_c($1, $3, NULL, locloc(@$));} + { simple_instr_list_c *tmp_simple_instr_list = new simple_instr_list_c(locloc(@3)); + tmp_simple_instr_list ->insert_element(new il_simple_instruction_c(new il_simple_operation_c(new LD_operator_c(locloc(@3)), $3, locloc(@3)), locloc(@3)), 0); + $$ = new il_expression_c($1, $3, tmp_simple_instr_list, locloc(@$)); + } | il_expr_operator_noclash '(' eol_list simple_instr_list ')' {$$ = new il_expression_c($1, NULL, $4, locloc(@$));} | il_expr_operator_noclash '(' il_operand eol_list simple_instr_list ')' - {$$ = new il_expression_c($1, $3, $5, locloc(@$));} + { simple_instr_list_c *tmp_simple_instr_list = dynamic_cast $5; + tmp_simple_instr_list ->insert_element(new il_simple_instruction_c(new il_simple_operation_c(new LD_operator_c(locloc(@3)), $3, locloc(@3)), locloc(@3)), 0); + $$ = new il_expression_c($1, $3, $5, locloc(@$)); + } | il_expr_operator_clash '(' eol_list ')' {$$ = new il_expression_c($1, NULL, NULL, locloc(@$));} | il_expr_operator_clash '(' il_operand eol_list ')' - {$$ = new il_expression_c($1, $3, NULL, locloc(@$));} + { simple_instr_list_c *tmp_simple_instr_list = new simple_instr_list_c(locloc(@3)); + tmp_simple_instr_list ->insert_element(new il_simple_instruction_c(new il_simple_operation_c(new LD_operator_c(locloc(@3)), $3, locloc(@3)), locloc(@3)), 0); + $$ = new il_expression_c($1, $3, tmp_simple_instr_list, locloc(@$)); + } | il_expr_operator_clash '(' il_operand eol_list simple_instr_list ')' - {$$ = new il_expression_c($1, $3, $5, locloc(@$));} + { simple_instr_list_c *tmp_simple_instr_list = dynamic_cast $5; + tmp_simple_instr_list ->insert_element(new il_simple_instruction_c(new il_simple_operation_c(new LD_operator_c(locloc(@3)), $3, locloc(@3)), locloc(@3)), 0); + $$ = new il_expression_c($1, $3, $5, locloc(@$)); + } | il_expr_operator_clash_eol_list simple_instr_list ')' {$$ = new il_expression_c($1, NULL, $2, locloc(@$));} /* ERROR_CHECK_BEGIN */ diff -r 45c35d829db9 -r 6156ee2b4e32 stage3/constant_folding.cc --- a/stage3/constant_folding.cc Thu Oct 25 18:12:51 2012 +0100 +++ b/stage3/constant_folding.cc Thu Oct 25 18:20:28 2012 +0100 @@ -982,8 +982,9 @@ void *constant_folding_c::visit(il_expression_c *symbol) { symbol_c *prev_il_instruction_backup = prev_il_instruction; - if (NULL != symbol->il_operand) - symbol->il_operand->accept(*this); + /* Stage2 will insert an artificial (and equivalent) LD to the simple_instr_list if necessary. We can therefore ignore the 'il_operand' entry! */ + // if (NULL != symbol->il_operand) + // symbol->il_operand->accept(*this); if(symbol->simple_instr_list != NULL) symbol->simple_instr_list->accept(*this); @@ -996,6 +997,16 @@ /* This object has (inherits) the same cvalues as the il_instruction */ symbol->const_value = symbol->il_expr_operator->const_value; + + /* Since stage2 will insert an artificial (and equivalent) LD to the simple_instr_list when an 'il_operand' exists, we know + * that if (symbol->il_operand != NULL), then the first IL instruction in the simple_instr_list will be the equivalent and artificial + * 'LD ' IL instruction. + * Just to be cosistent, we will copy the constant info back into the il_operand, even though this should not be necessary! + */ + if ((NULL != symbol->il_operand) && ((NULL == symbol->simple_instr_list) || (0 == ((list_c *)symbol->simple_instr_list)->n))) ERROR; // stage2 is not behaving as we expect it to! + if (NULL != symbol->il_operand) + symbol->il_operand->const_value = ((list_c *)symbol->simple_instr_list)->elements[0]->const_value; + return NULL; } diff -r 45c35d829db9 -r 6156ee2b4e32 stage3/fill_candidate_datatypes.cc --- a/stage3/fill_candidate_datatypes.cc Thu Oct 25 18:12:51 2012 +0100 +++ b/stage3/fill_candidate_datatypes.cc Thu Oct 25 18:20:28 2012 +0100 @@ -1020,12 +1020,22 @@ void *fill_candidate_datatypes_c::visit(il_expression_c *symbol) { symbol_c *prev_il_instruction_backup = prev_il_instruction; - if (NULL != symbol->il_operand) - symbol->il_operand->accept(*this); + /* Stage2 will insert an artificial (and equivalent) LD to the simple_instr_list if necessary. We can therefore ignore the 'il_operand' entry! */ + // if (NULL != symbol->il_operand) + // symbol->il_operand->accept(*this); if(symbol->simple_instr_list != NULL) symbol->simple_instr_list->accept(*this); + /* Since stage2 will insert an artificial (and equivalent) LD to the simple_instr_list when an 'il_operand' exists, we know + * that if (symbol->il_operand != NULL), then the first IL instruction in the simple_instr_list will be the equivalent and artificial + * 'LD ' IL instruction. + * Just to be cosistent, we will copy the datatype info back into the il_operand, even though this should not be necessary! + */ + if ((NULL != symbol->il_operand) && ((NULL == symbol->simple_instr_list) || (0 == ((list_c *)symbol->simple_instr_list)->n))) ERROR; // stage2 is not behaving as we expect it to! + if (NULL != symbol->il_operand) + symbol->il_operand->candidate_datatypes = ((list_c *)symbol->simple_instr_list)->elements[0]->candidate_datatypes; + /* Now check the if the data type semantics of operation are correct, */ il_operand = symbol->simple_instr_list; prev_il_instruction = prev_il_instruction_backup; diff -r 45c35d829db9 -r 6156ee2b4e32 stage3/flow_control_analysis.cc --- a/stage3/flow_control_analysis.cc Thu Oct 25 18:12:51 2012 +0100 +++ b/stage3/flow_control_analysis.cc Thu Oct 25 18:20:28 2012 +0100 @@ -265,7 +265,9 @@ return NULL; symbol_c *save_prev_il_instruction = prev_il_instruction; - prev_il_instruction = symbol->il_operand; + /* Stage2 will insert an artificial (and equivalent) LD to the simple_instr_list if necessary. We can therefore ignore the 'il_operand' entry! */ + // prev_il_instruction = symbol->il_operand; + prev_il_instruction = NULL; symbol->simple_instr_list->accept(*this); prev_il_instruction = save_prev_il_instruction; return NULL; diff -r 45c35d829db9 -r 6156ee2b4e32 stage3/narrow_candidate_datatypes.cc --- a/stage3/narrow_candidate_datatypes.cc Thu Oct 25 18:12:51 2012 +0100 +++ b/stage3/narrow_candidate_datatypes.cc Thu Oct 25 18:20:28 2012 +0100 @@ -719,6 +719,16 @@ il_instruction_c *save_fake_prev_il_instruction = fake_prev_il_instruction; /*this is not really necessary, but lets play it safe */ symbol->simple_instr_list->accept(*this); fake_prev_il_instruction = save_fake_prev_il_instruction; + + /* Since stage2 will insert an artificial (and equivalent) LD to the simple_instr_list when an 'il_operand' exists, we know + * that if (symbol->il_operand != NULL), then the first IL instruction in the simple_instr_list will be the equivalent and artificial + * 'LD ' IL instruction. + * Just to be consistent, we will copy the datatype info back into the il_operand, even though this should not be necessary! + */ + if ((NULL != symbol->il_operand) && ((NULL == symbol->simple_instr_list) || (0 == ((list_c *)symbol->simple_instr_list)->n))) ERROR; // stage2 is not behaving as we expect it to! + if (NULL != symbol->il_operand) + symbol->il_operand->datatype = ((list_c *)symbol->simple_instr_list)->elements[0]->datatype; + return NULL; } diff -r 45c35d829db9 -r 6156ee2b4e32 stage4/generate_c/generate_c_il.cc --- a/stage4/generate_c/generate_c_il.cc Thu Oct 25 18:12:51 2012 +0100 +++ b/stage4/generate_c/generate_c_il.cc Thu Oct 25 18:20:28 2012 +0100 @@ -965,54 +965,12 @@ il_default_variable_c old_implicit_variable_current = this->implicit_variable_current; il_default_variable_c old_implicit_variable_result = this->implicit_variable_result; - /* If the symbol->il_operand is not NULL, then we instantiate a 'LD' operation and insert it into the simple_instr_list - * (i.e. add an equivalent LD operation to the Abstract Syntax Tree), and let it be handled like any other LD operation! - */ - if (NULL != symbol->il_operand) { - tmp_LD_operator = new LD_operator_c(); - if (NULL == tmp_LD_operator) ERROR; - /* copy all the location, datatpe, etc.. data from symbol->il_operand to the new object! */ - *((symbol_c *)tmp_LD_operator) = *(symbol->il_operand); - - tmp_il_simple_operation = new il_simple_operation_c(tmp_LD_operator, symbol->il_operand); - if (NULL == tmp_il_simple_operation) ERROR; - /* copy all the location, datatpe, etc.. data from symbol->il_operand to the new object! */ - *((symbol_c *)tmp_il_simple_operation) = *(symbol->il_operand); - - tmp_il_simple_instruction = new il_simple_instruction_c(tmp_il_simple_operation); - if (NULL == tmp_il_simple_instruction) ERROR; - /* copy all the location, datatpe, etc.. data from symbol->il_operand to the new object! */ - *((symbol_c *)tmp_il_simple_instruction) = *(symbol->il_operand); - - if (NULL == symbol->simple_instr_list) { - symbol->simple_instr_list = new simple_instr_list_c(); - if (NULL == symbol->simple_instr_list) ERROR; - /* copy all the location, datatpe, etc.. data from symbol->il_operand to the new object! */ - *((symbol_c *)symbol->simple_instr_list) = *(symbol->il_operand); - } - list_c *tmp_list = dynamic_cast (symbol->simple_instr_list); - if (NULL == tmp_list) ERROR; - tmp_list->insert_element(tmp_il_simple_instruction, 0); - } + /* Stage2 will insert an artificial (and equivalent) LD to the simple_instr_list if necessary. We can therefore ignore the 'il_operand' entry! */ + //if (NULL != symbol->il_operand) { do nothing!! } /* Now do the parenthesised instructions... */ /* NOTE: the following code line will overwrite the variables implicit_variable_current and implicit_variable_result */ symbol->simple_instr_list->accept(*this); - - /* delete/undo any changes made to the AST above */ - if (NULL != symbol->il_operand) { - delete tmp_LD_operator; - delete tmp_il_simple_operation; - delete tmp_il_simple_instruction; - list_c *tmp_list = dynamic_cast (symbol->simple_instr_list); - if (NULL == tmp_list) ERROR; - delete tmp_list->elements[0]; - tmp_list->remove_element(0); - if (0 == tmp_list->n) { - delete symbol->simple_instr_list; - symbol->simple_instr_list = NULL; - } - } /* Now do the operation, using the previous result! */ /* NOTE: The result of the previous instruction list in the parenthesis will be stored @@ -1428,8 +1386,8 @@ * * NOTE 2: * If the intial value of the il implicit variable (in the above - * example 'var2') exists, then the il_expression_c will insert an equivalent - * LD operation into the parenthesized instruction list- This means we do not + * example 'var2') exists, then stage2 will insert an equivalent + * LD operation into the parenthesized instruction list. This means we do not * need to do anything here to handle this special situation! */ diff -r 45c35d829db9 -r 6156ee2b4e32 stage4/generate_c/generate_c_inlinefcall.cc --- a/stage4/generate_c/generate_c_inlinefcall.cc Thu Oct 25 18:12:51 2012 +0100 +++ b/stage4/generate_c/generate_c_inlinefcall.cc Thu Oct 25 18:20:28 2012 +0100 @@ -37,30 +37,6 @@ } variablegeneration_t; 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; - /* 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 @@ -109,7 +85,6 @@ search_var_instance_decl = new search_var_instance_decl_c (scope); this->set_variable_prefix(variable_prefix); - il_default_variable_init_value = NULL; fcall_number = 0; fbname = name; wanted_variablegeneration = expression_vg; @@ -577,18 +552,10 @@ /* We will be recursevely interpreting an instruction list, so we store a backup of the implicit_variable_result/current. * Notice that they will be overwriten while processing the parenthsized instruction list. */ - // il_default_variable_c old_implicit_variable_current = this->implicit_variable_current; // no longer needed! - - - /* 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; + // il_default_variable_c old_implicit_variable_current = this->implicit_variable_current; // no longer needed as we do not call symbol->il_expr_operator->accept(*this); + + /* Stage2 will insert an artificial (and equivalent) LD to the simple_instr_list if necessary. We can therefore ignore the 'il_operand' entry! */ + //if (NULL != symbol->il_operand) { do nothing!! } /* Now do the parenthesised instructions... */ /* NOTE: the following code line will get the variable this->implicit_variable_current.datatype updated! */ @@ -739,20 +706,16 @@ /* | 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... */ - // TODO: fix the way we handle this... It is currently not working!! -// if (NULL != this->il_default_variable_init_value) implicit_variable_current = il_default_variable_init_value; - this->il_default_variable_init_value = NULL; // this parameter no longer required... - - iterator_visitor_c::visit(symbol); - return NULL; - } + void *visit(simple_instr_list_c *symbol) {return iterator_visitor_c::visit(symbol);} // SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;) void *visit(il_simple_instruction_c *symbol) { - return symbol->il_simple_instruction->accept(*this); + /* all previous IL instructions should have the same datatype (checked in stage3), so we get the datatype from the first previous IL instruction we find */ + implicit_variable_current.datatype = (symbol->prev_il_instruction.empty())? NULL : symbol->prev_il_instruction[0]->datatype; + symbol->il_simple_instruction->accept(*this); + implicit_variable_current.datatype = NULL; + return NULL; } diff -r 45c35d829db9 -r 6156ee2b4e32 stage4/generate_iec/generate_iec.cc --- a/stage4/generate_iec/generate_iec.cc Thu Oct 25 18:12:51 2012 +0100 +++ b/stage4/generate_iec/generate_iec.cc Thu Oct 25 18:20:28 2012 +0100 @@ -1661,6 +1661,14 @@ /* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */ void *visit(il_expression_c *symbol) { + /* Since stage2 will insert an artificial (and equivalent) LD to the simple_instr_list when an 'il_operand' exists, we know + * that if (symbol->il_operand != NULL), then the first IL instruction in the simple_instr_list will be the equivalent and artificial + * 'LD ' IL instruction. + * Since we do not want the extra LD instruction, we simply remove it! + */ + if (symbol->il_operand != NULL) + ((list_c *)symbol->simple_instr_list)->remove_element(0); + symbol->il_expr_operator->accept(*this); s4o.print("("); if (symbol->il_operand != NULL)