Change prev_il_instruction to a vector<>
authorMario de Sousa <msousa@fe.up.pt>
Mon, 27 Feb 2012 11:44:03 +0000
changeset 457 67d8b07bac22
parent 456 ca8d98289ff9
child 458 587884880be6
Change prev_il_instruction to a vector<>
absyntax/absyntax.def
readme
stage3/datatype_functions.cc
stage3/datatype_functions.hh
stage3/fill_candidate_datatypes.cc
stage3/flow_control_analysis.cc
stage3/narrow_candidate_datatypes.cc
stage3/print_datatypes_error.cc
--- a/absyntax/absyntax.def	Mon Feb 27 11:28:51 2012 +0000
+++ b/absyntax/absyntax.def	Mon Feb 27 11:44:03 2012 +0000
@@ -917,7 +917,7 @@
  *       In case of an il instruction preceded by a label, this will include all IL instructions that jump to this label!
  *       It is filled in by the flow_control_analysis_c during stage 3.
  */
-SYM_REF2(il_instruction_c, label, il_instruction, symbol_c *prev_il_instruction;)
+SYM_REF2(il_instruction_c, label, il_instruction, std::vector <symbol_c *> prev_il_instruction;)
 
 
 /* | il_simple_operator [il_operand] */
@@ -965,7 +965,7 @@
  * | il_formal_funct_call eol_list
  */
 /* NOTE: The parameter 'prev_il_instruction' is used to point to all previous il instructions that may be executed imedaitely before this instruction. */
-SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;)
+SYM_REF1(il_simple_instruction_c, il_simple_instruction, std::vector <symbol_c *> prev_il_instruction;)
 
 /* | il_initial_param_list il_param_instruction */
 SYM_LIST(il_param_list_c)
--- a/readme	Mon Feb 27 11:28:51 2012 +0000
+++ b/readme	Mon Feb 27 11:44:03 2012 +0000
@@ -145,13 +145,15 @@
      Pass 1: Analyses the possible data types each expression/literal/IL instruction/etc. may take 
              Implemented in -> stage3/fill_candidate_datatypes_c
              This will anotate the abstract syntax tree 
-             (Every object of in the abstract syntax tree that may have a data type, will have the variable 'candidate_datatypes' correctly filled in.)
-     Pass 2: Narrows all the possible data types each expression/literal/IL instruction/etc. may take down to a single data type 
+             (Every object of in the abstract syntax tree that may have a data type, will have the variable 'candidate_datatypes' correctly filled in.
+             Additionally, objects in the abstract syntax tree that represen function invocations will have the variable 
+              'candidate_functions' correctly filled in.)
+Pass 2: Narrows all the possible data types each expression/literal/IL instruction/etc. may take down to a single data type 
              Implemented in -> stage3/narrow_candidate_datatypes_c
              This will anotate the abstract syntax tree 
              (Every object of in the abstract syntax tree that may have a data type, will have the variable 'datatype' correctly filled in.
               Additionally, objects in the abstract syntax tree that represen function invocations will have the variables 
-              'called_function_declaration', 'extensible_param_count' and 'candidate_functions' correctly filled in.
+              'called_function_declaration' and 'extensible_param_count' correctly filled in.
               Additionally, objects in the abstract syntax tree that represen function block (FB) invocations will have the variable
               'called_fb_declaration' correctly filled in.)
      Pass 2: Prints error messages in the event of the IEC 61131-3 source code being analysed contains semantic data type incompatibility errors.
--- a/stage3/datatype_functions.cc	Mon Feb 27 11:28:51 2012 +0000
+++ b/stage3/datatype_functions.cc	Mon Feb 27 11:44:03 2012 +0000
@@ -24,7 +24,8 @@
 
 #include "datatype_functions.hh"
 #include "../absyntax_utils/absyntax_utils.hh"
-#include <algorithm>
+#include <vector>
+// #include <algorithm>
 
 
 
@@ -71,14 +72,14 @@
 
 
 const struct widen_entry widen_SUB_table[] = {
-	{ &search_constant_type_c::time_type_name,          &search_constant_type_c::time_type_name,            &search_constant_type_c::time_type_name     },
-	{ &search_constant_type_c::tod_type_name,           &search_constant_type_c::tod_type_name,             &search_constant_type_c::tod_type_name      },
-	{ &search_constant_type_c::dt_type_name,            &search_constant_type_c::dt_type_name,              &search_constant_type_c::dt_type_name       },
-	{ &search_constant_type_c::safetime_type_name,      &search_constant_type_c::safetime_type_name,        &search_constant_type_c::safetime_type_name },
-	{ &search_constant_type_c::safetod_type_name,       &search_constant_type_c::safetod_type_name,         &search_constant_type_c::safetod_type_name  },
-	{ &search_constant_type_c::safedt_type_name,        &search_constant_type_c::safedt_type_name,          &search_constant_type_c::safedt_type_name   },
-
-	{ &search_constant_type_c::tod_type_name,           &search_constant_type_c::time_type_name,            &search_constant_type_c::tod_type_name      },
+    { &search_constant_type_c::time_type_name,          &search_constant_type_c::time_type_name,            &search_constant_type_c::time_type_name     },
+    { &search_constant_type_c::tod_type_name,           &search_constant_type_c::tod_type_name,             &search_constant_type_c::tod_type_name      },
+    { &search_constant_type_c::dt_type_name,            &search_constant_type_c::dt_type_name,              &search_constant_type_c::dt_type_name       },
+    { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::safetime_type_name,        &search_constant_type_c::safetime_type_name },
+    { &search_constant_type_c::safetod_type_name,       &search_constant_type_c::safetod_type_name,         &search_constant_type_c::safetod_type_name  },
+    { &search_constant_type_c::safedt_type_name,        &search_constant_type_c::safedt_type_name,          &search_constant_type_c::safedt_type_name   },
+
+    { &search_constant_type_c::tod_type_name,           &search_constant_type_c::time_type_name,            &search_constant_type_c::tod_type_name      },
     { &search_constant_type_c::safetod_type_name,       &search_constant_type_c::time_type_name,            &search_constant_type_c::tod_type_name      },
     { &search_constant_type_c::tod_type_name,           &search_constant_type_c::safetime_type_name,        &search_constant_type_c::tod_type_name      },
     { &search_constant_type_c::safetod_type_name,       &search_constant_type_c::safetime_type_name,        &search_constant_type_c::safetod_type_name  },
@@ -136,7 +137,7 @@
 };
 
 const struct widen_entry widen_DIV_table[] = {
-	{ &search_constant_type_c::time_type_name,          &search_constant_type_c::lreal_type_name,           &search_constant_type_c::time_type_name     },
+    { &search_constant_type_c::time_type_name,          &search_constant_type_c::lreal_type_name,           &search_constant_type_c::time_type_name     },
     { &search_constant_type_c::time_type_name,          &search_constant_type_c::real_type_name,            &search_constant_type_c::time_type_name     },
     { &search_constant_type_c::time_type_name,          &search_constant_type_c::dint_type_name,            &search_constant_type_c::time_type_name     },
     { &search_constant_type_c::time_type_name,          &search_constant_type_c::int_type_name,             &search_constant_type_c::time_type_name     },
@@ -201,6 +202,27 @@
 
 
 
+/* Intersect two candidate_datatype_lists.
+ * Remove from list1 (origin, dest.) all elements that are not found in list2 (with).
+ * In essence, list1 will contain the result of the intersection of list1 with list2.
+ * In other words, modify list1 so it only contains the elelements that are simultaneously in list1 and list2!
+ */
+void intersect_candidate_datatype_list(symbol_c *list1 /*origin, dest.*/, symbol_c *list2 /*with*/) {
+	if ((NULL == list1) || (NULL == list2))
+		/* In principle, we should never call it with NULL values. Best to abort the compiler just in case! */
+		return;
+
+	for(std::vector<symbol_c *>::iterator i = list1->candidate_datatypes.begin(); i < list1->candidate_datatypes.end(); ) {
+		/* Note that we do _not_ increment i in the for() loop!
+		 * When we erase an element from position i, a new element will take it's place, that must also be tested! 
+		 */
+		if (search_in_candidate_datatype_list(*i, list2->candidate_datatypes) < 0)
+			/* remove this element! This will change the value of candidate_datatypes.size() */
+			list1->candidate_datatypes.erase(i);
+		else i++;
+	}
+}
+
 
 
 /* A helper function... */
--- a/stage3/datatype_functions.hh	Mon Feb 27 11:28:51 2012 +0000
+++ b/stage3/datatype_functions.hh	Mon Feb 27 11:44:03 2012 +0000
@@ -146,6 +146,13 @@
  */
 void copy_candidate_datatype_list(symbol_c *from, symbol_c *to);
 
+/* Intersect two candidate_datatype_lists.
+ * Remove from list1 (origin, dest.) all elements that are not found in list2 (with).
+ * In essence, list1 will contain the result of the intersection of list1 with list2.
+ * In other words, modify list1 so it only contains the elelements that are simultaneously in list1 and list2!
+ */
+void intersect_candidate_datatype_list(symbol_c *list1 /*origin, dest.*/, symbol_c *list2 /*with*/);
+
 
 /* A helper function... */
 bool is_ANY_ELEMENTARY_type         (symbol_c *type_symbol);
--- a/stage3/fill_candidate_datatypes.cc	Mon Feb 27 11:28:51 2012 +0000
+++ b/stage3/fill_candidate_datatypes.cc	Mon Feb 27 11:44:03 2012 +0000
@@ -808,10 +808,16 @@
 		/* This empty/null il_instruction does not change the value of the current/default IL variable.
 		 * So it inherits the candidate_datatypes from it's previous IL instructions!
 		 */
-		if (NULL != symbol->prev_il_instruction)
-			copy_candidate_datatype_list(symbol->prev_il_instruction /*from*/, symbol /*to*/);	
+		if (!symbol->prev_il_instruction.empty()) {
+			copy_candidate_datatype_list(symbol->prev_il_instruction[0] /*from*/, symbol /*to*/);
+			for (unsigned int i = 1; i < symbol->prev_il_instruction.size(); i++) {
+				intersect_candidate_datatype_list(symbol /*origin, dest.*/, symbol->prev_il_instruction[i] /*with*/);
+			}
+		}
 	} else {
-		prev_il_instruction = symbol->prev_il_instruction;
+		if (symbol->prev_il_instruction.size() > 1) ERROR; /* This assertion is only valid for now. Remove it once flow_control_analysis_c is complete */
+		if (symbol->prev_il_instruction.size() == 0)  prev_il_instruction = NULL;
+		else                                          prev_il_instruction = symbol->prev_il_instruction[0];
 		symbol->il_instruction->accept(*this);
 		prev_il_instruction = NULL;
 
@@ -1011,9 +1017,14 @@
   return NULL;
 }
 
+
+
+
 // SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;)
 void *fill_candidate_datatypes_c::visit(il_simple_instruction_c *symbol) {
-  prev_il_instruction = symbol->prev_il_instruction;
+  if (symbol->prev_il_instruction.size() > 1) ERROR; /* This assertion is only valid for now. Remove it once flow_control_analysis_c is complete */
+  if (symbol->prev_il_instruction.size() == 0)  prev_il_instruction = NULL;
+  else                                          prev_il_instruction = symbol->prev_il_instruction[0];
   symbol->il_simple_instruction->accept(*this);
   prev_il_instruction = NULL;
 
--- a/stage3/flow_control_analysis.cc	Mon Feb 27 11:28:51 2012 +0000
+++ b/stage3/flow_control_analysis.cc	Mon Feb 27 11:44:03 2012 +0000
@@ -190,7 +190,7 @@
 // SYM_REF2(il_instruction_c, label, il_instruction)
 // void *visit(instruction_list_c *symbol);
 void *flow_control_analysis_c::visit(il_instruction_c *symbol) {
-	symbol->prev_il_instruction = prev_il_instruction;
+	symbol->prev_il_instruction.push_back(prev_il_instruction);
 	/* TODO: handle labels correctly!
 	 *
 	 *      Don't forget to handle multiple consecutive lables too!
@@ -268,7 +268,7 @@
 
 // SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;)
 void *flow_control_analysis_c::visit(il_simple_instruction_c*symbol) {
-	symbol->prev_il_instruction = prev_il_instruction;
+	symbol->prev_il_instruction.push_back(prev_il_instruction);
 	return NULL;
 }
 
--- a/stage3/narrow_candidate_datatypes.cc	Mon Feb 27 11:28:51 2012 +0000
+++ b/stage3/narrow_candidate_datatypes.cc	Mon Feb 27 11:44:03 2012 +0000
@@ -64,6 +64,13 @@
 
 
 
+/* Only set the symbol's desired datatype to 'datatype' if that datatype is in the candidate_datatype list */
+static void set_datatype_in_prev_il_instruction(symbol_c *datatype, il_instruction_c *symbol) {
+	for (unsigned int i = 0; i < symbol->prev_il_instruction.size(); i++)
+		set_datatype(datatype, symbol->prev_il_instruction[i]);
+}
+
+
 
 bool narrow_candidate_datatypes_c::is_widening_compatible(symbol_c *left_type, symbol_c *right_type, symbol_c *result_type, const struct widen_entry widen_table[]) {
 	for (int k = 0; NULL != widen_table[k].left;  k++) {
@@ -503,12 +510,12 @@
 void *narrow_candidate_datatypes_c::visit(il_instruction_c *symbol) {
 	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;
+		set_datatype_in_prev_il_instruction(symbol->datatype, symbol);
 	} else {
 		/* 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;
-		prev_il_instruction = symbol->prev_il_instruction;
+		if (symbol->prev_il_instruction.size() > 1) ERROR; /* This assertion is only valid for now. Remove it once flow_control_analysis_c is complete */
+		if (symbol->prev_il_instruction.size() == 0)  prev_il_instruction = NULL;
+		else                                          prev_il_instruction = symbol->prev_il_instruction[0];
 		symbol->il_instruction->accept(*this);
 		prev_il_instruction = NULL;
 	}
@@ -657,7 +664,9 @@
 
 // SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;)
 void *narrow_candidate_datatypes_c::visit(il_simple_instruction_c *symbol)	{
-  prev_il_instruction = symbol->prev_il_instruction;
+  if (symbol->prev_il_instruction.size() > 1) ERROR; /* This assertion is only valid for now. Remove it once flow_control_analysis_c is complete */
+  if (symbol->prev_il_instruction.size() == 0)   prev_il_instruction = NULL;
+  else                                           prev_il_instruction = symbol->prev_il_instruction[0];
   symbol->il_simple_instruction->datatype = symbol->datatype;
   symbol->il_simple_instruction->accept(*this);
   prev_il_instruction = NULL;
--- a/stage3/print_datatypes_error.cc	Mon Feb 27 11:28:51 2012 +0000
+++ b/stage3/print_datatypes_error.cc	Mon Feb 27 11:44:03 2012 +0000
@@ -598,7 +598,10 @@
 // SYM_REF2(il_instruction_c, label, il_instruction)
 void *print_datatypes_error_c::visit(il_instruction_c *symbol) {
 	if (NULL != symbol->il_instruction) {
-		prev_il_instruction = symbol->prev_il_instruction;
+		if (symbol->prev_il_instruction.size() > 1) ERROR; /* This assertion is only valid for now. Remove it once flow_control_analysis_c is complete */
+		if (symbol->prev_il_instruction.size() == 0)  prev_il_instruction = NULL;
+		else                                          prev_il_instruction = symbol->prev_il_instruction[0];
+
 		symbol->il_instruction->accept(*this);
 		prev_il_instruction = NULL;
 	}
@@ -736,7 +739,10 @@
 
 // SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;)
 void *print_datatypes_error_c::visit(il_simple_instruction_c *symbol)	{
-  prev_il_instruction = symbol->prev_il_instruction;
+  if (symbol->prev_il_instruction.size() > 1) ERROR; /* This assertion is only valid for now. Remove it once flow_control_analysis_c is complete */
+  if (symbol->prev_il_instruction.size() == 0)  prev_il_instruction = NULL;
+  else                                          prev_il_instruction = symbol->prev_il_instruction[0];
+
   symbol->il_simple_instruction->accept(*this);
   prev_il_instruction = NULL;
   return NULL;