mario@181: /*
msousa@265: * matiec - a compiler for the programming languages defined in IEC 61131-3
msousa@265: *
msousa@417: * Copyright (C) 2003-2012 Mario de Sousa (msousa@fe.up.pt)
Edouard@279: * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant
msousa@265: *
msousa@265: * This program is free software: you can redistribute it and/or modify
msousa@265: * it under the terms of the GNU General Public License as published by
msousa@265: * the Free Software Foundation, either version 3 of the License, or
msousa@265: * (at your option) any later version.
msousa@265: *
msousa@265: * This program is distributed in the hope that it will be useful,
msousa@265: * but WITHOUT ANY WARRANTY; without even the implied warranty of
msousa@265: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
msousa@265: * GNU General Public License for more details.
msousa@265: *
msousa@265: * You should have received a copy of the GNU General Public License
msousa@265: * along with this program. If not, see .
msousa@265: *
mario@181: *
mario@181: * This code is made available on the understanding that it will not be
mario@181: * used in safety-critical situations without a full and competent review.
mario@181: */
mario@181:
mario@181: /*
msousa@265: * An IEC 61131-3 compiler.
mario@181: *
mario@181: * Based on the
mario@181: * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
mario@181: *
mario@181: */
mario@181:
mario@181: /* Determine the data type of a variable.
mario@181: * The variable may be a simple variable, a function block instance, a
mario@181: * struture element within a data structured type (a struct or a fb), or
mario@181: * an array element.
mario@181: * A mixture of array element of a structure element of a structure element
mario@181: * of a .... is also suported!
mario@181: *
mario@181: * example:
mario@181: * window.points[1].coordinate.x
mario@181: * window.points[1].colour
mario@181: * etc... ARE ALLOWED!
mario@181: *
mario@181: * This class must be passed the scope within which the
mario@181: * variable was declared, and the variable name...
msousa@321: *
msousa@321: *
msousa@321: *
msousa@321: *
msousa@321: *
msousa@321: * This class has several members, depending on the exact data the caller
msousa@321: * is looking for...
msousa@321: *
msousa@321: * - item i: we can get either the name of the data type(A),
msousa@321: * or it's declaration (B)
msousa@321: * (notice however that some variables belong to a data type that does
msousa@321: * not have a name, only a declaration as in
msousa@321: * VAR a: ARRAY [1..3] of INT; END_VAR
msousa@321: * )
msousa@321: * - item ii: we can get either the direct data type (1),
msousa@321: * or the base type (2)
msousa@321: *
msousa@321: * By direct type, I mean the data type of the variable. By base type, I
msousa@321: * mean the data type on which the direct type is based on. For example, in
msousa@321: * a subrange on INT, the direct type is the subrange itself, while the
msousa@321: * base type is INT.
msousa@321: * e.g.
msousa@321: * This means that if we find that the variable is of type MY_INT,
msousa@321: * which was previously declared to be
msousa@321: * TYPE MY_INT: INT := 9;
msousa@321: * option (1) will return MY_INT
msousa@321: * option (2) will return INT
msousa@321: *
msousa@321: *
msousa@321: * Member functions:
msousa@321: * ================
msousa@417: * get_basetype_id() ---> returns 2A (implemented, although currently it is not needed! )
msousa@321: * get_basetype_decl() ---> returns 2B
msousa@321: * get_type_id() ---> returns 1A
msousa@321: *
msousa@417: * Since we haven't yet needed it, we don't yet implement
msousa@417: * get_type_decl() ---> returns 1B
msousa@321: */
mario@181:
mario@181:
msousa@417:
mario@181: #include "absyntax_utils.hh"
mario@181:
mario@181:
msousa@417: void search_varfb_instance_type_c::init(void) {
msousa@417: this->current_type_id = NULL;
msousa@417: this->current_basetype_id = NULL;
msousa@417: this->current_basetype_decl = NULL;
msousa@417: this->current_field_selector = NULL;
msousa@417: }
msousa@417:
msousa@417:
mario@181: search_varfb_instance_type_c::search_varfb_instance_type_c(symbol_c *search_scope): search_var_instance_decl(search_scope) {
msousa@417: this->init();
msousa@417: }
msousa@417:
msousa@417:
msousa@417: /* We expect to be passed a symbolic_variable_c */
msousa@417: symbol_c *search_varfb_instance_type_c::get_type_id(symbol_c *variable_name) {
msousa@417: this->init();
msousa@417: variable_name->accept(*this);
msousa@417: return current_type_id;
msousa@417: }
msousa@417:
msousa@417:
msousa@417: symbol_c *search_varfb_instance_type_c::get_basetype_id(symbol_c *variable_name) {
msousa@417: this->init();
msousa@417: variable_name->accept(*this);
msousa@417: return current_basetype_id;
mario@181: }
mario@181:
msousa@372:
msousa@372: symbol_c *search_varfb_instance_type_c::get_basetype_decl(symbol_c *variable_name) {
msousa@417: this->init();
msousa@417: variable_name->accept(*this);
msousa@417: return current_basetype_decl;
msousa@372: }
msousa@372:
msousa@372:
msousa@417:
msousa@417:
msousa@420: /*************************/
msousa@420: /* B.1 - Common elements */
msousa@420: /*************************/
msousa@420: /*******************************************/
msousa@420: /* B 1.1 - Letters, digits and identifiers */
msousa@420: /*******************************************/
msousa@420: // SYM_TOKEN(identifier_c)
msousa@420: void *search_varfb_instance_type_c::visit(identifier_c *variable_name) {
msousa@420: /* symbol should be a variable name!! */
msousa@420: /* 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! */
msousa@420: current_type_id = search_var_instance_decl.get_decl (variable_name);
msousa@718: current_basetype_decl = search_base_type_c::get_basetype_decl(current_type_id);
msousa@718: current_basetype_id = search_base_type_c::get_basetype_id (current_type_id);
msousa@420:
msousa@420: /* What if the variable has not been declared? Then this should not be a compiler error!
msousa@420: * However, currently stage 2 of the compiler already detects when variables have not been delcared,
msousa@420: * so if the variable's declaration is not found, then that means that we have an internal compiler error!
msousa@616: *
msousa@616: * Actually, the above is not true anymore. See the use of the any_symbolic_variable in iec_bison.yy
msousa@616: * - when defining the delay of a delayed action association in SFC
msousa@616: * - in program connections inside configurations (will this search_varfb_instance_type_c class be called to handle this??)
msousa@420: */
msousa@616: // if (NULL == current_type_id) ERROR;
msousa@420:
msousa@420: return NULL;
msousa@420: }
msousa@417:
msousa@417:
msousa@417:
msousa@417:
mario@181:
mario@181: /********************************/
mario@181: /* B 1.3.3 - Derived data types */
mario@181: /********************************/
mario@181: /* identifier ':' array_spec_init */
msousa@417: /* NOTE: I don't think this will ever get called, since in the visit method for array_variable_c
msousa@417: * we use the basetype_decl for recursively calling this class, and the base type should never be a
msousa@417: * array_type_declaration_c, but for now, let's leave it in...
msousa@417: */
mario@181: void *search_varfb_instance_type_c::visit(array_type_declaration_c *symbol) {
msousa@417: ERROR;
msousa@417: return NULL;
mario@181: }
mario@181:
laurent@238: /* array_specification [ASSIGN array_initialization] */
mario@181: /* array_initialization may be NULL ! */
msousa@417: /* NOTE: I don't think this will ever get called, since in the visit method for array_variable_c
msousa@417: * we use the basetype_decl for recursively calling this class, and the base type should never be a
msousa@417: * array_spec_init_c, but for now, let's leave it in...
msousa@417: */
mario@181: void *search_varfb_instance_type_c::visit(array_spec_init_c *symbol) {
msousa@417: /* Note that the 'array_specification' may be either an identifier of a previsously defined array type,
msousa@417: * or an array_specification_c, so we can not stop here and simply return a array_spec_init_c,
msousa@417: * especially if we are looking for the base class!
msousa@417: */
msousa@417: ERROR;
msousa@417: return NULL;
mario@181: }
laurent@238:
mario@181: /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */
msousa@417: /* NOTE: This method will be reached after being called from the
msousa@417: * search_varfb_instance_type_c::visit(array_variable_c *symbol)
msousa@417: * method, so we must return the data type of the data stored in the array,
msousa@417: * and not the data type of the array itself!
msousa@417: */
mario@181: void *search_varfb_instance_type_c::visit(array_specification_c *symbol) {
msousa@417: /* found the type of the element we were looking for! */
msousa@417: current_type_id = symbol->non_generic_type_name;
msousa@718: current_basetype_decl = search_base_type_c::get_basetype_decl(current_type_id);
msousa@718: current_basetype_id = search_base_type_c::get_basetype_id (current_type_id);
msousa@417:
msousa@417: return NULL;
msousa@417: }
msousa@417:
mario@181:
mario@181: /* structure_type_name ':' structure_specification */
msousa@371: /* NOTE: this is only used inside a TYPE ... END_TYPE declaration.
msousa@371: * It is never used directly when declaring a new variable!
msousa@371: */
msousa@417: /* NOTE: I don't think this will ever get called, since in the visit method for structured_variable_c
msousa@417: * we use the basetype_decl for recursively calling this class, and the base type should never be a
msousa@417: * structure_type_declaration_c, but for now, let's leave it in...
msousa@417: */
mario@181: void *search_varfb_instance_type_c::visit(structure_type_declaration_c *symbol) {
mjsousa@830: if (NULL == current_field_selector) return NULL; // the source code has a datatype consistency bug that will be caught later!!
mjsousa@830:
msousa@417: symbol->structure_specification->accept(*this);
msousa@417: return NULL;
mario@181: /* NOTE: structure_specification will point to either a
mario@181: * initialized_structure_c
mario@181: * OR A
mario@181: * structure_element_declaration_list_c
mario@181: */
mario@181: }
mario@181:
mario@181: /* structure_type_name ASSIGN structure_initialization */
mario@181: /* structure_initialization may be NULL ! */
mario@181: // SYM_REF2(initialized_structure_c, structure_type_name, structure_initialization)
msousa@417: /* NOTE: only the initialized structure is never used when declaring a new variable instance */
msousa@417: /* NOTE: I don't think this will ever get called, since in the visit method for structured_variable_c
msousa@417: * we use the basetype_decl for recursively calling this class, and the base type should never be a
msousa@417: * initialized_structure_c, but for now, let's leave it in...
msousa@417: */
mario@181: void *search_varfb_instance_type_c::visit(initialized_structure_c *symbol) {
mjsousa@830: if (NULL == current_field_selector) return NULL; // the source code has a datatype consistency bug that will be caught later!!
msousa@417:
msousa@417: /* recursively find out the data type of current_field_selector... */
msousa@417: symbol->structure_type_name->accept(*this);
msousa@417: return NULL;
laurent@382: }
laurent@382:
laurent@382: /* helper symbol for structure_declaration */
laurent@382: /* structure_declaration: STRUCT structure_element_declaration_list END_STRUCT */
laurent@382: /* structure_element_declaration_list structure_element_declaration ';' */
laurent@382: void *search_varfb_instance_type_c::visit(structure_element_declaration_list_c *symbol) {
mjsousa@830: if (NULL == current_field_selector) return NULL; // the source code has a datatype consistency bug that will be caught later!!
msousa@417:
laurent@382: /* now search the structure declaration */
msousa@417: for(int i = 0; i < symbol->n; i++) {
msousa@417: symbol->elements[i]->accept(*this);
msousa@417: }
msousa@619:
msousa@417: return NULL;
laurent@382: }
laurent@382:
laurent@382: /* structure_element_name ':' spec_init */
laurent@382: void *search_varfb_instance_type_c::visit(structure_element_declaration_c *symbol) {
mjsousa@830: if (NULL == current_field_selector) return NULL; // the source code has a datatype consistency bug that will be caught later!!
msousa@417:
msousa@417: if (compare_identifiers(symbol->structure_element_name, current_field_selector) == 0) {
laurent@382: /* found the type of the element we were looking for! */
msousa@417: current_type_id = symbol->spec_init;
msousa@718: current_basetype_decl = search_base_type_c::get_basetype_decl(current_type_id);
msousa@718: current_basetype_id = search_base_type_c::get_basetype_id (current_type_id);
laurent@382: }
laurent@382:
laurent@382: /* Did not find the type of the element we were looking for! */
laurent@382: /* Will keep looking... */
laurent@382: return NULL;
laurent@382: }
laurent@382:
laurent@382: /* helper symbol for structure_initialization */
laurent@382: /* structure_initialization: '(' structure_element_initialization_list ')' */
laurent@382: /* structure_element_initialization_list ',' structure_element_initialization */
laurent@382: void *search_varfb_instance_type_c::visit(structure_element_initialization_list_c *symbol) {ERROR; return NULL;} /* should never get called... */
laurent@382: /* structure_element_name ASSIGN value */
laurent@382: void *search_varfb_instance_type_c::visit(structure_element_initialization_c *symbol) {ERROR; return NULL;} /* should never get called... */
laurent@382:
laurent@382:
msousa@417: /*********************/
msousa@417: /* B 1.4 - Variables */
msousa@417: /*********************/
msousa@417: // SYM_REF1(symbolic_variable_c, var_name)
msousa@417: void *search_varfb_instance_type_c::visit(symbolic_variable_c *symbol) {
msousa@420: symbol->var_name->accept(*this);
msousa@417: return NULL;
msousa@417: }
msousa@417:
msousa@417: /********************************************/
msousa@417: /* B.1.4.1 Directly Represented Variables */
msousa@417: /********************************************/
msousa@417: // SYM_TOKEN(direct_variable_c)
msousa@417: /* We do not yet handle this. Will we ever need to handle it, as the data type of the direct variable is
msousa@417: * directly obtainable from the syntax of the direct variable itself?
msousa@417: */
msousa@417:
msousa@417: /*************************************/
msousa@417: /* B 1.4.2 - Multi-element variables */
msousa@417: /*************************************/
msousa@417: /* subscripted_variable '[' subscript_list ']' */
msousa@417: // SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
msousa@417: /* NOTE: when passed a array_variable_c, which represents some IEC61131-3 code similar to X[42]
msousa@417: * we must return the data type of the value _stored_ in the array.
msousa@417: * If you want to get the data type of the array itself (i.e. just the X variable, without the [42])
msousa@417: * then this class must be called with the identifier_c 'X'.
msousa@417: */
msousa@417: void *search_varfb_instance_type_c::visit(array_variable_c *symbol) {
msousa@417: /* determine the data type of the subscripted_variable...
msousa@417: * This should be an array_specification_c
msousa@417: * ARRAY [xx..yy] OF Stored_Data_Type
msousa@417: */
msousa@417: symbol->subscripted_variable->accept(*this);
msousa@619: symbol_c *basetype_decl = current_basetype_decl;
msousa@619: this->init(); /* set all current_*** pointers to NULL ! */
msousa@417:
msousa@417: /* Now we determine the 'Stored_Data_Type', i.e. the data type of the variable stored in the array. */
msousa@619: if (NULL != basetype_decl) {
msousa@619: basetype_decl->accept(*this);
msousa@417: }
msousa@417:
msousa@417: return NULL;
msousa@417: }
msousa@417:
msousa@417:
msousa@417: /* record_variable '.' field_selector */
msousa@417: /* WARNING: input and/or output variables of function blocks
msousa@417: * may be accessed as fields of a structured variable!
msousa@619: * Code handling a structured_variable_c must take this into account!
msousa@619: * (i.e. that a FB instance may be accessed as a structured variable)!
msousa@619: *
msousa@619: * WARNING: Status bit (.X) and activation time (.T) of STEPS in SFC diagrams
msousa@619: * may be accessed as fields of a structured variable!
msousa@619: * Code handling a structured_variable_c must take this into account
msousa@619: * (i.e. that an SFC STEP may be accessed as a structured variable)!
msousa@417: */
msousa@417: // SYM_REF2(structured_variable_c, record_variable, field_selector)
msousa@417: void *search_varfb_instance_type_c::visit(structured_variable_c *symbol) {
msousa@417: symbol->record_variable->accept(*this);
msousa@619: symbol_c *basetype_decl = current_basetype_decl;
msousa@619: this->init(); /* set all current_*** pointers to NULL ! */
msousa@417:
msousa@417: /* Now we search for the data type of the field... But only if we were able to determine the data type of the variable */
msousa@619: if (NULL != basetype_decl) {
msousa@417: current_field_selector = symbol->field_selector;
msousa@619: basetype_decl->accept(*this);
msousa@417: current_field_selector = NULL;
msousa@417: }
msousa@417:
msousa@417: return NULL;
msousa@417: }
msousa@417:
msousa@417:
laurent@382:
laurent@382: /**************************************/
laurent@382: /* B.1.5 - Program organization units */
laurent@382: /**************************************/
laurent@382: /*****************************/
laurent@382: /* B 1.5.2 - Function Blocks */
laurent@382: /*****************************/
msousa@417:
laurent@382: /* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
laurent@382: // SYM_REF4(function_block_declaration_c, fblock_name, var_declarations, fblock_body, unused)
laurent@382: void *search_varfb_instance_type_c::visit(function_block_declaration_c *symbol) {
mjsousa@830: if (NULL == current_field_selector) return NULL; // the source code has a datatype consistency bug that will be caught later!!
msousa@417:
msousa@417: /* now search the function block declaration for the variable... */
msousa@417: /* If not found, these pointers will all be set to NULL!! */
msousa@417: search_var_instance_decl_c search_decl(symbol);
msousa@417: current_type_id = search_decl.get_decl(current_field_selector);
msousa@718: current_basetype_decl = search_base_type_c::get_basetype_decl(current_type_id);
msousa@718: current_basetype_id = search_base_type_c::get_basetype_id (current_type_id);
msousa@417:
msousa@417: return NULL;
msousa@417: }
msousa@619:
msousa@619:
msousa@619:
msousa@619: /*********************************************/
msousa@619: /* B.1.6 Sequential function chart elements */
msousa@619: /*********************************************/
msousa@619: /* INITIAL_STEP step_name ':' action_association_list END_STEP */
msousa@619: // SYM_REF2(initial_step_c, step_name, action_association_list)
msousa@619: /* NOTE: this method may be called from visit(structured_variable_c *symbol) method| */
msousa@619: void *search_varfb_instance_type_c::visit(initial_step_c *symbol) {
mjsousa@830: if (NULL == current_field_selector) return NULL; // the source code has a datatype consistency bug that will be caught later!!
msousa@619:
msousa@619: identifier_c T("T");
msousa@619: identifier_c X("X");
msousa@619:
msousa@693: /* Hard code the datatypes of the implicit variables Stepname.X and Stepname.T */
msousa@619: if (compare_identifiers(&T, current_field_selector) == 0)
msousa@693: current_type_id = &get_datatype_info_c::time_type_name;
msousa@619: if (compare_identifiers(&X, current_field_selector) == 0)
msousa@693: current_type_id = &get_datatype_info_c::bool_type_name;
msousa@619:
msousa@718: current_basetype_decl = search_base_type_c::get_basetype_decl(current_type_id);
msousa@718: current_basetype_id = search_base_type_c::get_basetype_id (current_type_id);
msousa@619:
msousa@619: return NULL;
msousa@619: }
msousa@619:
msousa@619:
msousa@619: /* STEP step_name ':' action_association_list END_STEP */
msousa@619: // SYM_REF2(step_c, step_name, action_association_list)
msousa@619: /* NOTE: this method may be called from visit(structured_variable_c *symbol) method| */
msousa@619: void *search_varfb_instance_type_c::visit(step_c *symbol) {
msousa@619: /* The code here should be identicial to the code in the visit(initial_step_c *) visitor! So we simply call the other visitor! */
msousa@619: initial_step_c initial_step(NULL, NULL);
msousa@619: return initial_step.accept(*this);
msousa@619: }
mjsousa@936:
mjsousa@936:
mjsousa@936: /***************************************/
mjsousa@936: /* B.3 - Language ST (Structured Text) */
mjsousa@936: /***************************************/
mjsousa@936: /***********************/
mjsousa@936: /* B 3.1 - Expressions */
mjsousa@936: /***********************/
mjsousa@936: /* SYM_REF1(deref_expression_c, exp) --> an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Returns address of the varible! */
mjsousa@936: void *search_varfb_instance_type_c::visit(deref_expression_c *symbol) {
mjsousa@936: symbol->exp->accept(*this);
mjsousa@936: symbol_c *basetype_decl = current_basetype_decl;
mjsousa@936: this->init(); /* set all current_*** pointers to NULL ! */
mjsousa@936:
mjsousa@936: /* Check whether the expression if a REF_TO datatype, and if so, set the new datatype to the datatype it references! */
mjsousa@936: /* Determine whether the datatype is a ref_spec_c, as this is the class used as the */
mjsousa@936: /* canonical/base datatype of REF_TO types (see search_base_type_c ...) */
mjsousa@936: ref_spec_c * ref_spec = dynamic_cast(basetype_decl);
mjsousa@936: if (NULL != ref_spec) {
mjsousa@936: current_basetype_decl = search_base_type_c::get_basetype_decl(ref_spec->type_name);
mjsousa@936: current_basetype_id = search_base_type_c::get_basetype_id (ref_spec->type_name);
mjsousa@936: }
mjsousa@936:
mjsousa@936: return NULL;
mjsousa@936: }
mjsousa@936:
mjsousa@936:
mjsousa@936: /* SYM_REF1(deref_operator_c, exp) --> an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Returns address of the varible! */
mjsousa@936: void *search_varfb_instance_type_c::visit(deref_operator_c *symbol) {
mjsousa@936: symbol->exp->accept(*this);
mjsousa@936: symbol_c *basetype_decl = current_basetype_decl;
mjsousa@936: this->init(); /* set all current_*** pointers to NULL ! */
mjsousa@936:
mjsousa@936: /* Check whether the expression if a REF_TO datatype, and if so, set the new datatype to the datatype it references! */
mjsousa@936: /* Determine whether the datatype is a ref_spec_c, as this is the class used as the */
mjsousa@936: /* canonical/base datatype of REF_TO types (see search_base_type_c ...) */
mjsousa@936: ref_spec_c * ref_spec = dynamic_cast(basetype_decl);
mjsousa@936: if (NULL != ref_spec) {
mjsousa@936: current_basetype_decl = search_base_type_c::get_basetype_decl(ref_spec->type_name);
mjsousa@936: current_basetype_id = search_base_type_c::get_basetype_id (ref_spec->type_name);
mjsousa@936: }
mjsousa@936:
mjsousa@938: return NULL;
mjsousa@938: }