Correctly generate C code for IL expressions, i.e. IL instructions inside parenthesis.
--- 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_operand>' 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 */
--- 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 <il_operand> exists, and to make it easier to handle the <il_operand> as a general case (i.e. without C++ code handling this as a special case),
+ * we will create an equivalent LD <il_operand> IL instruction, and prepend it into the <simple_instr_list>.
+ * 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 <il_operand> (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 <simple_instr_list> 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 <simple_instr_list_c *> $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 <simple_instr_list_c *> $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 */
--- 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 <il_operand> 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 <il_operand> 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_operand>' 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;
}
--- 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 <il_operand> 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 <il_operand> 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_operand>' 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;
--- 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 <il_operand> 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;
--- 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 <il_operand> 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_operand>' 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;
}
--- 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 <list_c *>(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 <il_operand> 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 <list_c *>(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!
*/
--- 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 <il_operand> 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;
}
--- 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 <il_operand> 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_operand>' 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)