Do the full fill_candidate/narrow_datatype algorithm for all fields of a structured variable in the fill_candidate_datatypes_c
authormjsousa
Sun, 19 Oct 2014 21:30:58 +0100
changeset 938 31e3b3f2eff1
parent 937 887e7d90445a
child 939 5074236fb3c4
Do the full fill_candidate/narrow_datatype algorithm for all fields of a structured variable in the fill_candidate_datatypes_c
Allows us to remove temporary code from the search_varfb_decl_c
absyntax/absyntax.hh
absyntax_utils/get_datatype_info.cc
absyntax_utils/get_datatype_info.hh
absyntax_utils/search_varfb_instance_type.cc
stage3/fill_candidate_datatypes.cc
--- a/absyntax/absyntax.hh	Sun Oct 19 11:53:36 2014 +0100
+++ b/absyntax/absyntax.hh	Sun Oct 19 21:30:58 2014 +0100
@@ -136,6 +136,8 @@
     symbol_c *datatype;
     /* The POU in which the symbolic variable (or structured variable, or array variable, or located variable, - any more?)
      * was declared. This will point to a Configuration, Resource, Program, FB, or Function.
+     * This is set in stage 3 by the datatype analyser algorithm (fill/narrow) for the symbols:
+     *  symbolic_variable_c, array_variable_c, structured_variable_c
      */
     symbol_c *scope;    
 
--- a/absyntax_utils/get_datatype_info.cc	Sun Oct 19 11:53:36 2014 +0100
+++ b/absyntax_utils/get_datatype_info.cc	Sun Oct 19 21:30:58 2014 +0100
@@ -62,7 +62,12 @@
 /**********************************************************/
 /**********************************************************/
 
+
+/****************************************************************************************************/
+/****************************************************************************************************/
 /* Return the identifier (name) of a datatype, typically declared in a TYPE .. END_TYPE declaration */
+/****************************************************************************************************/
+/****************************************************************************************************/
 class get_datatype_id_c: null_visitor_c {
   private:
     static get_datatype_id_c *singleton;
@@ -157,9 +162,13 @@
 
 
 
-/***********************************************************************/
-/***********************************************************************/
-
+
+
+/**************************************************/
+/**************************************************/
+/* transform elementary data type class to string */
+/**************************************************/
+/**************************************************/
 
 /* A small helper class, to transform elementary data type to string.
  * this allows us to generate more relevant error messages...
@@ -273,6 +282,115 @@
 
 
 
+/*********************************************************/
+/*********************************************************/
+/* get the datatype of a field inside a struct data type */
+/*********************************************************/
+/*********************************************************/
+
+class get_struct_info_c : null_visitor_c {
+  private:
+    symbol_c *current_field;
+    /* singleton class! */
+    static get_struct_info_c *singleton;
+
+  public:
+    get_struct_info_c(void) {current_field = NULL;}
+
+    static symbol_c *get_field_type_id(symbol_c *struct_type, symbol_c *field_name) {
+      if (NULL == singleton)    singleton = new get_struct_info_c;
+      if (NULL == singleton)    ERROR;
+      singleton->current_field = field_name;
+      return (symbol_c *)struct_type->accept(*singleton);
+    }
+
+
+  private:
+    /*************************/
+    /* B.1 - Common elements */
+    /*************************/
+    /********************************/
+    /* B 1.3.3 - Derived data types */
+    /********************************/
+    /*  structure_type_name ':' structure_specification */
+    /* NOTE: this is only used inside a TYPE ... END_TYPE declaration.  It is never used directly when declaring a new variable! */
+    /* NOTE: structure_specification will point to either initialized_structure_c  OR  structure_element_declaration_list_c */
+    void *visit(structure_type_declaration_c *symbol) {return symbol->structure_specification->accept(*this);}
+
+    /* structure_type_name ASSIGN structure_initialization */
+    /* structure_initialization may be NULL ! */
+    // SYM_REF2(initialized_structure_c, structure_type_name, structure_initialization)
+    /* NOTE: only the initialized structure is never used when declaring a new variable instance */
+    void *visit(initialized_structure_c *symbol) {return symbol->structure_type_name->accept(*this);}
+
+    /* helper symbol for structure_declaration */
+    /* structure_declaration:  STRUCT structure_element_declaration_list END_STRUCT */
+    /* structure_element_declaration_list structure_element_declaration ';' */
+    void *visit(structure_element_declaration_list_c *symbol) {
+      /* now search the structure declaration */
+      for(int i = 0; i < symbol->n; i++) {
+        void *tmp = symbol->elements[i]->accept(*this);
+        if (NULL != tmp) return tmp;
+      }
+      return NULL; // not found!!
+    }  
+
+    /*  structure_element_name ':' spec_init */
+    void *visit(structure_element_declaration_c *symbol) {
+      if (compare_identifiers(symbol->structure_element_name, current_field) == 0)
+        return symbol->spec_init; /* found the type of the element we were looking for! */
+      return NULL;   /* not the element we are looking for! */
+    }
+      
+
+    /* helper symbol for structure_initialization */
+    /* structure_initialization: '(' structure_element_initialization_list ')' */
+    /* structure_element_initialization_list ',' structure_element_initialization */
+    void *visit(structure_element_initialization_list_c *symbol) {ERROR; return NULL;} /* should never get called... */
+    /*  structure_element_name ASSIGN value */
+    void *visit(structure_element_initialization_c *symbol) {ERROR; return NULL;} /* should never get called... */
+
+
+    /**************************************/
+    /* B.1.5 - Program organization units */
+    /**************************************/
+    /*****************************/
+    /* B 1.5.2 - Function Blocks */
+    /*****************************/
+    /*  FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
+    // SYM_REF4(function_block_declaration_c, fblock_name, var_declarations, fblock_body, unused)
+    void *visit(function_block_declaration_c *symbol) {
+      /* now search the function block declaration for the variable... */
+      search_var_instance_decl_c search_decl(symbol);
+      return search_decl.get_decl(current_field);
+    }
+      
+    /*********************************************/
+    /* B.1.6  Sequential function chart elements */
+    /*********************************************/
+    /* INITIAL_STEP step_name ':' action_association_list END_STEP */
+    // SYM_REF2(initial_step_c, step_name, action_association_list)
+    void *visit(initial_step_c *symbol) {
+      identifier_c T("T");  identifier_c X("X");
+      /* Hard code the datatypes of the implicit variables Stepname.X and Stepname.T */
+      if (compare_identifiers(&T, current_field) == 0)  return &get_datatype_info_c::time_type_name;
+      if (compare_identifiers(&X, current_field) == 0)  return &get_datatype_info_c::bool_type_name;
+      return NULL;
+    }
+      
+    /* STEP step_name ':' action_association_list END_STEP */
+    // SYM_REF2(step_c, step_name, action_association_list)
+    /* The code here should be identicial to the code in the visit(initial_step_c *) visitor! So we simply call the other visitor! */
+    void *visit(step_c *symbol) {initial_step_c initial_step(NULL, NULL); return initial_step.accept(*this);}
+      
+}; // get_struct_info_c
+
+get_struct_info_c *get_struct_info_c::singleton = NULL;
+
+
+
+
+
 /**********************************************************/
 /**********************************************************/
 /**********************************************************/
@@ -295,6 +413,10 @@
 }
 
 
+symbol_c *get_datatype_info_c::get_struct_field_type_id(symbol_c *struct_datatype, symbol_c *struct_fieldname) {
+  return get_struct_info_c::get_field_type_id(struct_datatype, struct_fieldname);
+}
+
 /* Returns true if both datatypes are equivalent (not necessarily equal!).
  * WARNING: May return true even though the datatypes are not the same/identicial!!!
  *          This occurs when at least one of the datatypes is of a generic
--- a/absyntax_utils/get_datatype_info.hh	Sun Oct 19 11:53:36 2014 +0100
+++ b/absyntax_utils/get_datatype_info.hh	Sun Oct 19 21:30:58 2014 +0100
@@ -60,6 +60,7 @@
     static symbol_c   *get_id    (symbol_c *datatype); /* get the identifier (name) of the datatype); returns NULL if anonymous datatype! Does not work for elementary datatypes!*/
     static const char *get_id_str(symbol_c *datatype); /* get the identifier (name) of the datatype); returns NULL if anonymous datatype! */
 
+    static symbol_c *get_struct_field_type_id      (symbol_c *struct_datatype, symbol_c *struct_fieldname);
     static symbol_c *get_ref_to                    (symbol_c *type_symbol);    // Defined in IEC 61131-3 v3 (returns the type that is being referenced/pointed to)        
     
     /* Returns true if both datatypes are equivalent (not necessarily equal!).
--- a/absyntax_utils/search_varfb_instance_type.cc	Sun Oct 19 11:53:36 2014 +0100
+++ b/absyntax_utils/search_varfb_instance_type.cc	Sun Oct 19 21:30:58 2014 +0100
@@ -428,13 +428,6 @@
     current_basetype_id   = search_base_type_c::get_basetype_id  (ref_spec->type_name);
   }
   
-/* ########### WARNING ########################################################## */
-/* The following two lines DO NOT belong here. It is just a temporary measure until I get the chance 
- * to clean this up, and move it to fill/narrow candidate datatypes in stage 3 
- */
-  symbol->datatype = current_basetype_decl;
-  symbol->exp->datatype = ref_spec;
-  
   return NULL;
 }
 
@@ -454,12 +447,5 @@
     current_basetype_id   = search_base_type_c::get_basetype_id  (ref_spec->type_name);
   }
   
-/* ########### WARNING ########################################################## */
-/* The following two lines DO NOT belong here. It is just a temporary measure until I get the chance 
- * to clean this up, and move it to fill/narrow candidate datatypes in stage 3 
- */
-  symbol->datatype = current_basetype_decl;
-  symbol->exp->datatype = ref_spec;
-  
-  return NULL;
-}
+  return NULL;
+}
--- a/stage3/fill_candidate_datatypes.cc	Sun Oct 19 11:53:36 2014 +0100
+++ b/stage3/fill_candidate_datatypes.cc	Sun Oct 19 21:30:58 2014 +0100
@@ -1170,7 +1170,14 @@
 /* B 1.4 - Variables */
 /*********************/
 void *fill_candidate_datatypes_c::visit(symbolic_variable_c *symbol) {
-	add_datatype_to_candidate_list(symbol, search_varfb_instance_type->get_basetype_decl(symbol)); /* will only add if non NULL */
+	/*  NOTE: We need to fully determine the datatype of each element in the structured_variable inside this fill_candidate_datatypes class!
+	 *        Basically, for variables (be they symbolic_variable, structured_variable, array_variable), we do the narrow algorithm
+	 *        in this fill_candidate_datatypes_c itself!
+	 *        This is needed because we need to know in which scope (i.e. the datatype of the recor_variable in a structtured_variable_c)
+	 *        we will search for the field_variable of the structured_variable_c
+	 */
+	symbol->datatype = search_varfb_instance_type->get_basetype_decl(symbol); // Do the narrow algorithm in this fill_candidate_datatypes_c!!
+	add_datatype_to_candidate_list(symbol, symbol->datatype); /* will only add if non NULL */
 	if (debug) std::cout << "VAR [" << symbol->candidate_datatypes.size() << "]\n";
 	return NULL;
 }
@@ -1211,7 +1218,17 @@
 	 * search_varfb_instance_type->get_basetype_decl(symbol->subscripted_variable)
 	 */
 	add_datatype_to_candidate_list(symbol, search_varfb_instance_type->get_basetype_decl(symbol));   /* will only add if non NULL */
-	
+
+	/*  NOTE: We need to fully determine the datatype of each element in the structured_variable inside this fill_candidate_datatypes class!
+	 *        Basically, for variables (be they symbolic_variable, structured_variable, array_variable), we do the narrow algorithm
+	 *        in this fill_candidate_datatypes_c itself!
+	 *        This is needed because we need to know in which scope (i.e. the datatype of the recor_variable in a structtured_variable_c)
+	 *        we will search for the field_variable of the structured_variable_c
+	 */
+	if (symbol->candidate_datatypes.size() == 1)
+	  // narrow the symbol->datatype for this strcutured_variable as explained above!
+	  symbol->datatype = symbol->candidate_datatypes[0];
+
 	/* recursively call the subscript list, so we can check the data types of the expressions used for the subscripts */
 	symbol->subscript_list->accept(*this);
 
@@ -1252,17 +1269,25 @@
  */
 // SYM_REF2(structured_variable_c, record_variable, field_selector)
 void *fill_candidate_datatypes_c::visit(structured_variable_c *symbol) {
-	/* NOTE: We do not need to recursively determine the data types of each field_selector, as the search_varfb_instance_type
-	 * will do that for us. So we determine the candidate datatypes only for the full structured_variable.
-	 */
-	add_datatype_to_candidate_list(symbol, search_varfb_instance_type->get_basetype_decl(symbol));  /* will only add if non NULL */
-	/* However, we do need to visit each record type recursively!
-	 * Remember that a structured variable may be stored inside an array (e.g. arrayvar[33].elem1)
+	/* Remember that a structured variable may be stored inside an array (e.g. arrayvar[33].elem1)
 	 * The array subscripts may contain a complex expression (e.g. arrayvar[ varx + 33].elem1) whose datatype must be correctly determined!
 	 * The expression, may even contain a function call to an overloaded function!
 	 *      (e.g.  arrayvar[ varx + TRUNC(realvar)].elem1)
 	 */
 	symbol->record_variable->accept(*this);
+	
+	/*  NOTE: We need to fully determine the datatype of each element in the structured_variable inside this fill_candidate_datatypes class!
+	 *        Basically, for variables (be they symbolic_variable, structured_variable, array_variable), we do the narrow algorithm
+	 *        in this fill_candidate_datatypes_c itself!
+	 *        This is needed because we need to know in which scope (i.e. the datatype of the recor_variable in a structtured_variable_c)
+	 *        we will search for the field_variable of the structured_variable_c
+	 */
+	if (NULL != symbol->record_variable->datatype) 
+	  // We relly on the fact that we have already narrowed the symbol->datatype for the record variable, and use it as the scope in which the filed_variable is declared!
+	  add_datatype_to_candidate_list(symbol, search_base_type_c::get_basetype_decl(get_datatype_info_c::get_struct_field_type_id(symbol->record_variable->datatype, symbol->field_selector)));  /* will only add if non NULL */
+	if (symbol->candidate_datatypes.size() == 1)
+	  // narrow the symbol->datatype for this strcutured_variable as explained above!
+	  symbol->datatype = symbol->candidate_datatypes[0];
 	return NULL;
 }
 
@@ -1917,7 +1942,20 @@
     
     if (NULL != ref_spec)
       add_datatype_to_candidate_list(symbol, search_base_type_c::get_basetype_decl(ref_spec->type_name));
+    
   }
+
+  /*  NOTE: We need to fully determine the datatype of each element in the structured_variable inside this fill_candidate_datatypes class!
+   *        Basically, for variables (be they symbolic_variable, structured_variable, array_variable), we do the narrow algorithm
+   *        in this fill_candidate_datatypes_c itself!
+   *        This is needed because we need to know in which scope (i.e. the datatype of the recor_variable in a structtured_variable_c)
+   *        we will search for the field_variable of the structured_variable_c
+   * 
+   *        Since the deref_operator_c may be used inside structures, we must narrow it here, if possible!
+   */
+  if (symbol->candidate_datatypes.size() == 1)
+    // narrow the symbol->datatype for this symbol as explained above!
+    symbol->datatype = symbol->candidate_datatypes[0];
   
   return NULL;
 }