mario@181: /* msousa@265: * matiec - a compiler for the programming languages defined in IEC 61131-3 msousa@265: * msousa@265: * Copyright (C) 2003-2011 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: mario@181: /* mario@181: * Determine the default initial value of a type declaration. mario@181: * mario@181: * This is part of the 4th stage that generates mario@181: * a c++ source program equivalent to the IL and ST mario@181: * code. mario@181: */ mario@181: mario@181: /* Given a type definition declration, determine its default mario@181: * initial value. Note that types based on other types mario@181: * may have to iterate through each type it is based on mario@181: * to determine the initial value. mario@181: * E.g. mario@181: * TYPE mario@181: * A_t : INT := 10; mario@181: * B_t : A_t := 20; mario@181: * C_t : B_t; mario@181: * D_t : C_t := 40; mario@181: * END_TYPE mario@181: * Where the default initial value for C_t is 20! mario@181: */ mario@181: /* NOTE: The main program only needs one instance of mario@181: * this class of object. This class mario@181: * is therefore a singleton. mario@181: */ mario@181: mario@181: class type_initial_value_c : public null_visitor_c { mario@181: msousa@762: public: msousa@762: static symbol_c *get(symbol_c *type); msousa@762: mario@181: private: mario@181: /* constants for the default values of elementary data types... */ mjsousa@925: static ref_value_null_literal_c *null_literal; mjsousa@925: static real_c *real_0; mjsousa@925: static integer_c *integer_0, *integer_1; mjsousa@925: static boolean_literal_c *bool_0; mjsousa@925: static date_literal_c *date_literal_0; mjsousa@925: static daytime_c *daytime_literal_0; mjsousa@925: static duration_c *time_0; mjsousa@925: static date_c *date_0; mjsousa@925: static time_of_day_c *tod_0; mjsousa@925: static date_and_time_c *dt_0; mario@181: static single_byte_character_string_c *string_0; mario@181: static double_byte_character_string_c *wstring_0; mario@181: mario@181: protected: mario@181: type_initial_value_c(void); mario@181: mario@181: private: msousa@762: static type_initial_value_c *_instance; msousa@762: static type_initial_value_c *instance(void); mario@181: void *handle_type_spec(symbol_c *base_type_name, symbol_c *type_spec_init); mario@181: mario@181: private: mjsousa@945: void *visit( identifier_c *type_name); mjsousa@945: void *visit(derived_datatype_identifier_c *type_name); mario@181: mario@181: /***********************************/ mario@181: /* B 1.3.1 - Elementary Data Types */ mario@181: /***********************************/ mario@181: void *visit(time_type_name_c *symbol); mario@181: void *visit(bool_type_name_c *symbol); mario@181: void *visit(sint_type_name_c *symbol); mario@181: void *visit(int_type_name_c *symbol); mario@181: void *visit(dint_type_name_c *symbol); mario@181: void *visit(lint_type_name_c *symbol); mario@181: void *visit(usint_type_name_c *symbol); mario@181: void *visit(uint_type_name_c *symbol); mario@181: void *visit(udint_type_name_c *symbol); mario@181: void *visit(ulint_type_name_c *symbol); mario@181: void *visit(real_type_name_c *symbol); mario@181: void *visit(lreal_type_name_c *symbol); mario@181: void *visit(date_type_name_c *symbol); mario@181: void *visit(tod_type_name_c *symbol); mario@181: void *visit(dt_type_name_c *symbol); mario@181: void *visit(byte_type_name_c *symbol); mario@181: void *visit(word_type_name_c *symbol); mario@181: void *visit(dword_type_name_c *symbol); mario@181: void *visit(lword_type_name_c *symbol); mario@181: void *visit(string_type_name_c *symbol); mario@181: void *visit(wstring_type_name_c *symbol); mario@181: msousa@257: void *visit(safetime_type_name_c *symbol); msousa@257: void *visit(safebool_type_name_c *symbol); msousa@257: void *visit(safesint_type_name_c *symbol); msousa@257: void *visit(safeint_type_name_c *symbol); msousa@257: void *visit(safedint_type_name_c *symbol); msousa@257: void *visit(safelint_type_name_c *symbol); msousa@257: void *visit(safeusint_type_name_c *symbol); msousa@257: void *visit(safeuint_type_name_c *symbol); msousa@257: void *visit(safeudint_type_name_c *symbol); msousa@257: void *visit(safeulint_type_name_c *symbol); msousa@257: void *visit(safereal_type_name_c *symbol); msousa@257: void *visit(safelreal_type_name_c *symbol); msousa@257: void *visit(safedate_type_name_c *symbol); msousa@257: void *visit(safetod_type_name_c *symbol); msousa@257: void *visit(safedt_type_name_c *symbol); msousa@257: void *visit(safebyte_type_name_c *symbol); msousa@257: void *visit(safeword_type_name_c *symbol); msousa@257: void *visit(safedword_type_name_c *symbol); msousa@257: void *visit(safelword_type_name_c *symbol); msousa@257: void *visit(safestring_type_name_c *symbol); msousa@257: void *visit(safewstring_type_name_c *symbol); msousa@257: mario@181: /********************************/ mario@181: /* B 1.3.3 - Derived data types */ mario@181: /********************************/ mario@181: /* simple_type_name ':' simple_spec_init */ mario@181: void *visit(simple_type_declaration_c *symbol); mario@181: mario@181: /* simple_specification ASSIGN constant */ mario@181: void *visit(simple_spec_init_c *symbol); mario@181: mario@181: /* subrange_type_name ':' subrange_spec_init */ mario@181: void *visit(subrange_type_declaration_c *symbol); mario@181: mario@181: /* subrange_specification ASSIGN signed_integer */ mario@181: void *visit(subrange_spec_init_c *symbol); mario@181: mario@181: /* integer_type_name '(' subrange')' */ mario@181: void *visit(subrange_specification_c *symbol); mario@181: mario@181: /* signed_integer DOTDOT signed_integer */ mario@181: void *visit(subrange_c *symbol); mario@181: mario@181: /* enumerated_type_name ':' enumerated_spec_init */ mario@181: void *visit(enumerated_type_declaration_c *symbol); mario@181: mario@181: /* enumerated_specification ASSIGN enumerated_value */ mario@181: void *visit(enumerated_spec_init_c *symbol); mario@181: mario@181: /* helper symbol for enumerated_specification->enumerated_spec_init */ mario@181: /* enumerated_value_list ',' enumerated_value */ mario@181: void *visit(enumerated_value_list_c *symbol); mario@181: mario@181: /* enumerated_type_name '#' identifier */ mario@181: // SYM_REF2(enumerated_value_c, type, value) mario@181: void *visit(enumerated_value_c *symbol); mario@181: mario@181: /* identifier ':' array_spec_init */ mario@181: void *visit(array_type_declaration_c *symbol); mario@181: mario@181: /* array_specification [ASSIGN array_initialization} */ mario@181: /* array_initialization may be NULL ! */ mario@181: void *visit(array_spec_init_c *symbol); mario@181: mario@181: /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */ mario@181: void *visit(array_specification_c *symbol); mario@181: mario@181: /* helper symbol for array_specification */ mario@181: /* array_subrange_list ',' subrange */ mario@181: void *visit(array_subrange_list_c *symbol); mario@181: mario@181: /* array_initialization: '[' array_initial_elements_list ']' */ mario@181: /* helper symbol for array_initialization */ mario@181: /* array_initial_elements_list ',' array_initial_elements */ mario@181: void *visit(array_initial_elements_list_c *symbol); mario@181: mario@181: /* integer '(' [array_initial_element] ')' */ mario@181: /* array_initial_element may be NULL ! */ mario@181: void *visit(array_initial_elements_c *symbol); mario@181: mario@181: /* structure_type_name ':' structure_specification */ mario@181: void *visit(structure_type_declaration_c *symbol); mario@181: mario@181: /* structure_type_name ASSIGN structure_initialization */ mario@181: /* structure_initialization may be NULL ! */ mario@181: void *visit(initialized_structure_c *symbol); mario@181: mario@181: /* helper symbol for structure_declaration */ mario@181: /* structure_declaration: STRUCT structure_element_declaration_list END_STRUCT */ mario@181: /* structure_element_declaration_list structure_element_declaration ';' */ mario@181: void *visit(structure_element_declaration_list_c *symbol); mario@181: mario@181: /* structure_element_name ':' *_spec_init */ mario@181: void *visit(structure_element_declaration_c *symbol); mario@181: mario@181: /* helper symbol for structure_initialization */ mario@181: /* structure_initialization: '(' structure_element_initialization_list ')' */ mario@181: /* structure_element_initialization_list ',' structure_element_initialization */ mario@181: void *visit(structure_element_initialization_list_c *symbol); mario@181: mario@181: /* structure_element_name ASSIGN value */ mario@181: void *visit(structure_element_initialization_c *symbol); mario@181: mario@181: /* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */ mario@181: /* mario@181: * NOTE: mario@181: * (Summary: Contrary to what is expected, the mario@181: * string_type_declaration_c is not used to store mario@181: * simple string type declarations that do not include mario@181: * size limits. mario@181: * For e.g.: mario@181: * str1_type: STRING := "hello!" mario@181: * will be stored in a simple_type_declaration_c mario@181: * instead of a string_type_declaration_c. mario@181: * The following: mario@181: * str2_type: STRING [64] := "hello!" mario@181: * will be stored in a sring_type_declaration_c mario@181: * mario@181: * Read on for why this is done... mario@181: * End Summary) mario@181: * mario@181: * According to the spec, the valid construct mario@181: * TYPE new_str_type : STRING := "hello!"; END_TYPE mario@181: * has two possible routes to type_declaration... mario@181: * mario@181: * Route 1: mario@181: * type_declaration: single_element_type_declaration mario@181: * single_element_type_declaration: simple_type_declaration mario@181: * simple_type_declaration: identifier ':' simple_spec_init mario@181: * simple_spec_init: simple_specification ASSIGN constant mario@181: * (shift: identifier <- 'new_str_type') mario@181: * simple_specification: elementary_type_name mario@181: * elementary_type_name: STRING mario@181: * (shift: elementary_type_name <- STRING) mario@181: * (reduce: simple_specification <- elementary_type_name) mario@181: * (shift: constant <- "hello!") mario@181: * (reduce: simple_spec_init: simple_specification ASSIGN constant) mario@181: * (reduce: ...) mario@181: * mario@181: * mario@181: * Route 2: mario@181: * type_declaration: string_type_declaration mario@181: * string_type_declaration: identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init mario@181: * (shift: identifier <- 'new_str_type') mario@181: * elementary_string_type_name: STRING mario@181: * (shift: elementary_string_type_name <- STRING) mario@181: * (shift: string_type_declaration_size <- empty ) mario@181: * string_type_declaration_init: ASSIGN character_string mario@181: * (shift: character_string <- "hello!") mario@181: * (reduce: string_type_declaration_init <- ASSIGN character_string) mario@181: * (reduce: string_type_declaration <- identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init ) mario@181: * (reduce: type_declaration <- string_type_declaration) mario@181: * mario@181: * mario@181: * At first glance it seems that removing route 1 would make mario@181: * the most sense. Unfortunately the construct 'simple_spec_init' mario@181: * shows up multiple times in other rules, so changing this construct mario@181: * would also mean changing all the rules in which it appears. mario@181: * I (Mario) therefore chose to remove route 2 instead. This means mario@181: * that the above declaration gets stored in a mario@181: * simple_type_declaration_c, and not in a string_type_declaration_c mario@181: * as would be expected! mario@181: */ mario@181: /* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */ msousa@433: // SYM_REF4(string_type_declaration_c, string_type_name, msousa@433: // elementary_string_type_name, msousa@433: // string_type_declaration_size, msousa@433: // string_type_declaration_init) /* may be == NULL! */ mario@181: void *visit(string_type_declaration_c *symbol); mjsousa@925: mjsousa@925: /* REF_TO (non_generic_type_name | function_block_type_name) */ mjsousa@925: void *visit(ref_spec_c *symbol); mjsousa@925: /* ref_spec [ ASSIGN ref_initialization ]; */ mjsousa@925: void *visit(ref_spec_init_c *symbol); mjsousa@925: /* identifier ':' ref_spec_init */ mjsousa@925: void *visit(ref_type_decl_c *symbol); mjsousa@925: mario@181: }; // type_initial_value_c mario@181: mario@181: mario@181: