Correctly generate C code for IL expressions, i.e. IL instructions inside parenthesis.
authorMario de Sousa <msousa@fe.up.pt>
Thu, 25 Oct 2012 18:20:28 +0100
changeset 690 6156ee2b4e32
parent 689 45c35d829db9
child 691 958454e9e40f
Correctly generate C code for IL expressions, i.e. IL instructions inside parenthesis.
absyntax/absyntax.def
stage1_2/iec_bison.yy
stage3/constant_folding.cc
stage3/fill_candidate_datatypes.cc
stage3/flow_control_analysis.cc
stage3/narrow_candidate_datatypes.cc
stage4/generate_c/generate_c_il.cc
stage4/generate_c/generate_c_inlinefcall.cc
stage4/generate_iec/generate_iec.cc
--- 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)