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: }