absyntax_utils/search_varfb_instance_type.cc
changeset 625 c0bda77b37a0
parent 412 aad38592bdde
parent 619 f8c9ac5c529a
child 693 51a2fa6441b9
--- a/absyntax_utils/search_varfb_instance_type.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/search_varfb_instance_type.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -1,7 +1,7 @@
 /*
  *  matiec - a compiler for the programming languages defined in IEC 61131-3
  *
- *  Copyright (C) 2003-2011  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2003-2012  Mario de Sousa (msousa@fe.up.pt)
  *  Copyright (C) 2007-2011  Laurent Bessard and Edouard Tisserant
  *
  *  This program is free software: you can redistribute it and/or modify
@@ -75,225 +75,143 @@
  *
  * Member functions:
  * ================
+ *   get_basetype_id()    ---> returns 2A   (implemented, although currently it is not needed! )
  *   get_basetype_decl()  ---> returns 2B 
  *   get_type_id()        ---> returns 1A
  * 
- *   Since we haven't yet needed them, we don't yet implement
- *   get_basetype_id()    ----> would return 2A
- *   get_type_decl()      ----> would return 1B
+ *   Since we haven't yet needed it, we don't yet implement
+ *   get_type_decl()      ---> returns 1B 
  */ 
 
 
-/*
- * TODO: this code has a memory leak...
- *       We call 'new' in several locations, but bever get to 'delete' the object instances...
- */
+
 #include "absyntax_utils.hh"
 
 
+void search_varfb_instance_type_c::init(void) {
+  this->current_type_id        = NULL;
+  this->current_basetype_id    = NULL;
+  this->current_basetype_decl  = NULL;
+  this->current_field_selector = NULL;
+}
+
+
 search_varfb_instance_type_c::search_varfb_instance_type_c(symbol_c *search_scope): search_var_instance_decl(search_scope) {
-  this->decompose_var_instance_name = NULL;
-  this->current_structelement_name = NULL;
-  this->current_typeid = NULL;
-  this->current_basetypeid = NULL;
-}
-
-symbol_c *search_varfb_instance_type_c::get_type_decl(symbol_c *variable_name) {
-  this->current_structelement_name = NULL;
-  this->current_typeid = NULL;
-  this->current_basetypeid = NULL;
-  this->decompose_var_instance_name = new decompose_var_instance_name_c(variable_name);
-  if (NULL == decompose_var_instance_name) ERROR;
-
-  /* find the part of the variable name that will appear in the
-   * variable declaration, for e.g., in window.point.x, this would be
-   * window!
+  this->init();
+}
+
+
+/* We expect to be passed a symbolic_variable_c */
+symbol_c *search_varfb_instance_type_c::get_type_id(symbol_c *variable_name) {
+  this->init();
+  variable_name->accept(*this);
+  return current_type_id;
+}
+
+
+symbol_c *search_varfb_instance_type_c::get_basetype_id(symbol_c *variable_name) {
+  this->init();
+  variable_name->accept(*this);
+  return current_basetype_id;
+}
+
+
+symbol_c *search_varfb_instance_type_c::get_basetype_decl(symbol_c *variable_name) {
+  this->init();
+  variable_name->accept(*this);
+  return current_basetype_decl;
+}  
+
+
+
+
+/*************************/
+/* B.1 - Common elements */
+/*************************/
+/*******************************************/
+/* B 1.1 - Letters, digits and identifiers */
+/*******************************************/
+// SYM_TOKEN(identifier_c)
+void *search_varfb_instance_type_c::visit(identifier_c *variable_name) {
+  /* symbol should be a variable name!! */
+  /* Note: although the method is called get_decl(), it is getting the declaration of the variable, which for us is the type_id of that variable! */
+  current_type_id       = search_var_instance_decl.get_decl (variable_name);
+  current_basetype_decl = search_base_type.get_basetype_decl(current_type_id);
+  current_basetype_id   = search_base_type.get_basetype_id  (current_type_id);
+    
+  /* What if the variable has not been declared?  Then this should not be a compiler error! 
+   * However, currently stage 2 of the compiler already detects when variables have not been delcared,
+   * so if the variable's declaration is not found, then that means that we have an internal compiler error!
+   * 
+   * Actually, the above is not true anymore. See the use of the any_symbolic_variable in iec_bison.yy
+   *  - when defining the delay of a delayed action association in SFC
+   *  - in program connections inside configurations (will this search_varfb_instance_type_c class be called to handle this??)
    */
-  symbol_c *var_name_part = decompose_var_instance_name->next_part();
-  if (NULL == var_name_part) ERROR;
-
-  /* Now we try to find the variable instance declaration, to determine its type... */
-  symbol_c *var_decl = search_var_instance_decl.get_decl(var_name_part);
-  if (NULL == var_decl) ERROR;
-
-  /* if it is a struct or function block, we must search the type
-   * of the struct or function block member.
-   * This is done by this class visiting the var_decl.
-   * This class, while visiting, will recursively call
-   * decompose_var_instance_name->get_next() when and if required...
-   */
-  symbol_c *res = (symbol_c *)var_decl->accept(*this);
-  /* NOTE: A Null result is not really an internal compiler error, but rather an error in 
-   * the IEC 61131-3 source code being compiled. This means we cannot just abort the compiler with ERROR.
-   * //   if (NULL == res) ERROR;
-   */
-  if (NULL == res) return NULL;
-
-  /* make sure that we have decomposed all structure elements of the variable name */
-  symbol_c *var_name = decompose_var_instance_name->next_part();
-  /* NOTE: A non-NULL result is not really an internal compiler error, but rather an error in 
-   * the IEC 61131-3 source code being compiled. 
-   *  (for example, 'int_var.struct_elem' in the source code, when 'int_var' is a simple integer,
-   *   and not a structure, will result in this result being non-NULL!)
-   * This means we cannot just abort the compiler with ERROR.
-   * //   if (NULL != var_name) ERROR;
-   */
-  if (NULL != var_name) return NULL;
-
-  return res;
-}
-
-
-symbol_c *search_varfb_instance_type_c::get_basetype_decl(symbol_c *variable_name) {
-  symbol_c *res = get_type_decl(variable_name);
-  if (NULL == res) return NULL;
-  return (symbol_c *)base_type(res);
-}  
-
-
-unsigned int search_varfb_instance_type_c::get_vartype(symbol_c *variable_name) {
-  this->current_structelement_name = NULL;
-  this->current_typeid = NULL;
-  this->current_basetypeid = NULL;
-  this->is_complex = false;
-  this->decompose_var_instance_name = new decompose_var_instance_name_c(variable_name);
-  if (NULL == decompose_var_instance_name) ERROR;
-
-  /* find the part of the variable name that will appear in the
-   * variable declaration, for e.g., in window.point.x, this would be
-   * window!
-   */
-  symbol_c *var_name_part = decompose_var_instance_name->next_part();
-  if (NULL == var_name_part) ERROR;
-
-  /* Now we try to find the variable instance declaration, to determine its type... */
-  symbol_c *var_decl = search_var_instance_decl.get_decl(var_name_part);
-  if (NULL == var_decl) {
-    /* variable instance declaration not found! */
-    return 0;
-  }
-
-  /* if it is a struct or function block, we must search the type
-   * of the struct or function block member.
-   * This is done by this class visiting the var_decl.
-   * This class, while visiting, will recursively call
-   * decompose_var_instance_name->get_next() when and if required...
-   */
-  var_decl->accept(*this);
-  unsigned int res = search_var_instance_decl.get_vartype();
-  
-  /* make sure that we have decomposed all structure elements of the variable name */
-  symbol_c *var_name = decompose_var_instance_name->next_part();
-  if (NULL != var_name) ERROR;
-
-  return res;
-}
-
-symbol_c *search_varfb_instance_type_c::get_type_id(symbol_c *variable_name) {
-  this->current_typeid = NULL;
-  symbol_c *vartype = this->get_type_decl(variable_name);
-  if (this->current_typeid != NULL)
-    return this->current_typeid;
-  else
-    return vartype;
-}
-
-bool search_varfb_instance_type_c::type_is_complex(void) {
-  return this->is_complex;
-}
-
-/* a helper function... */
-void *search_varfb_instance_type_c::visit_list(list_c *list)	{
-  if (NULL == current_structelement_name) ERROR;
-
-  for(int i = 0; i < list->n; i++) {
-    void *res = list->elements[i]->accept(*this);
-    if (res != NULL)
-      return res;
-  }
-  /* not found! */
-  return NULL;
-}
-
-/* a helper function... */
-void *search_varfb_instance_type_c::base_type(symbol_c *symbol)	{
-    search_base_type_c search_base_type;
-    return symbol->accept(search_base_type);
-}
-
-/* We override the base class' visitor to identifier_c.
- * This is so because the base class does not consider a function block
- * to be a type, unlike this class that allows a variable instance
- * of a function block type...
- */
-void *search_varfb_instance_type_c::visit(identifier_c *type_name) {
-  /* we only store the new type id if none had been found yet.
-   * Since we will recursively carry on looking at the base type 
-   * to determine the base type declaration and id, we must only set this variable
-   * the first time.
-   * e.g. TYPE myint1_t : int    := 1;
-   *           myint2_t : int1_t := 2;
-   *           myint3_t : int2_t := 3;
-   *      END_TYPE;
-   *      VAR
-   *          myint1 : myint1_t;
-   *          myint2 : myint2_t;
-   *          myint3 : myint3_t;
-   *      END_VAR
-   *        
-   *     If we ask for typeid of     myint3, it must return myint3_t
-   *     If we ask for basetypeid of myint3, it must return int
-   *
-   *     When determining the data type of myint3, we will recursively go all the way
-   *     down to int, but we must still only store myint3_t as the base type id.
-   */
-  if (NULL == this->current_typeid)
-    this->current_typeid = type_name;
-  this->current_basetypeid = type_name;
-
-  /* look up the type declaration... */
-  symbol_c *fb_decl = function_block_type_symtable.find_value(type_name);
-  if (fb_decl != function_block_type_symtable.end_value())
-    /* Type declaration found!! */
-    return fb_decl->accept(*this);
-
-  /* No. It is not a function block, so we let
-   * the base class take care of it...
-   */
-  return search_base_type_c::visit(type_name);
-}
+  // if (NULL == current_type_id) ERROR; 
+
+  return NULL;
+}
+
+
+
+
 
 /********************************/
 /* B 1.3.3 - Derived data types */
 /********************************/
-
 /*  identifier ':' array_spec_init */
+/* NOTE: I don't think this will ever get called, since in the visit method for array_variable_c
+ * we use the basetype_decl for recursively calling this class, and the base type should never be a 
+ * array_type_declaration_c, but for now, let's leave it in...
+ */
 void *search_varfb_instance_type_c::visit(array_type_declaration_c *symbol) {
-  return symbol->array_spec_init->accept(*this);
+  ERROR;
+  return NULL;
 }
     
 /* array_specification [ASSIGN array_initialization] */
 /* array_initialization may be NULL ! */
+/* NOTE: I don't think this will ever get called, since in the visit method for array_variable_c
+ * we use the basetype_decl for recursively calling this class, and the base type should never be a 
+ * array_spec_init_c, but for now, let's leave it in...
+ */
 void *search_varfb_instance_type_c::visit(array_spec_init_c *symbol) {
-  return symbol->array_specification->accept(*this);
+  /* Note that the 'array_specification' may be either an identifier of a previsously defined array type, 
+   * or an array_specification_c, so we can not stop here and simply return a array_spec_init_c, 
+   * especially if we are looking for the base class!
+   */
+  ERROR;
+  return NULL;
 }
 
 /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */
+/* NOTE: This method will be reached after being called from the 
+ * search_varfb_instance_type_c::visit(array_variable_c *symbol)
+ * method, so we must return the data type of the data stored in the array, 
+ * and not the data type of the array itself!
+ */
 void *search_varfb_instance_type_c::visit(array_specification_c *symbol) {
-  this->is_complex = true;
-  this->current_typeid = symbol;
-  return symbol->non_generic_type_name->accept(*this);
-}
+  /* found the type of the element we were looking for! */
+  current_type_id       = symbol->non_generic_type_name;
+  current_basetype_decl = search_base_type.get_basetype_decl(current_type_id);
+  current_basetype_id   = search_base_type.get_basetype_id  (current_type_id);
+    
+  return NULL; 
+}
+
 
 /*  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: I don't think this will ever get called, since in the visit method for structured_variable_c
+ * we use the basetype_decl for recursively calling this class, and the base type should never be a 
+ * structure_type_declaration_c, but for now, let's leave it in...
+ */
 void *search_varfb_instance_type_c::visit(structure_type_declaration_c *symbol) {
-  this->is_complex = true;
-
-  if (NULL == current_structelement_name) ERROR;
-  return symbol->structure_specification->accept(*this);
+  if (NULL == current_field_selector) ERROR;
+  symbol->structure_specification->accept(*this);
+  return NULL;
   /* NOTE: structure_specification will point to either a
    *       initialized_structure_c
    *       OR A
@@ -301,82 +219,45 @@
    */
 }
 
-/*  var1_list ':' structure_type_name */
-void *search_varfb_instance_type_c::visit(structured_var_declaration_c *symbol) {
-  this->is_complex = true;
-  if (NULL != current_structelement_name) ERROR;
-
-  /* make sure that we have decomposed all structure elements of the variable name */
-  symbol_c *var_name = decompose_var_instance_name->next_part();
-  if (NULL == var_name) {
-	/* this is it... !
-	 * No need to look any further...
-	 * Note also that, unlike for the struct types, a function block may
-	 * not be defined based on another (i.e. no inheritance is allowed),
-	 * so this function block is already the most base type.
-	 * We simply return it.
-	 */
-	return (void *)symbol;
-  }
-
-  /* reset current_type_id because of new structure element part */
-  this->current_typeid = NULL;
-
-  /* look for the var_name in the structure declaration */
-  current_structelement_name = var_name;
-
-  /* recursively find out the data type of current_structelement_name... */
-  return symbol->structure_type_name->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 ever used when declaring a new variable instance */
+/* NOTE: only the initialized structure is never used when declaring a new variable instance */
+/* NOTE: I don't think this will ever get called, since in the visit method for structured_variable_c
+ * we use the basetype_decl for recursively calling this class, and the base type should never be a 
+ * initialized_structure_c, but for now, let's leave it in...
+ */
 void *search_varfb_instance_type_c::visit(initialized_structure_c *symbol)	{
-  this->is_complex = true;
-  if (NULL != current_structelement_name) ERROR;
-  
-  /* make sure that we have decomposed all structure elements of the variable name */
-  symbol_c *var_name = decompose_var_instance_name->next_part();
-  if (NULL == var_name) {
-    /* this is it... !
-     * No need to look any further...
-     * Note also that, unlike for the struct types, a function block may
-     * not be defined based on another (i.e. no inheritance is allowed),
-     * so this function block is already the most base type.
-     * We simply return it.
-     */
-    return (void *)symbol;
-  }
-
-  /* reset current_type_id because of new structure element part */
-  this->current_typeid = NULL;
-
-  /* look for the var_name in the structure declaration */
-  current_structelement_name = var_name;
-
-  /* recursively find out the data type of current_structelement_name... */
-  return symbol->structure_type_name->accept(*this);
+  if (NULL != current_field_selector) ERROR;
+  
+  /* recursively find out the data type of current_field_selector... */
+  symbol->structure_type_name->accept(*this);
+  return NULL;
 }
 
 /* helper symbol for structure_declaration */
 /* structure_declaration:  STRUCT structure_element_declaration_list END_STRUCT */
 /* structure_element_declaration_list structure_element_declaration ';' */
 void *search_varfb_instance_type_c::visit(structure_element_declaration_list_c *symbol)	{
-  if (NULL == current_structelement_name) ERROR;
+  if (NULL == current_field_selector) ERROR;
+
   /* now search the structure declaration */
-  return visit_list(symbol);
+  for(int i = 0; i < symbol->n; i++) {
+    symbol->elements[i]->accept(*this);
+  }
+
+  return NULL;
 }
 
 /*  structure_element_name ':' spec_init */
 void *search_varfb_instance_type_c::visit(structure_element_declaration_c *symbol) {
-  if (NULL == current_structelement_name) ERROR;
-
-  if (compare_identifiers(symbol->structure_element_name, current_structelement_name) == 0) {
-    current_structelement_name = NULL;
+  if (NULL == current_field_selector) ERROR;
+
+  if (compare_identifiers(symbol->structure_element_name, current_field_selector) == 0) {
     /* found the type of the element we were looking for! */
-    return symbol->spec_init->accept(*this);
+    current_type_id       = symbol->spec_init;
+    current_basetype_decl = search_base_type.get_basetype_decl(current_type_id);
+    current_basetype_id   = search_base_type.get_basetype_id  (current_type_id);
   }  
 
   /* Did not find the type of the element we were looking for! */
@@ -392,6 +273,79 @@
 void *search_varfb_instance_type_c::visit(structure_element_initialization_c *symbol) {ERROR; return NULL;} /* should never get called... */
 
 
+/*********************/
+/* B 1.4 - Variables */
+/*********************/
+// SYM_REF1(symbolic_variable_c, var_name)
+void *search_varfb_instance_type_c::visit(symbolic_variable_c *symbol) {
+  symbol->var_name->accept(*this);
+  return NULL;
+}
+
+/********************************************/
+/* B.1.4.1   Directly Represented Variables */
+/********************************************/
+// SYM_TOKEN(direct_variable_c)
+/* We do not yet handle this. Will we ever need to handle it, as the data type of the direct variable is
+ * directly obtainable from the syntax of the direct variable itself?
+ */
+
+/*************************************/
+/* B 1.4.2 - Multi-element variables */
+/*************************************/
+/*  subscripted_variable '[' subscript_list ']' */
+// SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
+/* NOTE: when passed a array_variable_c, which represents some IEC61131-3 code similar to X[42]
+ * we must return the data type of the value _stored_ in the array.
+ * If you want to get the data type of the array itself (i.e. just the X variable, without the [42])
+ * then this class must be called with the identifier_c 'X'.
+ */
+void *search_varfb_instance_type_c::visit(array_variable_c *symbol) {
+  /* determine the data type of the subscripted_variable... 
+   * This should be an array_specification_c
+   *    ARRAY [xx..yy] OF Stored_Data_Type
+   */
+  symbol->subscripted_variable->accept(*this);
+  symbol_c *basetype_decl = current_basetype_decl;
+  this->init(); /* set all current_*** pointers to NULL ! */
+  
+  /* Now we determine the 'Stored_Data_Type', i.e. the data type of the variable stored in the array. */
+  if (NULL != basetype_decl) {
+    basetype_decl->accept(*this);
+  }
+  
+  return NULL;
+}
+
+
+/*  record_variable '.' field_selector */
+/*  WARNING: input and/or output variables of function blocks
+ *           may be accessed as fields of a structured variable!
+ *           Code handling a structured_variable_c must take this into account!
+ *           (i.e. that a FB instance may be accessed as a structured variable)!
+ *
+ *  WARNING: Status bit (.X) and activation time (.T) of STEPS in SFC diagrams
+ *           may be accessed as fields of a structured variable!
+ *           Code handling a structured_variable_c must take this into account 
+ *           (i.e. that an SFC STEP may be accessed as a structured variable)!
+ */
+// SYM_REF2(structured_variable_c, record_variable, field_selector)
+void *search_varfb_instance_type_c::visit(structured_variable_c *symbol) {
+  symbol->record_variable->accept(*this);
+  symbol_c *basetype_decl = current_basetype_decl;
+  this->init(); /* set all current_*** pointers to NULL ! */
+  
+  /* Now we search for the data type of the field... But only if we were able to determine the data type of the variable */
+  if (NULL != basetype_decl) {
+    current_field_selector = symbol->field_selector;
+    basetype_decl->accept(*this);
+    current_field_selector = NULL;
+  }
+  
+  return NULL;
+}
+
+
 
 /**************************************/
 /* B.1.5 - Program organization units */
@@ -399,46 +353,53 @@
 /*****************************/
 /* 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 *search_varfb_instance_type_c::visit(function_block_declaration_c *symbol) {
-  /* make sure that we have decomposed all structure elements of the variable name */
-  symbol_c *var_name = decompose_var_instance_name->next_part();
-  if (NULL == var_name) {
-    /* this is it... !
-     * No need to look any further...
-     * Note also that, unlike for the struct types, a function block may
-     * not be defined based on another (i.e. no inheritance is allowed),
-     * so this function block is already the most base type.
-     * We simply return it.
-     */
-    return (void *)symbol;
-   }
-
-   /* reset current_type_id because of new structure element part */
-   this->current_typeid = NULL;
-
-   /* now search the function block declaration for the variable... */
-   search_var_instance_decl_c search_decl(symbol);
-   symbol_c *var_decl = search_decl.get_decl(var_name);
-   if (NULL == var_decl) {
-     /* variable instance declaration not found! */
-     return NULL;
-   }
-#if 0
-   /* We have found the declaration.
-    * Should we look any further?
-    */
-   var_name = decompose_var_instance_name->next_part();
-   if (NULL == var_name) {
-     /* this is it... ! */
-     return base_type(var_decl);
-   }
-
-  current_structelement_name = var_name;
-  /* recursively find out the data type of var_name... */
-  return symbol->var_declarations->accept(*this);
-#endif
-  /* carry on recursively, in case the variable has more elements to be decomposed... */
-  return var_decl->accept(*this);
-}
+  if (NULL == current_field_selector) ERROR;
+
+  /* now search the function block declaration for the variable... */
+  /* If not found, these pointers will all be set to NULL!! */
+  search_var_instance_decl_c search_decl(symbol);
+  current_type_id       = search_decl.get_decl(current_field_selector);
+  current_basetype_decl = search_base_type.get_basetype_decl(current_type_id);
+  current_basetype_id   = search_base_type.get_basetype_id  (current_type_id);
+  
+  return NULL;
+}
+
+
+
+/*********************************************/
+/* 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)
+/* NOTE: this method may be called from visit(structured_variable_c *symbol) method| */
+void *search_varfb_instance_type_c::visit(initial_step_c *symbol) {
+  if (NULL == current_field_selector) ERROR;
+
+  identifier_c T("T");
+  identifier_c X("X");
+  
+  if (compare_identifiers(&T, current_field_selector) == 0)   
+    current_type_id = &search_constant_type_c::time_type_name;
+  if (compare_identifiers(&X, current_field_selector) == 0)   
+    current_type_id = &search_constant_type_c::bool_type_name;
+  
+  current_basetype_decl = search_base_type.get_basetype_decl(current_type_id);
+  current_basetype_id   = search_base_type.get_basetype_id  (current_type_id);
+
+  return NULL;
+}
+
+
+/* STEP step_name ':' action_association_list END_STEP */
+// SYM_REF2(step_c, step_name, action_association_list)
+/* NOTE: this method may be called from visit(structured_variable_c *symbol) method| */
+void *search_varfb_instance_type_c::visit(step_c *symbol) {
+  /* The code here should be identicial to the code in the visit(initial_step_c *) visitor! So we simply call the other visitor! */
+  initial_step_c initial_step(NULL, NULL);
+  return initial_step.accept(*this);
+}