Do datatype checking of enum values defined inside anonymous enumeration types (i.e. enum types defined inside a VAR ... END_VAR daclaration).
authorMario de Sousa <msousa@fe.up.pt>
Wed, 07 Nov 2012 10:03:54 +0000
changeset 716 eb9aad0c3627
parent 700 b0ef6711f2a8
child 717 44f74fad2cc0
Do datatype checking of enum values defined inside anonymous enumeration types (i.e. enum types defined inside a VAR ... END_VAR daclaration).
absyntax_utils/absyntax_utils.hh
stage3/fill_candidate_datatypes.cc
util/symtable.hh
--- a/absyntax_utils/absyntax_utils.hh	Wed Oct 24 00:06:55 2012 +0200
+++ b/absyntax_utils/absyntax_utils.hh	Wed Nov 07 10:03:54 2012 +0000
@@ -77,16 +77,21 @@
 extern symbol_c null_symbol4;
 extern symtable_c<symbol_c *, &null_symbol4> type_symtable;
 
-/* A symbol table with all values declared for enumerated type... */
+/* A symbol table with all values declared for enumerated types declared in global scope
+ * (i.e. declared inside a TYPE ... END_TYPE declaration.
+ */
 /* Notes:
- * - if the value is defined multiple times the value
- * is the null pointer.
+ * (A) - Some enumerations are implicitly declared inside a VAR ... END_VAR declaration
+ *   (e.g. VAR enum_var : (enumvalue1, enumvalue2); END_VAR)
+ *   These enumvalueX will only be valid (in scope) inside the POU in which the enum_var is declared. 
+ *   Because of this, they are not stored in this symbol table
  *
- * - The stored symbol_c * associated to the value points to the enumerated_type_name
- * (i.e. the name of the enumerated data type) in which the the value/identifier
- * is used/declared.
+ * (B) - if the value is defined multiple times the value is the null pointer.
  *
- * - We could re-use the null_symbol4 object, but it is safer to use a distinct object
+ * (C) - The stored symbol_c * associated to the value points to the enumerated_type_name
+ *   (i.e. the name of the enumerated data type) in which the the value/identifier is used/declared.
+ *
+ * (D) - We could re-use the null_symbol4 object, but it is safer to use a distinct object
  *   (i.e. it might make it easier to find strange bugs).
  */
 extern symbol_c null_symbol5;
--- a/stage3/fill_candidate_datatypes.cc	Wed Oct 24 00:06:55 2012 +0200
+++ b/stage3/fill_candidate_datatypes.cc	Wed Nov 07 10:03:54 2012 +0000
@@ -71,6 +71,117 @@
 /* set to 1 to see debug info during execution */
 static int debug = 0;
 
+
+
+
+/*****************************************************/
+/*                                                   */
+/*  A small helper class...                          */
+/*                                                   */
+/*****************************************************/
+
+/* Add to the local_enumerated_value_symtable the local enum value constants */
+/* WARNING: This visitor expects to visit a POU (function, FB, program, ...)
+ *          It should not be called to visit any symbol that may include a TYPE .., END_TYPE declaration!
+ */
+/* Notes:
+ * Some enumerations are 
+ *   (A) declared anonymously inside a VAR ... END_VAR declaration
+ *       (e.g. VAR enum_var : (enumvalue1, enumvalue2); END_VAR)
+ *  while others are 
+ *   (B) declared (with a name) inside a TYPE .. END_TYPE declaration.
+ *
+ *  Values in (A) are added to the enumerated_value_symtable in absyntaxt_utils.cc.
+ *  Values in (B) are only in scope inside the POU with the VAR END_VAR declaration.
+ *
+ * This class will add the enum values in (B) to the local_enumerated_value_symtable.
+ *
+ * If a locally defined enum value is identical to another locally defined enum_value, the
+ *  corresponding entry in local_enumerated_value_symtable is set to NULL.
+ *  However, if a locally defined enum value is identical to another globally defined enum_value, the
+ *  corresponding entry in local_enumerated_value_symtable is set to the local datatype (and not NULL).
+ *  This is because anonynous locally feined enum datatypes are anonymous, and its enum values cannot therefore
+ *  be disambiguated using EnumType#enum_value (since the enum type does not have a name, it is anonymous!).
+ *  For this reason we implement the semantics where locally defined enum values, when in scope, will 'cover'
+ *  the globally defined enum value with the same name/identifier.
+ *  For example:
+ *
+ *  TYPE  GlobalEnumT: (xxx1, xxx2, xxx3) END_TYPE
+ * 
+ *   FUNCTION_BLOCK FOO
+ *    VAR_INPUT
+ *       GlobalEnumVar: GlobalEnumT;
+ *      LocalEnumVar : (xxx1, yyy2, yyy3);
+ *     END_VAR
+ *     LocalEnumVar  := xxx1;   <-- We consider it OK!!!     xxx1 will reference the anonymous type used for LocalEnumVar
+ *     GlobalEnumVar := xxx1;   <-- We consider it an error. xxx1 will reference the anonymous type used for LocalEnumVar
+ *     GlobalEnumVar := GlobalEnumT#xxx1;
+ *     END_FUNCTION_BLOCK
+ */
+ 
+ symbol_c null_enumvalue_symbol; /* cannot be static, so it may be used in the template!! */
+ static symtable_c<symbol_c *, &null_enumvalue_symbol> local_enumerated_value_symtable;
+
+
+class populate_enumvalue_symtable_c: public iterator_visitor_c {
+  private:
+    symbol_c *current_enumerated_type;
+
+  public:
+     populate_enumvalue_symtable_c(void) {current_enumerated_type = NULL;};
+    ~populate_enumvalue_symtable_c(void) {}
+
+  public:
+  /*************************/
+  /* B.1 - Common elements */
+  /*************************/
+  /**********************/
+  /* B.1.3 - Data types */
+  /**********************/
+  /********************************/
+  /* B 1.3.3 - Derived data types */
+  /********************************/
+  /* enumerated_specification ASSIGN enumerated_value */
+  void *visit(enumerated_spec_init_c *symbol) {
+    current_enumerated_type = symbol;
+    symbol->enumerated_specification->accept(*this);
+    /* DO NOT visit the symbol->enumerated_value   !!! */
+    current_enumerated_type = NULL;
+    return NULL;
+  }
+
+  /* [enumerated_type_name '#'] identifier */
+  void *visit(enumerated_value_c *symbol) {
+    /* if the enumerated_value_c is not inside a enumerated_spec_init_c (e.g. used as the inital value of a variable), we simply return */
+    if (current_enumerated_type == NULL) return NULL;  
+    /* this is really an ERROR! The initial value may use the syntax NUM_TYPE#enum_value, but in that case we should have return'd in the above statement !! */
+    if (symbol->type != NULL) ERROR;  
+
+    // symbol_c *global_value_type =       enumerated_value_symtable.find_value(symbol->value);
+    symbol_c *local_value_type  = local_enumerated_value_symtable.find_value(symbol->value);
+    if (local_value_type == local_enumerated_value_symtable.end_value())
+      /* This identifier has not yet been used in any previous local declaration of an enumeration data type, so we add it to the local symbol table. */
+      local_enumerated_value_symtable.insert(symbol->value, current_enumerated_type);
+    else 
+      /* This identifier has already been used in a previous declaration of an enumeration data type. so we set the symbol in symbol table pointing to NULL. */
+      local_enumerated_value_symtable.set(symbol->value, NULL);
+    return NULL;
+  }
+}; // class populate_enumvalue_symtable_c
+
+static populate_enumvalue_symtable_c populate_enumvalue_symtable;
+
+
+
+
+/*****************************************************/
+/*                                                   */
+/*  Main  FILL candidate datatypes algorithm...      */
+/*                                                   */
+/*****************************************************/
+
+
+
 fill_candidate_datatypes_c::fill_candidate_datatypes_c(symbol_c *ignore) {
 	il_operand = NULL;
 	prev_il_instruction = NULL;
@@ -630,14 +741,26 @@
 */
 
 void *fill_candidate_datatypes_c::visit(enumerated_value_c *symbol) {
+	symbol_c *global_enumerated_type;
+	symbol_c *local_enumerated_type;
 	symbol_c *enumerated_type;
 
 	if (NULL != symbol->type)
-		enumerated_type = symbol->type;
+		enumerated_type = symbol->type; /* TODO: check whether the value really belongs to that datatype!! */
 	else {
-		enumerated_type = enumerated_value_symtable.find_value(symbol->value);
-		if (enumerated_type == enumerated_value_symtable.end_value())
-			enumerated_type = NULL;
+		global_enumerated_type =       enumerated_value_symtable.find_value(symbol->value);
+		local_enumerated_type  = local_enumerated_value_symtable.find_value(symbol->value);
+		if      ((local_enumerated_type == local_enumerated_value_symtable.end_value()) && (global_enumerated_type == enumerated_value_symtable.end_value()))
+		  enumerated_type = NULL; // not found!
+		else if ((local_enumerated_type != local_enumerated_value_symtable.end_value()) && (local_enumerated_type == NULL))
+			enumerated_type = NULL; // Duplicate, so it is ambiguous!
+		else if ((local_enumerated_type != local_enumerated_value_symtable.end_value()))
+			enumerated_type = local_enumerated_type;
+		else if ((global_enumerated_type !=      enumerated_value_symtable.end_value()) && (global_enumerated_type == NULL))
+			enumerated_type = NULL; // Duplicate, so it is ambiguous!
+		else if ((global_enumerated_type !=      enumerated_value_symtable.end_value()))
+			enumerated_type = global_enumerated_type;
+		else ERROR;
 	}
 	enumerated_type = base_type(enumerated_type);
 	if (NULL != enumerated_type)
@@ -849,11 +972,16 @@
 /*********************/
 void *fill_candidate_datatypes_c::visit(function_declaration_c *symbol) {
 	if (debug) printf("Filling candidate data types list of function %s\n", ((token_c *)(symbol->derived_function_name))->value);
+	local_enumerated_value_symtable.reset();
+	symbol->var_declarations_list->accept(populate_enumvalue_symtable);
+
 	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
 	symbol->var_declarations_list->accept(*this);
 	symbol->function_body->accept(*this);
 	delete search_varfb_instance_type;
 	search_varfb_instance_type = NULL;
+
+	local_enumerated_value_symtable.reset();
 	return NULL;
 }
 
@@ -862,11 +990,16 @@
 /***************************/
 void *fill_candidate_datatypes_c::visit(function_block_declaration_c *symbol) {
 	if (debug) printf("Filling candidate data types list of FB %s\n", ((token_c *)(symbol->fblock_name))->value);
+	local_enumerated_value_symtable.reset();
+	symbol->var_declarations->accept(populate_enumvalue_symtable);
+
 	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
 	symbol->var_declarations->accept(*this);
 	symbol->fblock_body->accept(*this);
 	delete search_varfb_instance_type;
 	search_varfb_instance_type = NULL;
+
+	local_enumerated_value_symtable.reset();
 	return NULL;
 }
 
@@ -875,11 +1008,16 @@
 /**********************/
 void *fill_candidate_datatypes_c::visit(program_declaration_c *symbol) {
 	if (debug) printf("Filling candidate data types list in program %s\n", ((token_c *)(symbol->program_type_name))->value);
+	local_enumerated_value_symtable.reset();
+	symbol->var_declarations->accept(populate_enumvalue_symtable);
+	
 	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
 	symbol->var_declarations->accept(*this);
 	symbol->function_block_body->accept(*this);
 	delete search_varfb_instance_type;
 	search_varfb_instance_type = NULL;
+
+	local_enumerated_value_symtable.reset();
 	return NULL;
 }
 
--- a/util/symtable.hh	Wed Oct 24 00:06:55 2012 +0200
+++ b/util/symtable.hh	Wed Nov 07 10:03:54 2012 +0000
@@ -77,11 +77,12 @@
   private:
       /* pointer to symbol table of the next inner scope */
     symtable_c *inner_scope;
-    void reset(void); /* clear all entries... */
 
   public:
     symtable_c(void);
 
+    void reset(void); /* clear all entries... */
+
     void push(void); /* create new inner scope */
     int  pop(void);  /* clear most inner scope */