etisserant@0: /* etisserant@0: * (c) 2003 Mario de Sousa etisserant@0: * etisserant@0: * Offered to the public under the terms of the GNU General Public License etisserant@0: * as published by the Free Software Foundation; either version 2 of the etisserant@0: * License, or (at your option) any later version. etisserant@0: * etisserant@0: * This program is distributed in the hope that it will be useful, but etisserant@0: * WITHOUT ANY WARRANTY; without even the implied warranty of etisserant@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General etisserant@0: * Public License for more details. etisserant@0: * etisserant@0: * This code is made available on the understanding that it will not be etisserant@0: * used in safety-critical situations without a full and competent review. etisserant@0: */ etisserant@0: etisserant@0: /* etisserant@0: * An IEC 61131-3 IL and ST compiler. etisserant@0: * etisserant@0: * Based on the etisserant@0: * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) etisserant@0: * etisserant@0: */ etisserant@0: etisserant@0: /* etisserant@0: * Stage 2 etisserant@0: * ======= etisserant@0: * etisserant@0: * This file contains the syntax definition of the textual etisserant@0: * languages IL and ST. The syntax parser, comprising the etisserant@0: * 2nd stage of the overall compiler, is generated by runing etisserant@0: * bison on this file. etisserant@0: */ etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /**********************************************************************/ etisserant@0: /**********************************************************************/ etisserant@0: /**********************************************************************/ etisserant@0: /**********************************************************************/ etisserant@0: /******* *******/ etisserant@0: /******* The following syntax does not have any conflicts. *******/ etisserant@0: /******* *******/ etisserant@0: /******* P L E A S E K E E P I T T H A T W A Y ! *******/ etisserant@0: /******* =================================================== *******/ etisserant@0: /******* *******/ etisserant@0: /**********************************************************************/ etisserant@0: /**********************************************************************/ etisserant@0: /**********************************************************************/ etisserant@0: /**********************************************************************/ etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: %{ etisserant@0: #include /* required for strdup() */ etisserant@0: etisserant@0: etisserant@0: /* declare the token parser generated by flex... */ etisserant@0: int yylex(void); etisserant@0: etisserant@0: /* declare the error handler defined at the end of this file */ etisserant@0: void yyerror (const char *error_msg); etisserant@0: etisserant@0: /* produce a more verbose parsing error message */ etisserant@0: #define YYERROR_VERBOSE etisserant@0: etisserant@0: /* Include debuging code. etisserant@0: * Printing of debug info must then be activated by setting etisserant@0: * the variable yydebug to 1. etisserant@0: */ etisserant@0: #define YYDEBUG 0 etisserant@0: etisserant@0: etisserant@0: /* file with declaration of absyntax classes... */ etisserant@0: #include "../absyntax/absyntax.hh" etisserant@0: etisserant@0: /* file with declaration of token constants. Generated by bison! */ etisserant@0: #include "iec.y.hh" etisserant@0: etisserant@0: /* file with the declarations of symbol tables... */ etisserant@0: #include "../util/symtable.hh" etisserant@0: etisserant@0: etisserant@0: /* an ugly hack!! etisserant@0: * We will probably not need it when we decide etisserant@0: * to cut down the abstract syntax down to size. etisserant@0: * We keep it as it is until we get to write etisserant@0: * stages 3 and 4 of the compiler. Who knows, etisserant@0: * we might just find out that we really do need etisserant@0: * the abstract syntax tree to stay as it is etisserant@0: * afterall! etisserant@0: */ etisserant@0: /* for each element in list_c * etisserant@0: * execute the code etisserant@0: */ etisserant@0: #define FOR_EACH_ELEMENT(elem, list, code) { \ etisserant@0: symbol_c *elem; \ etisserant@0: for(int i = 0; i < list->n; i++) { \ etisserant@0: elem = list->elements[i]; \ etisserant@0: code; \ etisserant@0: } \ etisserant@0: } etisserant@0: etisserant@0: etisserant@0: /* A macro for printing out internal parser errors... */ etisserant@0: #define ERROR error_exit(__FILE__,__LINE__) etisserant@0: /* function defined in main.cc */ etisserant@0: extern void error_exit(const char *file_name, int line_no); etisserant@0: etisserant@0: etisserant@0: /*********************************/ etisserant@0: /* The global symbol tables... */ etisserant@0: /*********************************/ etisserant@0: /* NOTE: declared static because they are not accessed etisserant@0: * directly by the lexical parser (flex), but rather etisserant@0: * through the function get_identifier_token() etisserant@0: */ etisserant@0: /* A symbol table to store all the library elements */ etisserant@0: /* e.g.: etisserant@0: * etisserant@0: * etisserant@0: * etisserant@0: * etisserant@0: */ etisserant@0: static symtable_c library_element_symtable; etisserant@0: etisserant@0: /* A symbol table to store the declared variables of etisserant@0: * the function currently being parsed... etisserant@0: */ etisserant@0: static symtable_c variable_name_symtable; etisserant@0: etisserant@0: etisserant@0: /*************************/ etisserant@0: /* global variables... */ etisserant@0: /*************************/ etisserant@0: static symbol_c *tree_root = NULL; etisserant@0: etisserant@0: /* The name of the file currently being parsed... etisserant@0: * Note that flex accesses and updates this global variable etisserant@0: * apropriately whenever it comes across an (*#include *) etisserant@0: * directive... etisserant@0: */ etisserant@0: const char *current_filename = NULL; etisserant@0: etisserant@0: /* A global flag used to tell the parser if overloaded funtions should be allowed. etisserant@0: * The IEC 61131-3 standard allows overloaded funtions in the standard library, etisserant@0: * but disallows them in user code... etisserant@0: */ etisserant@0: bool allow_function_overloading = false; etisserant@0: etisserant@0: etisserant@0: /************************/ etisserant@0: /* forward declarations */ etisserant@0: /************************/ etisserant@0: /* The functions declared here are defined at the end of this file... */ etisserant@0: etisserant@0: /* Convert an il_operator_c into an identifier_c */ etisserant@0: symbol_c *il_operator_c_2_identifier_c(symbol_c *il_operator); etisserant@0: etisserant@0: /* print an error message */ etisserant@0: void print_err_msg(const char *filename, int lineno, const char *additional_error_msg); etisserant@0: etisserant@0: etisserant@0: /************************/ etisserant@0: /* forward declarations */ etisserant@0: /************************/ etisserant@0: /* The functions declared here are defined in iec.flex... */ etisserant@0: void print_include_stack(void); lbessard@3: void cmd_goto_body_state(void); lbessard@3: int get_goto_body_state(void); lbessard@3: void rst_goto_body_state(void); etisserant@0: etisserant@0: %} etisserant@0: etisserant@0: etisserant@0: etisserant@0: %union { etisserant@0: symbol_c *leaf; etisserant@0: list_c *list; etisserant@0: char *ID; /* token value */ etisserant@0: struct { etisserant@0: symbol_c *first; etisserant@0: symbol_c *second; lbessard@3: symbol_c *third; lbessard@3: symbol_c *fourth; lbessard@3: } tmp_symbol; /* used as a temorary reference to symbols by: lbessard@3: il_simple_operator_clash_il_operand lbessard@3: transaction_tmp lbessard@3: action_tmp lbessard@3: */ etisserant@0: } etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /*****************************/ etisserant@0: /* Prelimenary constructs... */ etisserant@0: /*****************************/ etisserant@0: %type start etisserant@0: etisserant@0: %type any_identifier etisserant@0: etisserant@0: %token prev_declared_variable_name_token etisserant@0: %token prev_declared_fb_name_token etisserant@0: %type prev_declared_variable_name etisserant@0: %type prev_declared_fb_name etisserant@0: etisserant@0: %token prev_declared_simple_type_name_token etisserant@0: %token prev_declared_subrange_type_name_token etisserant@0: %token prev_declared_enumerated_type_name_token etisserant@0: %token prev_declared_array_type_name_token etisserant@0: %token prev_declared_structure_type_name_token etisserant@0: %token prev_declared_string_type_name_token etisserant@0: etisserant@0: %type prev_declared_simple_type_name etisserant@0: %type prev_declared_subrange_type_name etisserant@0: %type prev_declared_enumerated_type_name etisserant@0: %type prev_declared_array_type_name etisserant@0: %type prev_declared_structure_type_name etisserant@0: %type prev_declared_string_type_name etisserant@0: etisserant@0: %token prev_declared_derived_function_name_token etisserant@0: %token prev_declared_derived_function_block_name_token etisserant@0: %token prev_declared_program_type_name_token etisserant@0: %type prev_declared_derived_function_name etisserant@0: %type prev_declared_derived_function_block_name etisserant@0: %type prev_declared_program_type_name etisserant@0: etisserant@0: etisserant@0: /* A bogus token that, in principle, flex MUST NEVER generate */ etisserant@0: /* USE 1: etisserant@0: * ====== etisserant@0: * This token is currently also being used as the default etisserant@0: * initialisation value of the token_id member in etisserant@0: * the symbol_c base class. etisserant@0: * etisserant@0: * USE 2 etisserant@0: * ===== etisserant@0: * This token may also be used in the future to remove etisserant@0: * mysterious reduce/reduce conflicts due to the fact etisserant@0: * that our grammar may not be LALR(1) but merely LR(1). etisserant@0: * This means that bison cannot handle it without some etisserant@0: * caoxing from ourselves. We will then need this token etisserant@0: * to do the coaxing... etisserant@0: */ etisserant@0: %token BOGUS_TOKEN_ID etisserant@0: etisserant@0: etisserant@0: /* The pragmas... */ etisserant@0: %token pragma_token etisserant@0: %type pragma etisserant@0: etisserant@0: etisserant@0: /* Where do these tokens belong ?? */ etisserant@0: /* TODO: get the syntax parser to handle these tokens... */ etisserant@0: %token EN etisserant@0: %token ENO etisserant@0: etisserant@0: etisserant@0: etisserant@0: /***************************/ etisserant@0: /* B 0 - Programming Model */ etisserant@0: /***************************/ etisserant@0: %type library etisserant@0: %type library_element_declaration etisserant@0: etisserant@0: etisserant@0: /*******************************************/ etisserant@0: /* B 1.1 - Letters, digits and identifiers */ etisserant@0: /*******************************************/ etisserant@0: /* Done totally within flex... etisserant@0: letter etisserant@0: digit etisserant@0: octal_digit etisserant@0: hex_digit etisserant@0: */ etisserant@0: %token identifier_token etisserant@0: %type identifier etisserant@0: etisserant@0: etisserant@0: /*********************/ etisserant@0: /* B 1.2 - Constants */ etisserant@0: /*********************/ etisserant@0: %type constant etisserant@0: /* a helper symbol for expression */ etisserant@0: %type non_negative_constant etisserant@0: etisserant@0: etisserant@0: /******************************/ etisserant@0: /* B 1.2.1 - Numeric Literals */ etisserant@0: /******************************/ etisserant@0: /* Done totally within flex... etisserant@0: bit etisserant@0: */ etisserant@0: %type numeric_literal etisserant@0: /* helper symbol for non_negative_constant */ etisserant@0: %type non_negative_numeric_literal etisserant@0: %type integer_literal etisserant@0: %type signed_integer etisserant@0: /* a helper symbol for non_negative_constant */ etisserant@0: %type non_negative_signed_integer etisserant@0: %token integer_token etisserant@0: %type integer etisserant@0: %token binary_integer_token etisserant@0: %type binary_integer etisserant@0: %token octal_integer_token etisserant@0: %type octal_integer etisserant@0: %token hex_integer_token etisserant@0: %type hex_integer etisserant@0: %token real_token etisserant@0: %type real etisserant@0: %type signed_real etisserant@0: /* helper symbol for non_negative_real_literal */ etisserant@0: %type non_negative_signed_real etisserant@0: %type real_literal etisserant@0: /* helper symbol for non_negative_numeric_literal */ etisserant@0: %type non_negative_real_literal etisserant@0: // %type exponent etisserant@0: %type bit_string_literal etisserant@0: %type boolean_literal etisserant@0: etisserant@0: %token FALSE etisserant@0: %token TRUE etisserant@0: etisserant@0: etisserant@0: /*******************************/ etisserant@0: /* B 1.2.2 - Character Strings */ etisserant@0: /*******************************/ etisserant@0: %token single_byte_character_string_token etisserant@0: %token double_byte_character_string_token etisserant@0: etisserant@0: %type character_string etisserant@0: %type single_byte_character_string etisserant@0: %type double_byte_character_string etisserant@0: etisserant@0: etisserant@0: /***************************/ etisserant@0: /* B 1.2.3 - Time Literals */ etisserant@0: /***************************/ etisserant@0: %type time_literal etisserant@0: etisserant@0: etisserant@0: /************************/ etisserant@0: /* B 1.2.3.1 - Duration */ etisserant@0: /************************/ etisserant@0: %type duration etisserant@0: %type interval etisserant@0: %type days etisserant@0: %type fixed_point etisserant@0: %type hours etisserant@0: %type minutes etisserant@0: %type seconds etisserant@0: %type milliseconds etisserant@0: etisserant@0: %type integer_d etisserant@0: %type integer_h etisserant@0: %type integer_m etisserant@0: %type integer_s etisserant@0: %type integer_ms etisserant@0: %type fixed_point_d etisserant@0: %type fixed_point_h etisserant@0: %type fixed_point_m etisserant@0: %type fixed_point_s etisserant@0: %type fixed_point_ms etisserant@0: etisserant@0: %token fixed_point_token etisserant@0: %token fixed_point_d_token etisserant@0: %token integer_d_token etisserant@0: %token fixed_point_h_token etisserant@0: %token integer_h_token etisserant@0: %token fixed_point_m_token etisserant@0: %token integer_m_token etisserant@0: %token fixed_point_s_token etisserant@0: %token integer_s_token etisserant@0: %token fixed_point_ms_token etisserant@0: %token integer_ms_token etisserant@0: etisserant@0: %token TIME etisserant@0: %token T_SHARP etisserant@0: etisserant@0: etisserant@0: /************************************/ etisserant@0: /* B 1.2.3.2 - Time of day and Date */ etisserant@0: /************************************/ etisserant@0: %type time_of_day etisserant@0: %type daytime etisserant@0: %type day_hour etisserant@0: %type day_minute etisserant@0: %type day_second etisserant@0: %type date etisserant@0: %type date_literal etisserant@0: %type year etisserant@0: %type month etisserant@0: %type day etisserant@0: %type date_and_time etisserant@0: etisserant@0: %token TIME_OF_DAY etisserant@0: %token DATE etisserant@0: %token D_SHARP etisserant@0: %token DATE_AND_TIME etisserant@0: etisserant@0: etisserant@0: /**********************/ etisserant@0: /* B 1.3 - Data Types */ etisserant@0: /**********************/ etisserant@0: /* Strangely, the following symbol does seem to be required! */ etisserant@0: // %type data_type_name etisserant@0: %type non_generic_type_name etisserant@0: etisserant@0: etisserant@0: /***********************************/ etisserant@0: /* B 1.3.1 - Elementary Data Types */ etisserant@0: /***********************************/ etisserant@0: /* NOTES: etisserant@0: * etisserant@0: * - To make the definition of bit_string_literal more etisserant@0: * concise, it is useful to use an extra non-terminal etisserant@0: * symbol (i.e. a grouping or construct) that groups the etisserant@0: * following elements (BYTE, WORD, DWORD, LWORD). etisserant@0: * Note that the definition of bit_string_type_name etisserant@0: * (according to the spec) includes the above elements etisserant@0: * and an extra BOOL. etisserant@0: * We could use an extra construct with the first four etisserant@0: * elements to be used solely in the definition of etisserant@0: * bit_string_literal, but with the objective of not etisserant@0: * having to replicate the actions (if we ever need etisserant@0: * to change them, they would need to be changed in both etisserant@0: * bit_string_type_name and the extra grouping), we etisserant@0: * have re-defined bit_string_type_name as only including etisserant@0: * the first four elements. etisserant@0: * In order to have our parser implement the specification etisserant@0: * correctly we have augmented every occurence of etisserant@0: * bit_string_type_name in other rules with the BOOL etisserant@0: * token. Since bit_string_type_name only appears in etisserant@0: * the rule for elementary_type_name, this does not etisserant@0: * seem to be a big concession to make! etisserant@0: * etisserant@0: * - We have added a helper symbol to concentrate the etisserant@0: * instantiation of STRING and WSTRING into a single etisserant@0: * location (elementary_string_type_name). etisserant@0: * These two elements show up in several other rules, etisserant@0: * but we want to create the equivalent abstract syntax etisserant@0: * in a single location of this file, in order to make etisserant@0: * possible future changes easier to edit... etisserant@0: */ etisserant@0: %type elementary_type_name etisserant@0: %type numeric_type_name etisserant@0: %type integer_type_name etisserant@0: %type signed_integer_type_name etisserant@0: %type unsigned_integer_type_name etisserant@0: %type real_type_name etisserant@0: %type date_type_name etisserant@0: %type bit_string_type_name etisserant@0: /* helper symbol to concentrate the instantiation etisserant@0: * of STRING and WSTRING into a single location etisserant@0: */ etisserant@0: %type elementary_string_type_name etisserant@0: etisserant@0: %token BYTE etisserant@0: %token WORD etisserant@0: %token DWORD etisserant@0: %token LWORD etisserant@0: etisserant@0: %token LREAL etisserant@0: %token REAL etisserant@0: etisserant@0: %token SINT etisserant@0: %token INT etisserant@0: %token DINT etisserant@0: %token LINT etisserant@0: etisserant@0: %token USINT etisserant@0: %token UINT etisserant@0: %token UDINT etisserant@0: %token ULINT etisserant@0: etisserant@0: %token WSTRING etisserant@0: %token STRING etisserant@0: %token BOOL etisserant@0: etisserant@0: %token TIME etisserant@0: %token DATE etisserant@0: %token DATE_AND_TIME etisserant@0: %token DT etisserant@0: %token TIME_OF_DAY etisserant@0: %token TOD etisserant@0: etisserant@0: etisserant@0: /********************************/ etisserant@0: /* B 1.3.2 - Generic data types */ etisserant@0: /********************************/ etisserant@0: /* Strangely, the following symbol does seem to be required! */ etisserant@0: // %type generic_type_name etisserant@0: etisserant@0: /* The following tokens do not seem to be used either etisserant@0: * but we declare them so they become reserved words... etisserant@0: */ etisserant@0: %token ANY etisserant@0: %token ANY_DERIVED etisserant@0: %token ANY_ELEMENTARY etisserant@0: %token ANY_MAGNITUDE etisserant@0: %token ANY_NUM etisserant@0: %token ANY_REAL etisserant@0: %token ANY_INT etisserant@0: %token ANY_BIT etisserant@0: %token ANY_STRING etisserant@0: %token ANY_DATE etisserant@0: etisserant@0: etisserant@0: /********************************/ etisserant@0: /* B 1.3.3 - Derived data types */ etisserant@0: /********************************/ etisserant@0: %type derived_type_name etisserant@0: %type single_element_type_name etisserant@0: // %type simple_type_name etisserant@0: // %type subrange_type_name etisserant@0: // %type enumerated_type_name etisserant@0: // %type array_type_name etisserant@0: // %type structure_type_name etisserant@0: etisserant@0: %type data_type_declaration etisserant@0: /* helper symbol for data_type_declaration */ etisserant@0: %type type_declaration_list etisserant@0: %type type_declaration etisserant@0: %type single_element_type_declaration etisserant@0: etisserant@0: %type simple_type_declaration etisserant@0: %type simple_spec_init etisserant@0: %type simple_specification etisserant@0: etisserant@0: %type subrange_type_declaration etisserant@0: %type subrange_spec_init etisserant@0: %type subrange_specification etisserant@0: %type subrange etisserant@0: etisserant@0: %type enumerated_type_declaration etisserant@0: %type enumerated_spec_init etisserant@0: %type enumerated_specification etisserant@0: /* helper symbol for enumerated_value */ etisserant@0: %type enumerated_value_list etisserant@0: %type enumerated_value etisserant@0: etisserant@0: %type array_type_declaration etisserant@0: %type array_spec_init etisserant@0: %type array_specification etisserant@0: /* helper symbol for array_specification */ etisserant@0: %type array_subrange_list etisserant@0: %type array_initialization etisserant@0: /* helper symbol for array_initialization */ etisserant@0: %type array_initial_elements_list etisserant@0: %type array_initial_elements etisserant@0: %type array_initial_element etisserant@0: etisserant@0: %type structure_type_declaration etisserant@0: %type structure_specification etisserant@0: %type initialized_structure etisserant@0: %type structure_declaration etisserant@0: /* helper symbol for structure_declaration */ etisserant@0: %type structure_element_declaration_list etisserant@0: %type structure_element_declaration etisserant@0: %type structure_element_name etisserant@0: %type structure_initialization etisserant@0: /* helper symbol for structure_initialization */ etisserant@0: %type structure_element_initialization_list etisserant@0: %type structure_element_initialization etisserant@0: etisserant@0: //%type string_type_name etisserant@0: %type string_type_declaration etisserant@0: /* helper symbol for string_type_declaration */ etisserant@0: %type string_type_declaration_size etisserant@0: /* helper symbol for string_type_declaration */ etisserant@0: %type string_type_declaration_init etisserant@0: etisserant@0: %token ASSIGN etisserant@0: %token DOTDOT /* ".." */ etisserant@0: %token TYPE etisserant@0: %token END_TYPE etisserant@0: %token ARRAY etisserant@0: %token OF etisserant@0: %token STRUCT etisserant@0: %token END_STRUCT etisserant@0: etisserant@0: etisserant@0: etisserant@0: /*********************/ etisserant@0: /* B 1.4 - Variables */ etisserant@0: /*********************/ etisserant@0: %type variable etisserant@0: %type symbolic_variable etisserant@0: /* helper symbol for prog_cnxn */ etisserant@0: %type any_symbolic_variable etisserant@0: %type variable_name etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /********************************************/ etisserant@0: /* B.1.4.1 Directly Represented Variables */ etisserant@0: /********************************************/ etisserant@0: /* Done totally within flex... etisserant@0: location_prefix etisserant@0: size_prefix etisserant@0: */ etisserant@0: %token direct_variable_token etisserant@0: %type direct_variable etisserant@0: etisserant@0: etisserant@0: /*************************************/ etisserant@0: /* B.1.4.2 Multi-element Variables */ etisserant@0: /*************************************/ etisserant@0: %type multi_element_variable etisserant@0: /* helper symbol for any_symbolic_variable */ etisserant@0: %type any_multi_element_variable etisserant@0: %type array_variable etisserant@0: /* helper symbol for any_symbolic_variable */ etisserant@0: %type any_array_variable etisserant@0: %type subscripted_variable etisserant@0: /* helper symbol for any_symbolic_variable */ etisserant@0: %type any_subscripted_variable etisserant@0: %type subscript_list etisserant@0: %type subscript etisserant@0: %type structured_variable etisserant@0: /* helper symbol for any_symbolic_variable */ etisserant@0: %type any_structured_variable etisserant@0: %type record_variable etisserant@0: /* helper symbol for any_symbolic_variable */ etisserant@0: %type any_record_variable etisserant@0: %type field_selector etisserant@0: etisserant@0: etisserant@0: /******************************************/ etisserant@0: /* B 1.4.3 - Declaration & Initialisation */ etisserant@0: /******************************************/ etisserant@0: %type input_declarations etisserant@0: /* helper symbol for input_declarations */ etisserant@0: %type input_declaration_list etisserant@0: %type input_declaration etisserant@0: %type edge_declaration etisserant@0: %type var_init_decl etisserant@0: %type var1_init_decl etisserant@0: %type var1_list etisserant@0: %type array_var_init_decl etisserant@0: %type structured_var_init_decl etisserant@0: %type fb_name_decl etisserant@0: /* helper symbol for fb_name_decl */ etisserant@0: %type fb_name_list_with_colon etisserant@0: /* helper symbol for fb_name_list_with_colon */ etisserant@0: %type var1_list_with_colon etisserant@0: // %type fb_name_list etisserant@0: // %type fb_name etisserant@0: %type output_declarations etisserant@0: %type input_output_declarations etisserant@0: /* helper symbol for input_output_declarations */ etisserant@0: %type var_declaration_list etisserant@0: %type var_declaration etisserant@0: %type temp_var_decl etisserant@0: %type var1_declaration etisserant@0: %type array_var_declaration etisserant@0: %type structured_var_declaration etisserant@0: %type var_declarations etisserant@0: %type retentive_var_declarations etisserant@0: %type located_var_declarations etisserant@0: /* helper symbol for located_var_declarations */ etisserant@0: %type located_var_decl_list etisserant@0: %type located_var_decl etisserant@0: %type external_var_declarations etisserant@0: /* helper symbol for external_var_declarations */ etisserant@0: %type external_declaration_list etisserant@0: %type external_declaration etisserant@0: %type global_var_name etisserant@0: %type global_var_declarations etisserant@0: /* helper symbol for global_var_declarations */ etisserant@0: %type global_var_decl_list etisserant@0: %type global_var_decl etisserant@0: %type global_var_spec etisserant@0: %type located_var_spec_init etisserant@0: %type location etisserant@0: %type global_var_list etisserant@0: %type string_var_declaration etisserant@0: %type single_byte_string_var_declaration etisserant@0: %type single_byte_string_spec etisserant@0: %type double_byte_string_var_declaration etisserant@0: %type double_byte_string_spec etisserant@0: %type incompl_located_var_declarations etisserant@0: /* helper symbol for incompl_located_var_declarations */ etisserant@0: %type incompl_located_var_decl_list etisserant@0: %type incompl_located_var_decl etisserant@0: %type incompl_location etisserant@0: %type var_spec etisserant@0: /* helper symbol for var_spec */ etisserant@0: %type string_spec etisserant@0: /* intermediate helper symbol for: etisserant@0: * - non_retentive_var_decls etisserant@0: * - output_declarations etisserant@0: */ etisserant@0: %type var_init_decl_list etisserant@0: etisserant@0: %token incompl_location_token etisserant@0: etisserant@0: %token VAR_INPUT etisserant@0: %token VAR_OUTPUT etisserant@0: %token VAR_IN_OUT etisserant@0: %token VAR_EXTERNAL etisserant@0: %token VAR_GLOBAL etisserant@0: %token END_VAR etisserant@0: %token RETAIN etisserant@0: %token NON_RETAIN etisserant@0: %token R_EDGE etisserant@0: %token F_EDGE etisserant@0: %token AT etisserant@0: etisserant@0: etisserant@0: /***********************/ etisserant@0: /* B 1.5.1 - Functions */ etisserant@0: /***********************/ etisserant@0: //%type function_name etisserant@0: /* helper symbol for IL language */ etisserant@0: %type function_name_no_clashes etisserant@0: %type function_name_simpleop_clashes etisserant@0: //%type function_name_expression_clashes etisserant@0: /* helper symbols for ST language */ etisserant@0: //%type function_name_NOT_clashes etisserant@0: %type function_name_no_NOT_clashes etisserant@0: etisserant@0: //%type standard_function_name etisserant@0: /* helper symbols for IL language */ etisserant@0: %type standard_function_name_no_clashes etisserant@0: %type standard_function_name_simpleop_clashes etisserant@0: %type standard_function_name_expression_clashes etisserant@0: /* helper symbols for ST language */ etisserant@0: %type standard_function_name_NOT_clashes etisserant@0: %type standard_function_name_no_NOT_clashes etisserant@0: etisserant@0: %type derived_function_name etisserant@0: %type function_declaration etisserant@0: /* helper symbol for function_declaration */ etisserant@0: %type function_name_declaration etisserant@0: %type io_var_declarations etisserant@0: %type function_var_decls etisserant@0: %type function_body etisserant@0: %type var2_init_decl etisserant@0: /* intermediate helper symbol for function_declaration */ etisserant@0: %type io_OR_function_var_declarations_list etisserant@0: /* intermediate helper symbol for function_var_decls */ etisserant@0: %type var2_init_decl_list etisserant@0: etisserant@0: %token standard_function_name_token etisserant@0: etisserant@0: %token FUNCTION etisserant@0: %token END_FUNCTION etisserant@0: %token CONSTANT etisserant@0: etisserant@0: etisserant@0: /*****************************/ etisserant@0: /* B 1.5.2 - Function Blocks */ etisserant@0: /*****************************/ etisserant@0: %type function_block_type_name etisserant@0: %type standard_function_block_name etisserant@0: %type derived_function_block_name etisserant@0: %type function_block_declaration etisserant@0: %type other_var_declarations etisserant@0: %type temp_var_decls etisserant@0: %type non_retentive_var_decls etisserant@0: %type function_block_body etisserant@0: /* intermediate helper symbol for function_declaration */ etisserant@0: %type io_OR_other_var_declarations_list etisserant@0: /* intermediate helper symbol for temp_var_decls */ etisserant@0: %type temp_var_decls_list etisserant@0: etisserant@0: %token standard_function_block_name_token etisserant@0: etisserant@0: %token FUNCTION_BLOCK etisserant@0: %token END_FUNCTION_BLOCK etisserant@0: %token VAR_TEMP etisserant@0: %token END_VAR etisserant@0: %token VAR etisserant@0: %token NON_RETAIN etisserant@0: %token END_VAR etisserant@0: etisserant@0: etisserant@0: /**********************/ etisserant@0: /* B 1.5.3 - Programs */ etisserant@0: /**********************/ etisserant@0: %type program_type_name etisserant@0: %type program_declaration etisserant@0: /* helper symbol for program_declaration */ etisserant@0: %type program_var_declarations_list etisserant@0: etisserant@0: %token PROGRAM etisserant@0: %token END_PROGRAM etisserant@0: etisserant@0: etisserant@0: /********************************************/ etisserant@0: /* B 1.6 Sequential Function Chart elements */ etisserant@0: /********************************************/ etisserant@0: /* TODO */ etisserant@1: etisserant@0: %type sequential_function_chart etisserant@1: %type sfc_network etisserant@0: %type initial_step etisserant@0: %type step etisserant@1: %type action_association_list etisserant@0: %type step_name etisserant@0: %type action_association etisserant@1: /* helper symbol for action_association */ etisserant@0: %type indicator_name_list etisserant@0: %type action_name etisserant@0: %type action_qualifier etisserant@1: %type qualifier etisserant@0: %type timed_qualifier etisserant@0: %type action_time etisserant@0: %type indicator_name etisserant@0: %type transition etisserant@0: %type steps etisserant@0: %type step_name_list lbessard@3: %type transition_header lbessard@3: %type transition_condition_il lbessard@3: %type transition_condition_st lbessard@3: %type action_header etisserant@0: %type action etisserant@1: %type transition_name etisserant@1: etisserant@0: etisserant@0: %token ASSIGN etisserant@0: %token ACTION etisserant@0: %token END_ACTION etisserant@0: etisserant@0: %token TRANSITION etisserant@0: %token END_TRANSITION etisserant@0: %token FROM etisserant@0: %token TO etisserant@0: %token PRIORITY etisserant@0: etisserant@0: %token INITIAL_STEP etisserant@0: %token STEP etisserant@0: %token END_STEP etisserant@0: etisserant@0: %token L etisserant@0: %token D etisserant@0: %token SD etisserant@0: %token DS etisserant@0: %token SL etisserant@0: etisserant@0: %token N etisserant@0: %token P etisserant@0: /* NOTE: the following two clash with the R and S IL operators. etisserant@0: * It will have to be handled when we include parsing of SFC... etisserant@0: */ etisserant@0: /* etisserant@0: %token R etisserant@0: %token S etisserant@0: */ etisserant@0: etisserant@0: etisserant@0: /********************************/ etisserant@0: /* B 1.7 Configuration elements */ etisserant@0: /********************************/ etisserant@0: %type configuration_name etisserant@0: %type resource_type_name etisserant@0: %type configuration_declaration etisserant@0: // helper symbol for etisserant@0: // - configuration_declaration etisserant@0: // - resource_declaration etisserant@0: // etisserant@0: %type optional_global_var_declarations etisserant@0: // helper symbol for configuration_declaration etisserant@0: %type optional_access_declarations etisserant@0: // helper symbol for configuration_declaration etisserant@0: %type optional_instance_specific_initializations etisserant@0: // helper symbol for configuration_declaration etisserant@0: %type resource_declaration_list etisserant@0: %type resource_declaration etisserant@0: %type single_resource_declaration etisserant@0: // helper symbol for single_resource_declaration etisserant@0: %type task_configuration_list etisserant@0: // helper symbol for single_resource_declaration etisserant@0: %type program_configuration_list etisserant@0: %type resource_name etisserant@0: // %type access_declarations etisserant@0: // helper symbol for access_declarations etisserant@0: // %type access_declaration_list etisserant@0: // %type access_declaration etisserant@0: // %type access_path etisserant@0: // helper symbol for access_path etisserant@0: %type any_fb_name_list etisserant@0: %type global_var_reference etisserant@0: // %type access_name etisserant@0: %type program_output_reference etisserant@0: %type program_name etisserant@0: // %type direction etisserant@0: %type task_configuration etisserant@0: %type task_name etisserant@0: %type task_initialization etisserant@0: %type data_source etisserant@0: %type program_configuration etisserant@0: // helper symbol for program_configuration etisserant@0: %type optional_task_name etisserant@0: // helper symbol for program_configuration etisserant@0: %type optional_prog_conf_elements etisserant@0: %type prog_conf_elements etisserant@0: %type prog_conf_element etisserant@0: %type fb_task etisserant@0: %type prog_cnxn etisserant@0: %type prog_data_source etisserant@0: %type data_sink etisserant@0: %type instance_specific_initializations etisserant@0: // helper symbol for instance_specific_initializations etisserant@0: %type instance_specific_init_list etisserant@0: %type instance_specific_init etisserant@0: // helper symbol for instance_specific_init etisserant@0: %type fb_initialization etisserant@0: etisserant@0: %type prev_declared_global_var_name etisserant@0: %token prev_declared_global_var_name_token etisserant@0: etisserant@0: %type prev_declared_program_name etisserant@0: %token prev_declared_program_name_token etisserant@0: etisserant@0: %type prev_declared_resource_name etisserant@0: %token prev_declared_resource_name_token etisserant@0: etisserant@0: %token prev_declared_configuration_name_token etisserant@0: etisserant@0: // %type prev_declared_task_name etisserant@0: // %token prev_declared_task_name_token etisserant@0: etisserant@0: %token CONFIGURATION etisserant@0: %token END_CONFIGURATION etisserant@0: %token TASK etisserant@0: %token RESOURCE etisserant@0: %token ON etisserant@0: %token END_RESOURCE etisserant@0: %token VAR_CONFIG etisserant@0: %token VAR_ACCESS etisserant@0: %token END_VAR etisserant@0: %token WITH etisserant@0: %token PROGRAM etisserant@0: %token RETAIN etisserant@0: %token NON_RETAIN etisserant@0: %token PRIORITY etisserant@0: %token SINGLE etisserant@0: %token INTERVAL etisserant@0: %token READ_WRITE etisserant@0: %token READ_ONLY etisserant@0: etisserant@0: etisserant@0: /***********************************/ etisserant@0: /* B 2.1 Instructions and Operands */ etisserant@0: /***********************************/ etisserant@0: %type instruction_list etisserant@0: %type il_instruction etisserant@0: %type il_incomplete_instruction etisserant@0: %type label etisserant@0: %type il_simple_operation etisserant@0: // helper symbol for il_simple_operation lbessard@3: %type il_simple_operator_clash_il_operand etisserant@0: %type il_expression etisserant@0: %type il_jump_operation etisserant@0: %type il_fb_call etisserant@0: %type il_formal_funct_call etisserant@0: // helper symbol for il_formal_funct_call etisserant@0: %type il_expr_operator_clash_eol_list etisserant@0: %type il_operand etisserant@0: %type il_operand_list etisserant@0: %type simple_instr_list etisserant@0: %type il_simple_instruction etisserant@0: %type il_param_list etisserant@0: %type il_param_instruction_list etisserant@0: %type il_param_instruction etisserant@0: %type il_param_last_instruction etisserant@0: %type il_param_assignment etisserant@0: %type il_param_out_assignment etisserant@0: etisserant@0: %token EOL etisserant@0: etisserant@0: etisserant@0: /*******************/ etisserant@0: /* B 2.2 Operators */ etisserant@0: /*******************/ etisserant@0: %token sendto_identifier_token etisserant@0: %type sendto_identifier etisserant@0: etisserant@0: %type LD_operator etisserant@0: %type LDN_operator etisserant@0: %type ST_operator etisserant@0: %type STN_operator etisserant@0: %type NOT_operator etisserant@0: %type S_operator etisserant@0: %type R_operator etisserant@0: %type S1_operator etisserant@0: %type R1_operator etisserant@0: %type CLK_operator etisserant@0: %type CU_operator etisserant@0: %type CD_operator etisserant@0: %type PV_operator etisserant@0: %type IN_operator etisserant@0: %type PT_operator etisserant@0: %type AND_operator etisserant@0: %type AND2_operator etisserant@0: %type OR_operator etisserant@0: %type XOR_operator etisserant@0: %type ANDN_operator etisserant@0: %type ANDN2_operator etisserant@0: %type ORN_operator etisserant@0: %type XORN_operator etisserant@0: %type ADD_operator etisserant@0: %type SUB_operator etisserant@0: %type MUL_operator etisserant@0: %type DIV_operator etisserant@0: %type MOD_operator etisserant@0: %type GT_operator etisserant@0: %type GE_operator etisserant@0: %type EQ_operator etisserant@0: %type LT_operator etisserant@0: %type LE_operator etisserant@0: %type NE_operator etisserant@0: %type CAL_operator etisserant@0: %type CALC_operator etisserant@0: %type CALCN_operator etisserant@0: %type RET_operator etisserant@0: %type RETC_operator etisserant@0: %type RETCN_operator etisserant@0: %type JMP_operator etisserant@0: %type JMPC_operator etisserant@0: %type JMPCN_operator etisserant@0: etisserant@0: %type il_simple_operator etisserant@0: %type il_simple_operator_clash etisserant@0: %type il_simple_operator_clash1 etisserant@0: %type il_simple_operator_clash2 etisserant@0: %type il_simple_operator_noclash etisserant@0: etisserant@0: //%type il_expr_operator etisserant@0: %type il_expr_operator_clash etisserant@0: %type il_expr_operator_noclash etisserant@0: etisserant@0: %type il_assign_operator etisserant@0: %type il_assign_out_operator etisserant@0: %type il_call_operator etisserant@0: %type il_return_operator etisserant@0: %type il_jump_operator etisserant@0: etisserant@0: etisserant@0: %token LD etisserant@0: %token LDN etisserant@0: %token ST etisserant@0: %token STN etisserant@0: %token NOT etisserant@0: %token S etisserant@0: %token R etisserant@0: %token S1 etisserant@0: %token R1 etisserant@0: %token CLK etisserant@0: %token CU etisserant@0: %token CD etisserant@0: %token PV etisserant@0: %token IN etisserant@0: %token PT etisserant@0: %token AND etisserant@0: %token AND2 /* character '&' in the source code*/ etisserant@0: %token OR etisserant@0: %token XOR etisserant@0: %token ANDN etisserant@0: %token ANDN2 /* characters '&N' in the source code */ etisserant@0: %token ORN etisserant@0: %token XORN etisserant@0: %token ADD etisserant@0: %token SUB etisserant@0: %token MUL etisserant@0: %token DIV etisserant@0: %token MOD etisserant@0: %token GT etisserant@0: %token GE etisserant@0: %token EQ etisserant@0: %token LT etisserant@0: %token LE etisserant@0: %token NE etisserant@0: %token CAL etisserant@0: %token CALC etisserant@0: %token CALCN etisserant@0: %token RET etisserant@0: %token RETC etisserant@0: %token RETCN etisserant@0: %token JMP etisserant@0: %token JMPC etisserant@0: %token JMPCN etisserant@0: etisserant@0: %token SENDTO /* "=>" */ etisserant@0: etisserant@0: etisserant@0: /***********************/ etisserant@0: /* B 3.1 - Expressions */ etisserant@0: /***********************/ etisserant@0: /* NOTE: etisserant@0: * etisserant@0: * - unary_operator, multiply_operator, etisserant@0: * add_operator and comparison_operator etisserant@0: * are not required. Their values are integrated etisserant@0: * directly into other rules... etisserant@0: */ etisserant@0: %type expression etisserant@0: %type xor_expression etisserant@0: %type and_expression etisserant@0: %type comparison etisserant@0: %type equ_expression etisserant@0: // %type comparison_operator etisserant@0: %type add_expression etisserant@0: // %type add_operator etisserant@0: %type term etisserant@0: // %type multiply_operator etisserant@0: %type power_expression etisserant@0: %type unary_expression etisserant@0: // %type unary_operator etisserant@0: %type primary_expression etisserant@0: /* intermediate helper symbol for primary_expression */ etisserant@0: %type function_invocation etisserant@0: etisserant@0: %token AND etisserant@0: %token XOR etisserant@0: %token OR etisserant@0: %token MOD etisserant@0: %token NOT etisserant@0: %token OPER_NE etisserant@0: %token OPER_GE etisserant@0: %token OPER_LE etisserant@0: %token OPER_EXP etisserant@0: etisserant@0: etisserant@0: /********************/ etisserant@0: /* B 3.2 Statements */ etisserant@0: /********************/ etisserant@0: %type statement_list etisserant@0: %type statement etisserant@0: etisserant@0: etisserant@0: etisserant@0: /*********************************/ etisserant@0: /* B 3.2.1 Assignment Statements */ etisserant@0: /*********************************/ etisserant@0: %type assignment_statement etisserant@0: %token ASSIGN /* ":=" */ etisserant@0: etisserant@0: etisserant@0: /*****************************************/ etisserant@0: /* B 3.2.2 Subprogram Control Statements */ etisserant@0: /*****************************************/ etisserant@0: %type subprogram_control_statement etisserant@0: %type return_statement etisserant@0: %type fb_invocation etisserant@0: %type param_assignment etisserant@0: /* helper symbol for fb_invocation */ etisserant@0: %type param_assignment_list etisserant@0: etisserant@0: %token ASSIGN etisserant@0: %token SENDTO /* "=>" */ etisserant@0: %token RETURN etisserant@0: etisserant@0: etisserant@0: /********************************/ etisserant@0: /* B 3.2.3 Selection Statements */ etisserant@0: /********************************/ etisserant@0: %type selection_statement etisserant@0: %type if_statement etisserant@0: %type case_statement etisserant@0: %type case_element etisserant@0: %type case_list etisserant@0: %type case_list_element etisserant@0: /* helper symbol for if_statement */ etisserant@0: %type elseif_statement_list etisserant@0: /* helper symbol for elseif_statement_list */ etisserant@0: %type elseif_statement etisserant@0: /* helper symbol for case_statement */ etisserant@0: %type case_element_list etisserant@0: etisserant@0: %token IF etisserant@0: %token THEN etisserant@0: %token ELSIF etisserant@0: %token ELSE etisserant@0: %token END_IF etisserant@0: etisserant@0: %token CASE etisserant@0: %token OF etisserant@0: %token ELSE etisserant@0: %token END_CASE etisserant@0: etisserant@0: etisserant@0: etisserant@0: /********************************/ etisserant@0: /* B 3.2.4 Iteration Statements */ etisserant@0: /********************************/ etisserant@0: %type iteration_statement etisserant@0: %type for_statement etisserant@0: %type control_variable etisserant@0: %type while_statement etisserant@0: %type repeat_statement etisserant@0: %type exit_statement etisserant@0: /* Integrated directly into for_statement */ etisserant@0: // %type for_list etisserant@0: etisserant@0: %token FOR etisserant@0: %token ASSIGN etisserant@0: %token TO etisserant@0: %token BY etisserant@0: %token DO etisserant@0: %token END_FOR etisserant@0: etisserant@0: %token WHILE etisserant@0: %token DO etisserant@0: %token END_WHILE etisserant@0: etisserant@0: %token REPEAT etisserant@0: %token UNTIL etisserant@0: %token END_REPEAT etisserant@0: etisserant@0: %token EXIT etisserant@0: etisserant@0: %% etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: /********************************************************/ etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /*****************************/ etisserant@0: /* Prelimenary constructs... */ etisserant@0: /*****************************/ etisserant@0: start: etisserant@0: library {$$ = $1;} etisserant@0: ; etisserant@0: etisserant@0: /* the pragmas... */ etisserant@0: pragma: etisserant@0: pragma_token {$$ = new pragma_c($1);} etisserant@0: etisserant@0: etisserant@0: etisserant@0: /* NOTE: etisserant@0: * short version: etisserant@0: * identifier is used for previously undeclared identifiers etisserant@0: * any_identifier is used when any identifier, previously etisserant@0: * declared or not, is required in the syntax. etisserant@0: * etisserant@0: * long version: etisserant@0: * When flex comes across an identifier, it first etisserant@0: * searches through the currently declared variables, etisserant@0: * functions, types, etc... to determine if it has etisserant@0: * been previously declared. etisserant@0: * Only if the identifier has not yet been declared etisserant@0: * will it return an identifier_token (later turned into etisserant@0: * an identifier symbol by the bison generated syntax parser). etisserant@0: * etisserant@0: * Some constructs in the syntax, such as when calling etisserant@0: * a function 'F(var1 := 1; var2 := 2);', will accept _any_ etisserant@0: * identifier in 'var1', even if it has been previously etisserant@0: * declared in the current scope, since var1 belongs to etisserant@0: * another scope (the variables declared in function F). etisserant@0: * etisserant@0: * For the above reason, we need to define the symbol etisserant@0: * any_identifier. All the symbols that may become an etisserant@0: * any_identifier are expected to be stored in the etisserant@0: * abstract syntax as a identifier_c etisserant@0: */ etisserant@0: /* NOTE: etisserant@0: * Type names, function names, function block type names and etisserant@0: * program type names are considerd keywords once they are defined, etisserant@0: * so may no longer be used for variable names! etisserant@0: * BUT the spec is confusing on this issue, as it is not clear when etisserant@0: * a function name should be considered as defined. If it is to be etisserant@0: * considered defined only from the location from where it is declared etisserant@0: * and onwards, it means that before it is declared its name may be etisserant@0: * used for variable names! etisserant@0: * This means that we must allow names previously used for functions etisserant@0: * (et. al.) to also constitue an any_identifier! etisserant@0: */ etisserant@0: any_identifier: etisserant@0: identifier etisserant@0: | prev_declared_fb_name etisserant@0: | prev_declared_variable_name etisserant@0: /**/ etisserant@0: | prev_declared_enumerated_type_name etisserant@0: | prev_declared_simple_type_name etisserant@0: | prev_declared_subrange_type_name etisserant@0: | prev_declared_array_type_name etisserant@0: | prev_declared_structure_type_name etisserant@0: | prev_declared_string_type_name etisserant@0: | prev_declared_derived_function_name etisserant@0: | prev_declared_derived_function_block_name etisserant@0: | prev_declared_program_type_name etisserant@0: /**/ etisserant@0: | prev_declared_resource_name etisserant@0: | prev_declared_program_name etisserant@0: | prev_declared_global_var_name etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: prev_declared_variable_name: prev_declared_variable_name_token {$$ = new identifier_c($1);}; etisserant@0: prev_declared_fb_name: prev_declared_fb_name_token {$$ = new identifier_c($1);}; etisserant@0: etisserant@0: prev_declared_simple_type_name: prev_declared_simple_type_name_token {$$ = new identifier_c($1);}; etisserant@0: prev_declared_subrange_type_name: prev_declared_subrange_type_name_token {$$ = new identifier_c($1);}; etisserant@0: prev_declared_enumerated_type_name: prev_declared_enumerated_type_name_token {$$ = new identifier_c($1);}; etisserant@0: prev_declared_array_type_name: prev_declared_array_type_name_token {$$ = new identifier_c($1);}; etisserant@0: prev_declared_structure_type_name: prev_declared_structure_type_name_token {$$ = new identifier_c($1);}; etisserant@0: prev_declared_string_type_name: prev_declared_string_type_name_token {$$ = new identifier_c($1);}; etisserant@0: etisserant@0: prev_declared_derived_function_name: prev_declared_derived_function_name_token {$$ = new identifier_c($1);}; etisserant@0: prev_declared_derived_function_block_name: prev_declared_derived_function_block_name_token {$$ = new identifier_c($1);}; etisserant@0: prev_declared_program_type_name: prev_declared_program_type_name_token {$$ = new identifier_c($1);}; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /***************************/ etisserant@0: /* B 0 - Programming Model */ etisserant@0: /***************************/ etisserant@0: library: etisserant@0: /* empty */ etisserant@0: {if (tree_root == NULL) etisserant@0: tree_root = new library_c(); etisserant@0: $$ = (list_c *)tree_root; etisserant@0: } etisserant@0: | library library_element_declaration etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: | library error etisserant@0: {$$ = NULL; etisserant@0: print_err_msg(current_filename, @2.last_line, "unknown error."); etisserant@0: /* yychar */ etisserant@0: yyerrok; etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: library_element_declaration: etisserant@0: data_type_declaration etisserant@0: | function_declaration etisserant@0: | function_block_declaration etisserant@0: | program_declaration etisserant@0: | configuration_declaration etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /*******************************************/ etisserant@0: /* B 1.1 - Letters, digits and identifiers */ etisserant@0: /*******************************************/ etisserant@0: /* NOTE: the spec defines identifier as: etisserant@0: * identifier ::= (letter|('_' (letter|digit))) {['_'] (letter|digit)} etisserant@0: * In essence, any sequence of letters or digits, starting with a letter etisserant@0: * or '_'. etisserant@0: * etisserant@0: * On section 2.1.3 (pg 26) , the spec states etisserant@0: * "The keywords listed in annex C shall not be used for any other purpose, etisserant@0: * e.g., variable names or extensions as defined in 1.5.1." etisserant@0: * (NOTE: the spec itself does not follow this rule, as it defines standard etisserant@0: * functions with names identidal to keywords, e.g. 'MOD', 'NOT' !!. This is etisserant@0: * another issue altogether, and is worked around somewhere else...) etisserant@0: * etisserant@0: * This means that we must re-define indentifier so as to exclude etisserant@0: * any keywords defined in annex C. etisserant@0: * etisserant@0: * Note also that the list includes etisserant@0: * - Data type names etisserant@0: * - Function names etisserant@0: * - Function Block names etisserant@0: * This means that any named used for a function name, data type name etisserant@0: * or function block name, essentially becomes a keyword, and may therefore etisserant@0: * no longer be re-used for any other use! (see NOTE 2) etisserant@0: * etisserant@0: * In our case, excluding the keywords is achieved in the lexical parser, etisserant@0: * by two mechanisms: etisserant@0: * (1) giving higher priority to the keywords (tokens) than to identifiers, etisserant@0: * so when the lexical parser finds a keyword it will be parsed as a etisserant@0: * token before being parsed as an identifier. etisserant@0: * (2) when an identifier is found that is not a keyword, the lexical parser etisserant@0: * then looks in the global symbol table, and will not return an identifier etisserant@0: * if the name has been previously used as a data type name, function name, etisserant@0: * or function block name! (In these cases it will return a etisserant@0: * prev_declared_function_name_token, etc...). etisserant@0: * etisserant@0: * Unfortunately, the language (especially IL) uses tokens that are etisserant@0: * not defined as keywords in the spec (e.g. 'IN', 'R1', 'S1', 'PT', etc...)! etisserant@0: * This means that it is valid to name a function 'IN', a variable 'PT', etc... etisserant@0: * BUT, the lexical parser will interpret these names as tokens (keywords). etisserant@0: * To allow these names to be used as function names, variable names, etc..., etisserant@0: * I (Mario) have augmented the definition of identifier to also include the tokens etisserant@0: * that are not explicitly defined as keywords in the spec!! etisserant@0: * etisserant@0: * etisserant@0: * etisserant@0: * etisserant@0: * NOTE 2: etisserant@0: * I (Mario) find it strange that the writers of the spec really want etisserant@0: * names previously used for function names, data type names or function etisserant@0: * block names, to become full fledged keywords. I understand that they etisserant@0: * do not want these names being used as variable names, but how about etisserant@0: * enumeration values? How about structure element names? etisserant@0: * If we interpret the spec literally, these would not be accepted, etisserant@0: * which would probably burden the programmer quite a bit, in making sure etisserant@0: * all these name don't clash! etisserant@0: * etisserant@0: * etisserant@0: * etisserant@0: * NOTE 3: The keywords, as specified in Annex C are... etisserant@0: * etisserant@0: * - Data type names etisserant@0: * - Function names etisserant@0: * - Function Block names etisserant@0: * - ACTION...END_ACTION etisserant@0: * - ARRAY...OF etisserant@0: * - AT etisserant@0: * - CASE...OF...ELSE...END_CASE etisserant@0: * - CONFIGURATION...END_CONFIGURATION etisserant@0: * - CONSTANT etisserant@0: * - EN, ENO etisserant@0: * - EXIT etisserant@0: * - FALSE etisserant@0: * - F_EDGE etisserant@0: * - FOR...TO...BY...DO...END_FOR etisserant@0: * - FUNCTION...END_FUNCTION etisserant@0: * - FUNCTION_BLOCK...END_FUNCTION_BLOCK etisserant@0: * - IF...THEN...ELSIF...ELSE...END_IF etisserant@0: * - INITIAL_STEP...END_STEP etisserant@0: * - NOT, MOD, AND, XOR, OR etisserant@0: * - PROGRAM...WITH... etisserant@0: * - PROGRAM...END_PROGRAM etisserant@0: * - R_EDGE etisserant@0: * - READ_ONLY, READ_WRITE etisserant@0: * - REPEAT...UNTIL...END_REPEAT etisserant@0: * - RESOURCE...ON...END_RESOURCE etisserant@0: * - RETAIN, NON_RETAIN etisserant@0: * - RETURN etisserant@0: * - STEP...END_STEP etisserant@0: * - STRUCT...END_STRUCT etisserant@0: * - TASK etisserant@0: * - TRANSITION...FROM...TO...END_TRANSITION etisserant@0: * - TRUE etisserant@0: * - TYPE...END_TYPE etisserant@0: * - VAR...END_VAR etisserant@0: * - VAR_INPUT...END_VAR etisserant@0: * - VAR_OUTPUT...END_VAR etisserant@0: * - VAR_IN_OUT...END_VAR etisserant@0: * - VAR_TEMP...END_VAR etisserant@0: * - VAR_EXTERNAL...END_VAR etisserant@0: * - VAR_ACCESS...END_VAR etisserant@0: * - VAR_CONFIG...END_VAR etisserant@0: * - VAR_GLOBAL...END_VAR etisserant@0: * - WHILE...DO...END_WHILE etisserant@0: * - WITH etisserant@0: */ etisserant@0: etisserant@0: identifier: etisserant@0: identifier_token {$$ = new identifier_c($1);} etisserant@0: /* Make sure that all tokens (names) not defined as keywords are included here... etisserant@0: * I (Mario) have already done this, but if any changes are made to this file, etisserant@0: * this list MUST be kept consistent!! etisserant@0: */ etisserant@0: /**/ etisserant@0: | PRIORITY {$$ = new identifier_c(strdup("PRIORITY"));} etisserant@0: | SINGLE {$$ = new identifier_c(strdup("SINGLE"));} etisserant@0: | INTERVAL {$$ = new identifier_c(strdup("INTERVAL"));} etisserant@0: /**/ etisserant@0: | LD_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | LDN_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | ST_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | STN_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | S_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | R_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | S1_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | R1_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | CLK_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | CU_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | CD_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | PV_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | IN_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | PT_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | ANDN_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: /* NOTE: ANDN2_operator corresponds to the string '&N' in the source code! etisserant@0: * This is __not__ a valid name, so it is omitted from this list!! etisserant@0: *| ANDN2_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: */ etisserant@0: /* NOTE: 'AND' is a keyword, so should not appear on this list... */ etisserant@0: | ORN_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | XORN_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | ADD_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | SUB_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | MUL_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | DIV_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | GT_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | GE_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | EQ_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | LT_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | LE_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | NE_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | CAL_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | CALC_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | CALCN_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | RET_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | RETC_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | RETCN_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | JMP_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | JMPC_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | JMPCN_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: ; etisserant@0: etisserant@0: /*********************/ etisserant@0: /* B 1.2 - Constants */ etisserant@0: /*********************/ etisserant@0: constant: etisserant@0: numeric_literal etisserant@0: | character_string etisserant@0: | time_literal etisserant@0: | bit_string_literal etisserant@0: | boolean_literal etisserant@0: /* NOTE: in order to remove reduce/reduce conflicts, etisserant@0: * unsigned_integer, signed_integer, binary_integer, octal_integer etisserant@0: * and hex_integer have been integrated directly into etisserant@0: * the constants construct, instead of belonging to etisserant@0: * either the bit_string_literal or integer_literal etisserant@0: * construct. etisserant@0: */ etisserant@0: /* NOTE: unsigned_integer, although used in some etisserant@0: * rules, is not defined in the spec! etisserant@0: * We therefore replaced unsigned_integer as integer etisserant@0: */ etisserant@0: /*| integer {} */ /* i.e. an unsigned_integer */ /* NOTE: already included as a signed integer! */ etisserant@0: | signed_integer etisserant@0: | binary_integer etisserant@0: | octal_integer etisserant@0: | hex_integer etisserant@0: ; etisserant@0: etisserant@0: /* a helper symbol for expression */ etisserant@0: /* A constant without any preceding '-', but may etisserant@0: * include a preceding '+' ! etisserant@0: */ etisserant@0: non_negative_constant: etisserant@0: non_negative_numeric_literal etisserant@0: | character_string etisserant@0: | time_literal etisserant@0: | bit_string_literal etisserant@0: | boolean_literal etisserant@0: | non_negative_signed_integer etisserant@0: | binary_integer etisserant@0: | octal_integer etisserant@0: | hex_integer etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /******************************/ etisserant@0: /* B 1.2.1 - Numeric Literals */ etisserant@0: /******************************/ etisserant@0: /* NOTES: etisserant@0: * etisserant@0: * - integer is parsed by flex, but signed_integer etisserant@0: * is parsed by bison. Flex cannot parse a signed etisserant@0: * integer correctly! For example: '123+456' etisserant@0: * would be parsed by flex as an {integer} {signed_integer} etisserant@0: * instead of {integer} '+' {integer} etisserant@0: * etisserant@0: * - Neither flex nor bison can parse a real_literal etisserant@0: * completely (and correctly). etisserant@0: * Note that we cannot use the definition of real in bison as etisserant@0: * real: signed_integer '.' integer [exponent] etisserant@0: * exponent: {'E'|'e'} ['+'|'-'] integer etisserant@0: * because 123e45 would be parsed by flex as etisserant@0: * integer (123) identifier (e45). etisserant@0: * I.e., flex never hands over an 'e' directly to etisserant@0: * bison, but rather interprets it as an identifier. etisserant@0: * I guess we could jump through hoops and get it etisserant@0: * working in bison, but the following alternative etisserant@0: * seems more straight forward... etisserant@0: * etisserant@0: * We therefore had to break up the definition of etisserant@0: * real_literal in discrete parts: etisserant@0: * real_literal: [real_type_name '#'] singned_real etisserant@0: * signed_real: ['+'|'-'] real etisserant@0: * Flex handles real, while bison handles signed_real etisserant@0: * and real_literal. etisserant@0: * etisserant@0: * - According to the spec, intger '.' integer etisserant@0: * may be reduced to either a real or a fixed_point. etisserant@0: * It is nevertheless possible to figure out from the etisserant@0: * context which of the two rules should be used in etisserant@0: * the reduction. etisserant@0: * Unfortunately, due to the issue described above etisserant@0: * regarding the exponent of a real, the syntax etisserant@0: * integer '.' integer etisserant@0: * must be parsed by flex as a single token (i.e. etisserant@0: * fixed_point_token). This means we must add fixed_point etisserant@0: * to the definition of real! etisserant@0: * etisserant@0: * - The syntax also uses a construct etisserant@0: * fixed_point: integer ['.' integer] etisserant@0: * Notice that real is not defined based on fixed point, etisserant@0: * but rather off integer thus: etisserant@0: * real: integer '.' integer [exponent] etisserant@0: * This means that a real may not be composed of a single etisserant@0: * integer, unlike the construct fixed_point! etisserant@0: * This also means that a etisserant@0: * integer '.' integer etisserant@0: * could be reduced to either a real or a fixed_point etisserant@0: * construct. It is probably possible to decide by looking etisserant@0: * at the context, BUT: etisserant@0: * Unfortunatley, due to the reasons explained way above, etisserant@0: * a real (with an exponent) has to be handled by flex as a etisserant@0: * whole. This means that we cannot leave to bison (the syntax etisserant@0: * parser) the decision of how to reduce an etisserant@0: * integer '.' integer etisserant@0: * (either to real or to fixed_point) etisserant@0: * The decision on how to reduce it would need to be done by etisserant@0: * ther lexical analyser (i.e. flex). But flex cannot do this etisserant@0: * sort of thing. etisserant@0: * The solution I (Mario) adopted is to have flex return etisserant@0: * a real_token on (notice that exponent is no longer optional) etisserant@0: * integer '.' integer exponent etisserant@0: * and to return a fixed_point_token when it finds etisserant@0: * integer '.' integer etisserant@0: * We now redefine real and fixed_point to be etisserant@0: * fixed_point: fixed_point_token | integer etisserant@0: * real: real_token | fixed_point_token etisserant@0: */ etisserant@0: real: etisserant@0: real_token {$$ = new real_c($1);} etisserant@0: | fixed_point_token {$$ = new real_c($1);} etisserant@0: ; etisserant@0: etisserant@0: integer: integer_token {$$ = new integer_c($1);}; etisserant@0: binary_integer: binary_integer_token {$$ = new binary_integer_c($1);}; etisserant@0: octal_integer: octal_integer_token {$$ = new octal_integer_c($1);}; etisserant@0: hex_integer: hex_integer_token {$$ = new hex_integer_c($1);}; etisserant@0: etisserant@0: numeric_literal: etisserant@0: integer_literal etisserant@0: | real_literal etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for non_negative_constant */ etisserant@0: non_negative_numeric_literal: etisserant@0: integer_literal etisserant@0: | non_negative_real_literal etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: integer_literal: etisserant@0: integer_type_name '#' signed_integer etisserant@0: {$$ = new integer_literal_c($1, $3);} etisserant@0: | integer_type_name '#' binary_integer etisserant@0: {$$ = new integer_literal_c($1, $3);} etisserant@0: | integer_type_name '#' octal_integer etisserant@0: {$$ = new integer_literal_c($1, $3);} etisserant@0: | integer_type_name '#' hex_integer etisserant@0: {$$ = new integer_literal_c($1, $3);} etisserant@0: /* NOTE: see note in the definition of constant for reason etisserant@0: * why signed_integer, binary_integer, octal_integer etisserant@0: * and hex_integer are missing here! etisserant@0: */ etisserant@0: ; etisserant@0: etisserant@0: signed_integer: etisserant@0: integer etisserant@0: | '+' integer {$$ = $2;} etisserant@0: | '-' integer {$$ = new neg_expression_c($2);} etisserant@0: ; etisserant@0: etisserant@0: /* a helper symbol for non_negative_constant */ etisserant@0: /* A integer without any preceding '-', but may etisserant@0: * include a preceding '+' ! etisserant@0: */ etisserant@0: non_negative_signed_integer: etisserant@0: integer etisserant@0: | '+' integer {$$ = $2;} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: real_literal: etisserant@0: signed_real etisserant@0: | real_type_name '#' signed_real etisserant@0: {$$ = new real_literal_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for non_negative_numeric_literal */ etisserant@0: non_negative_real_literal: etisserant@0: non_negative_signed_real etisserant@0: | real_type_name '#' signed_real etisserant@0: {$$ = new real_literal_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: signed_real: etisserant@0: real etisserant@0: | '+' real {$$ = $2;} etisserant@0: | '-' real {$$ = new neg_expression_c($2);} etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for non_negative_real_literal */ etisserant@0: non_negative_signed_real: etisserant@0: real etisserant@0: | '+' real {$$ = $2;} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: bit_string_literal: etisserant@0: bit_string_type_name '#' integer /* i.e. unsigned_integer */ etisserant@0: {$$ = new bit_string_literal_c($1, $3);} etisserant@0: | bit_string_type_name '#' binary_integer etisserant@0: {$$ = new bit_string_literal_c($1, $3);} etisserant@0: | bit_string_type_name '#' octal_integer etisserant@0: {$$ = new bit_string_literal_c($1, $3);} etisserant@0: | bit_string_type_name '#' hex_integer etisserant@0: {$$ = new bit_string_literal_c($1, $3);} etisserant@0: /* NOTE: see note in the definition of constant for reason etisserant@0: * why unsigned_integer, binary_integer, octal_integer etisserant@0: * and hex_integer are missing here! etisserant@0: */ etisserant@0: /* NOTE: see note under the B 1.2.1 section of token etisserant@0: * and grouping type definition for reason why the use of etisserant@0: * bit_string_type_name, although seemingly incorrect, is etisserant@0: * really correct here! etisserant@0: */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: boolean_literal: etisserant@0: TRUE {$$ = new boolean_literal_c(new bool_type_name_c(), etisserant@0: new boolean_true_c());} etisserant@0: | FALSE {$$ = new boolean_literal_c(new bool_type_name_c(), etisserant@0: new boolean_false_c());} etisserant@0: /* etisserant@0: | BOOL '#' '1' {} etisserant@0: | BOOL '#' '0' {} etisserant@0: */ etisserant@0: /* NOTE: the rules etisserant@0: * BOOL '#' '1' etisserant@0: * and etisserant@0: * BOOL '#' '0' etisserant@0: * do not work as expected... etisserant@0: * Consider that we are using 'BOOL' and '#' as tokens etisserant@0: * that flex hands over to bison (yacc). Because flex would etisserant@0: * then parse the single '1' or '0' as an integer, etisserant@0: * the rule in bison would have to be etisserant@0: * BOOL '#' integer, followed by verifying of the etisserant@0: * integer has the correct value! etisserant@0: * etisserant@0: * We therefore have flex return TRUE whenever it etisserant@0: * comes across 'TRUE' or 'BOOL#1', and FALSE whenever etisserant@0: * it comes across 'FALSE' or 'BOOL#0'. etisserant@0: * Note that this means that flex will parse "BOOL#01" etisserant@0: * as FALSE followed by an integer ('1'). etisserant@0: * Bison should detect this as an error, so we should etisserant@0: * be OK. etisserant@0: * etisserant@0: * Another option would be to change the rules to accept etisserant@0: * BOOL '#' integer etisserant@0: * but then check whether the integer has a correct etisserant@0: * value! At the moment I feel that the first option etisserant@0: * is more straight forward. etisserant@0: */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /*******************************/ etisserant@0: /* B 1.2.2 - Character Strings */ etisserant@0: /*******************************/ etisserant@0: /* Transform the tokens given us by flex into leafs */ etisserant@0: single_byte_character_string: single_byte_character_string_token etisserant@0: {$$ = new single_byte_character_string_c($1);}; etisserant@0: etisserant@0: double_byte_character_string: double_byte_character_string_token etisserant@0: {$$ = new double_byte_character_string_c($1);}; etisserant@0: etisserant@0: etisserant@0: character_string: etisserant@0: single_byte_character_string etisserant@0: | double_byte_character_string etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /***************************/ etisserant@0: /* B 1.2.3 - Time Literals */ etisserant@0: /***************************/ etisserant@0: time_literal: etisserant@0: time_of_day etisserant@0: | date etisserant@0: | date_and_time etisserant@0: | duration etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /************************/ etisserant@0: /* B 1.2.3.1 - Duration */ etisserant@0: /************************/ etisserant@0: duration: etisserant@0: /* (T | TIME) '#' ['-'] interval */ etisserant@0: /* NOTE: since TIME is also a data type, it is a keyword etisserant@0: * and may therefore be handled by a token. etisserant@0: * etisserant@0: * Unfortunately T is not a data type, and therefore etisserant@0: * not a keyword. This means that we may have variables named T! etisserant@0: * Flex cannot return the token TIME when it comes across a single T! etisserant@0: * etisserant@0: * We therefore have flex returning the token T_SHARP etisserant@0: * when it comes across 'T#' etisserant@0: */ etisserant@0: TIME '#' interval etisserant@0: {$$ = new duration_c(NULL, $3);} etisserant@0: | TIME '#' '-' interval etisserant@0: {$$ = new duration_c(new neg_time_c(), $4);} etisserant@0: | T_SHARP interval etisserant@0: {$$ = new duration_c(NULL, $2);} etisserant@0: | T_SHARP '-' interval etisserant@0: {$$ = new duration_c(new neg_time_c(), $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: interval: etisserant@0: days etisserant@0: | hours etisserant@0: | minutes etisserant@0: | seconds etisserant@0: | milliseconds etisserant@0: ; etisserant@0: etisserant@0: integer_d: integer_d_token {$$ = new integer_c($1);}; etisserant@0: integer_h: integer_h_token {$$ = new integer_c($1);}; etisserant@0: integer_m: integer_m_token {$$ = new integer_c($1);}; etisserant@0: integer_s: integer_s_token {$$ = new integer_c($1);}; etisserant@0: integer_ms: integer_ms_token {$$ = new integer_c($1);}; etisserant@0: etisserant@0: fixed_point_d: etisserant@0: fixed_point_d_token etisserant@0: {$$ = new fixed_point_c($1);} etisserant@0: | integer_d etisserant@0: ; etisserant@0: etisserant@0: fixed_point_h: etisserant@0: fixed_point_h_token etisserant@0: {$$ = new fixed_point_c($1);} etisserant@0: | integer_h etisserant@0: ; etisserant@0: etisserant@0: fixed_point_m: etisserant@0: fixed_point_m_token etisserant@0: {$$ = new fixed_point_c($1);} etisserant@0: | integer_m etisserant@0: ; etisserant@0: etisserant@0: fixed_point_s: etisserant@0: fixed_point_s_token etisserant@0: {$$ = new fixed_point_c($1);} etisserant@0: | integer_s etisserant@0: ; etisserant@0: etisserant@0: fixed_point_ms: etisserant@0: fixed_point_ms_token etisserant@0: {$$ = new fixed_point_c($1);} etisserant@0: | integer_ms etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: fixed_point: etisserant@0: fixed_point_token etisserant@0: {$$ = new fixed_point_c($1);} etisserant@0: | integer etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: days: etisserant@0: /* fixed_point ('d') */ etisserant@0: fixed_point_d etisserant@0: {$$ = new days_c($1, NULL);} etisserant@0: /*| integer ('d') ['_'] hours */ etisserant@0: | integer_d hours etisserant@0: {$$ = new days_c($1, $2);} etisserant@0: | integer_d '_' hours etisserant@0: {$$ = new days_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: hours: etisserant@0: /* fixed_point ('h') */ etisserant@0: fixed_point_h etisserant@0: {$$ = new hours_c($1, NULL);} etisserant@0: /*| integer ('h') ['_'] minutes */ etisserant@0: | integer_h minutes etisserant@0: {$$ = new hours_c($1, $2);} etisserant@0: | integer_h '_' minutes etisserant@0: {$$ = new hours_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: minutes: etisserant@0: /* fixed_point ('m') */ etisserant@0: fixed_point_m etisserant@0: {$$ = new minutes_c($1, NULL);} etisserant@0: /*| integer ('m') ['_'] seconds */ etisserant@0: | integer_m seconds etisserant@0: {$$ = new minutes_c($1, $2);} etisserant@0: | integer_m '_' seconds etisserant@0: {$$ = new minutes_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: seconds: etisserant@0: /* fixed_point ('s') */ etisserant@0: fixed_point_s etisserant@0: {$$ = new seconds_c($1, NULL);} etisserant@0: /*| integer ('s') ['_'] milliseconds */ etisserant@0: | integer_s milliseconds etisserant@0: {$$ = new seconds_c($1, $2);} etisserant@0: | integer_s '_' milliseconds etisserant@0: {$$ = new seconds_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: milliseconds: etisserant@0: /* fixed_point ('ms') */ etisserant@0: fixed_point_ms etisserant@0: {$$ = new milliseconds_c($1);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /************************************/ etisserant@0: /* B 1.2.3.2 - Time of day and Date */ etisserant@0: /************************************/ etisserant@0: time_of_day: etisserant@0: TIME_OF_DAY '#' daytime etisserant@0: {$$ = new time_of_day_c($3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: daytime: etisserant@0: day_hour ':' day_minute ':' day_second etisserant@0: {$$ = new daytime_c($1, $3, $5);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: day_hour: integer; etisserant@0: day_minute: integer; etisserant@0: day_second: fixed_point; etisserant@0: etisserant@0: etisserant@0: date: etisserant@0: DATE '#' date_literal etisserant@0: {$$ = new date_c($3);} etisserant@0: | D_SHARP date_literal etisserant@0: {$$ = new date_c($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: date_literal: etisserant@0: year '-' month '-' day etisserant@0: {$$ = new date_literal_c($1, $3, $5);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: year: integer; etisserant@0: month: integer; etisserant@0: day: integer; etisserant@0: etisserant@0: etisserant@0: date_and_time: etisserant@0: DATE_AND_TIME '#' date_literal '-' daytime etisserant@0: {$$ = new date_and_time_c($3, $5);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /**********************/ etisserant@0: /* B 1.3 - Data Types */ etisserant@0: /**********************/ etisserant@0: /* Strangely, the following symbol does seem to be required! */ etisserant@0: /* etisserant@0: data_type_name: etisserant@0: non_generic_type_name etisserant@0: | generic_type_name etisserant@0: ; etisserant@0: */ etisserant@0: etisserant@0: non_generic_type_name: etisserant@0: elementary_type_name etisserant@0: | derived_type_name etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /***********************************/ etisserant@0: /* B 1.3.1 - Elementary Data Types */ etisserant@0: /***********************************/ etisserant@0: elementary_type_name: etisserant@0: numeric_type_name etisserant@0: | date_type_name etisserant@0: | bit_string_type_name etisserant@0: | elementary_string_type_name etisserant@0: | TIME {$$ = new time_type_name_c();} etisserant@0: | BOOL {$$ = new bool_type_name_c();} etisserant@0: /* NOTE: see note under the B 1.2.1 section of token etisserant@0: * and grouping type definition for reason why BOOL etisserant@0: * was added to this definition. etisserant@0: */ etisserant@0: ; etisserant@0: etisserant@0: numeric_type_name: etisserant@0: integer_type_name etisserant@0: | real_type_name etisserant@0: ; etisserant@0: etisserant@0: integer_type_name: etisserant@0: signed_integer_type_name etisserant@0: | unsigned_integer_type_name etisserant@0: ; etisserant@0: etisserant@0: signed_integer_type_name: etisserant@0: SINT {$$ = new sint_type_name_c();} etisserant@0: | INT {$$ = new int_type_name_c();} etisserant@0: | DINT {$$ = new dint_type_name_c();} etisserant@0: | LINT {$$ = new lint_type_name_c();} etisserant@0: ; etisserant@0: etisserant@0: unsigned_integer_type_name: etisserant@0: USINT {$$ = new usint_type_name_c();} etisserant@0: | UINT {$$ = new uint_type_name_c();} etisserant@0: | UDINT {$$ = new udint_type_name_c();} etisserant@0: | ULINT {$$ = new ulint_type_name_c();} etisserant@0: ; etisserant@0: etisserant@0: real_type_name: etisserant@0: REAL {$$ = new real_type_name_c();} etisserant@0: | LREAL {$$ = new lreal_type_name_c();} etisserant@0: ; etisserant@0: etisserant@0: date_type_name: etisserant@0: DATE {$$ = new date_type_name_c();} etisserant@0: | TIME_OF_DAY {$$ = new tod_type_name_c();} etisserant@0: | TOD {$$ = new tod_type_name_c();} etisserant@0: | DATE_AND_TIME {$$ = new dt_type_name_c();} etisserant@0: | DT {$$ = new dt_type_name_c();} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: bit_string_type_name: etisserant@0: BYTE {$$ = new byte_type_name_c();} etisserant@0: | WORD {$$ = new word_type_name_c();} etisserant@0: | DWORD {$$ = new dword_type_name_c();} etisserant@0: | LWORD {$$ = new lword_type_name_c();} etisserant@0: /* NOTE: see note under the B 1.2.1 section of token etisserant@0: * and grouping type definition for reason why the BOOL etisserant@0: * was omitted from this definition. etisserant@0: */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* Helper symbol to concentrate the instantiation etisserant@0: * of STRING and WSTRING into a single location. etisserant@0: * etisserant@0: * These two elements show up in several other rules, etisserant@0: * but we want to create the equivalent abstract syntax etisserant@0: * in a single location of this file, in order to make etisserant@0: * possible future changes easier to edit... etisserant@0: */ etisserant@0: elementary_string_type_name: etisserant@0: STRING {$$ = new string_type_name_c();} etisserant@0: | WSTRING {$$ = new wstring_type_name_c();} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /********************************/ etisserant@0: /* B 1.3.2 - Generic data types */ etisserant@0: /********************************/ etisserant@0: /* Strangely, the following symbol does seem to be required! */ etisserant@0: /* etisserant@0: generic_type_name: etisserant@0: ANY etisserant@0: | ANY_DERIVED etisserant@0: | ANY_ELEMENTARY etisserant@0: | ANY_MAGNITUDE etisserant@0: | ANY_NUM etisserant@0: | ANY_REAL etisserant@0: | ANY_INT etisserant@0: | ANY_BIT etisserant@0: | ANY_STRING etisserant@0: | ANY_DATE etisserant@0: ; etisserant@0: */ etisserant@0: etisserant@0: etisserant@0: /********************************/ etisserant@0: /* B 1.3.3 - Derived data types */ etisserant@0: /********************************/ etisserant@0: etisserant@0: derived_type_name: etisserant@0: single_element_type_name etisserant@0: | prev_declared_array_type_name {$$ = $1;} etisserant@0: | prev_declared_structure_type_name {$$ = $1;} etisserant@0: | prev_declared_string_type_name {$$ = $1;} etisserant@0: ; etisserant@0: etisserant@0: single_element_type_name: etisserant@0: prev_declared_simple_type_name {$$ = $1;} etisserant@0: /* Include the following if arrays of function blocks are to be allowed! etisserant@0: * Since the standard does not allow them, etisserant@0: * we leave it commented out for the time being... etisserant@0: */ etisserant@0: //| prev_declared_derived_function_block_name {$$ = $1;} etisserant@0: | prev_declared_subrange_type_name {$$ = $1;} etisserant@0: | prev_declared_enumerated_type_name {$$ = $1;} etisserant@0: ; etisserant@0: etisserant@0: /* NOTE: in order to remove a reduce/reduce conflict, etisserant@0: * all occurences of simple_type_name, etc... etisserant@0: * have been replaced with identifier! etisserant@0: */ etisserant@0: /* etisserant@0: simple_type_name: identifier; etisserant@0: subrange_type_name: identifier; etisserant@0: enumerated_type_name: identifier; etisserant@0: array_type_name: identifier; etisserant@0: structure_type_name: identifier; etisserant@0: */ etisserant@0: etisserant@0: data_type_declaration: etisserant@0: TYPE type_declaration_list END_TYPE etisserant@0: {$$ = new data_type_declaration_c($2);} etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for data_type_declaration */ etisserant@0: type_declaration_list: etisserant@0: type_declaration ';' etisserant@0: {$$ = new type_declaration_list_c(); $$->add_element($1);} etisserant@0: | type_declaration_list type_declaration ';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: type_declaration: etisserant@0: single_element_type_declaration etisserant@0: | array_type_declaration etisserant@0: | structure_type_declaration etisserant@0: | string_type_declaration etisserant@0: ; etisserant@0: etisserant@0: single_element_type_declaration: etisserant@0: simple_type_declaration etisserant@0: | subrange_type_declaration etisserant@0: | enumerated_type_declaration etisserant@0: ; etisserant@0: etisserant@0: simple_type_declaration: etisserant@0: /* simple_type_name ':' simple_spec_init */ etisserant@0: identifier ':' simple_spec_init etisserant@0: {$$ = new simple_type_declaration_c($1, $3); etisserant@0: library_element_symtable.insert($1, prev_declared_simple_type_name_token); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: simple_spec_init: etisserant@0: simple_specification etisserant@0: /* The following line was changed so that we wouldn't etisserant@0: * have the first element of a simple_spec_init_c() etisserant@0: * pointing to another simple_spec_init_c! etisserant@0: */ etisserant@0: /* etisserant@0: | simple_specification ASSIGN constant etisserant@0: {$$ = new simple_spec_init_c($1, $3);} etisserant@0: */ etisserant@0: | elementary_type_name ASSIGN constant etisserant@0: {$$ = new simple_spec_init_c($1, $3);} etisserant@0: | prev_declared_simple_type_name ASSIGN constant etisserant@0: {$$ = new simple_spec_init_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: /* When converting to C/C++, we need to know whether etisserant@0: * the elementary_type_name is being used in a variable etisserant@0: * declaration or elsewhere (ex. declaration of a derived etisserant@0: * type), so the abstract syntax has the elementary_type_name etisserant@0: * wrapped inside a simple_spec_init_c. etisserant@0: * The exact same thing occurs with prev_declared_simple_type_name. etisserant@0: * etisserant@0: * This is why in the definition of simple_spec_init, etisserant@0: * simple_specification was brocken up into its etisserant@0: * constituent components... etisserant@0: */ etisserant@0: simple_specification: etisserant@0: // elementary_type_name | simple_type_name etisserant@0: elementary_type_name etisserant@0: {$$ = new simple_spec_init_c($1, NULL);} etisserant@0: | prev_declared_simple_type_name etisserant@0: {$$ = new simple_spec_init_c($1, NULL);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: subrange_type_declaration: etisserant@0: /* subrange_type_name ':' subrange_spec_init */ etisserant@0: identifier ':' subrange_spec_init etisserant@0: {$$ = new subrange_type_declaration_c($1, $3); etisserant@0: library_element_symtable.insert($1, prev_declared_subrange_type_name_token); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: subrange_spec_init: etisserant@0: subrange_specification etisserant@0: {$$ = new subrange_spec_init_c($1, NULL);} etisserant@0: | subrange_specification ASSIGN signed_integer etisserant@0: {$$ = new subrange_spec_init_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: subrange_specification: etisserant@0: integer_type_name '(' subrange')' etisserant@0: {$$ = new subrange_specification_c($1, $3);} etisserant@0: | prev_declared_subrange_type_name {$$ = $1;} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: subrange: etisserant@0: signed_integer DOTDOT signed_integer etisserant@0: {$$ = new subrange_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: enumerated_type_declaration: etisserant@0: /* enumerated_type_name ':' enumerated_spec_init */ etisserant@0: identifier ':' enumerated_spec_init etisserant@0: {$$ = new enumerated_type_declaration_c($1, $3); etisserant@0: library_element_symtable.insert($1, prev_declared_enumerated_type_name_token); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: enumerated_spec_init: etisserant@0: enumerated_specification etisserant@0: {$$ = new enumerated_spec_init_c($1, NULL);} etisserant@0: | enumerated_specification ASSIGN enumerated_value etisserant@0: {$$ = new enumerated_spec_init_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: enumerated_specification: etisserant@0: '(' enumerated_value_list ')' etisserant@0: {$$ = $2;} etisserant@0: | prev_declared_enumerated_type_name {$$ = $1;} etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for enumerated_specification */ etisserant@0: enumerated_value_list: etisserant@0: enumerated_value etisserant@0: {$$ = new enumerated_value_list_c(); $$->add_element($1);} etisserant@0: | enumerated_value_list ',' enumerated_value etisserant@0: {$$ = $1; $$->add_element($3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: enumerated_value: etisserant@0: identifier etisserant@0: {$$ = $1;} etisserant@0: | prev_declared_enumerated_type_name '#' any_identifier etisserant@0: {$$ = new enumerated_value_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: array_type_declaration: etisserant@0: /* array_type_name ':' array_spec_init */ etisserant@0: identifier ':' array_spec_init etisserant@0: {$$ = new array_type_declaration_c($1, $3); etisserant@0: library_element_symtable.insert($1, prev_declared_array_type_name_token); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: array_spec_init: etisserant@0: array_specification etisserant@0: {$$ = new array_spec_init_c($1, NULL);} etisserant@0: | array_specification ASSIGN array_initialization etisserant@0: {$$ = new array_spec_init_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: array_specification: etisserant@0: prev_declared_array_type_name etisserant@0: {$$ = $1;} etisserant@0: | ARRAY '[' array_subrange_list ']' OF non_generic_type_name etisserant@0: {$$ = new array_specification_c($3, $6);} etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for array_specification */ etisserant@0: array_subrange_list: etisserant@0: subrange etisserant@0: {$$ = new array_subrange_list_c(); $$->add_element($1);} etisserant@0: | array_subrange_list ',' subrange etisserant@0: {$$ = $1; $$->add_element($1);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: array_initialization: etisserant@0: '[' array_initial_elements_list ']' etisserant@0: {$$ = $2;} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* helper symbol for array_initialization */ etisserant@0: array_initial_elements_list: etisserant@0: array_initial_elements etisserant@0: {$$ = new array_initial_elements_list_c(); $$->add_element($1);} etisserant@0: | array_initial_elements_list ',' array_initial_elements etisserant@0: {$$ = $1; $$->add_element($3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: array_initial_elements: etisserant@0: array_initial_element etisserant@0: | integer '(' ')' etisserant@0: | integer '(' array_initial_element ')' etisserant@0: {$$ = new array_initial_elements_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: array_initial_element: etisserant@0: constant etisserant@0: | enumerated_value etisserant@0: | structure_initialization etisserant@0: | array_initialization etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: structure_type_declaration: etisserant@0: /* structure_type_name ':' structure_specification */ etisserant@0: identifier ':' structure_specification etisserant@0: {$$ = new structure_type_declaration_c($1, $3); etisserant@0: library_element_symtable.insert($1, prev_declared_structure_type_name_token); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: structure_specification: etisserant@0: structure_declaration etisserant@0: | initialized_structure etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: initialized_structure: etisserant@0: prev_declared_structure_type_name etisserant@0: {$$ = new initialized_structure_c($1, NULL);} etisserant@0: | prev_declared_structure_type_name ASSIGN structure_initialization etisserant@0: {$$ = new initialized_structure_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: structure_declaration: etisserant@0: STRUCT structure_element_declaration_list END_STRUCT etisserant@0: {$$ = $2;} etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for structure_declaration */ etisserant@0: structure_element_declaration_list: etisserant@0: structure_element_declaration ';' etisserant@0: {$$ = new structure_element_declaration_list_c(); $$->add_element($1);} etisserant@0: | structure_element_declaration_list structure_element_declaration ';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: structure_element_declaration: etisserant@0: structure_element_name ':' simple_spec_init etisserant@0: {$$ = new structure_element_declaration_c($1, $3);} etisserant@0: | structure_element_name ':' subrange_spec_init etisserant@0: {$$ = new structure_element_declaration_c($1, $3);} etisserant@0: | structure_element_name ':' enumerated_spec_init etisserant@0: {$$ = new structure_element_declaration_c($1, $3);} etisserant@0: | structure_element_name ':' array_spec_init etisserant@0: {$$ = new structure_element_declaration_c($1, $3);} etisserant@0: | structure_element_name ':' initialized_structure etisserant@0: {$$ = new structure_element_declaration_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: structure_element_name: any_identifier; etisserant@0: etisserant@0: etisserant@0: structure_initialization: etisserant@0: '(' structure_element_initialization_list ')' etisserant@0: {$$ = $2;} etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for structure_initialization */ etisserant@0: structure_element_initialization_list: etisserant@0: structure_element_initialization etisserant@0: {$$ = new structure_element_initialization_list_c(); $$->add_element($1);} etisserant@0: | structure_element_initialization_list ',' structure_element_initialization etisserant@0: {$$ = $1; $$->add_element($3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: structure_element_initialization: etisserant@0: structure_element_name ASSIGN constant etisserant@0: {$$ = new structure_element_initialization_c($1, $3);} etisserant@0: | structure_element_name ASSIGN enumerated_value etisserant@0: {$$ = new structure_element_initialization_c($1, $3);} etisserant@0: | structure_element_name ASSIGN array_initialization etisserant@0: {$$ = new structure_element_initialization_c($1, $3);} etisserant@0: | structure_element_name ASSIGN structure_initialization etisserant@0: {$$ = new structure_element_initialization_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: /* NOTE: in order to remove a reduce/reduce conflict, etisserant@0: * all occurences of string_type_name etisserant@0: * have been replaced with identifier! etisserant@0: */ etisserant@0: /* etisserant@0: string_type_name: identifier; etisserant@0: */ etisserant@0: etisserant@0: string_type_declaration: etisserant@0: /* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */ etisserant@0: identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init etisserant@0: {$$ = new string_type_declaration_c($1, $3, $4, $5); etisserant@0: library_element_symtable.insert($1, prev_declared_string_type_name_token); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* helper symbol for string_type_declaration */ etisserant@0: string_type_declaration_size: etisserant@0: '[' integer ']' etisserant@0: {$$ = $2;} etisserant@0: /* REMOVED !! */ etisserant@0: //| /* empty */ etisserant@0: // {$$ = NULL;} etisserant@0: ; etisserant@0: /* The syntax contains a reduce/reduce conflict. etisserant@0: * The optional '[' ']' etisserant@0: * has been changed to become mandatory to remove the conflict. etisserant@0: * etisserant@0: * The conflict arises because etisserant@0: * new_str_type : STRING := "hello!" etisserant@0: * may be reduced to a string_type_declaration OR etisserant@0: * a simple_type_declaration. etisserant@0: * etisserant@0: * Our change forces it to be reduced to a etisserant@0: * simple_type_declaration! etisserant@0: * We chose this option because changing the definition etisserant@0: * of simple_spec_init would force us to change all the other etisserant@0: * rules in which it appears. The change we made has no etisserant@0: * side-effects! etisserant@0: */ etisserant@0: etisserant@0: /* helper symbol for string_type_declaration */ etisserant@0: string_type_declaration_init: etisserant@0: /* empty */ etisserant@0: {$$ = NULL;} etisserant@0: | ASSIGN character_string etisserant@0: {$$ = $2;} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /*********************/ etisserant@0: /* B 1.4 - Variables */ etisserant@0: /*********************/ etisserant@0: variable: etisserant@0: symbolic_variable etisserant@0: | direct_variable etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: symbolic_variable: etisserant@0: /* NOTE: To be entirely correct, variable_name should be replacemed by etisserant@0: * prev_declared_variable_name | prev_declared_fb_name | prev_declared_global_var_name etisserant@0: */ etisserant@0: prev_declared_variable_name etisserant@0: {$$ = new symbolic_variable_c($1);} etisserant@0: | prev_declared_fb_name etisserant@0: {$$ = new symbolic_variable_c($1);} etisserant@0: | prev_declared_global_var_name etisserant@0: {$$ = new symbolic_variable_c($1);} etisserant@0: | multi_element_variable etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* NOTE: in section B 1.7, when configuring a program, symbolic_variable etisserant@0: * is used. Nevertheless, during the parsing of a configuration, etisserant@0: * the variables in question are out of scope, so we should etisserant@0: * be allowing any_identifier instead of prev_declared_variable_name! etisserant@0: * etisserant@0: * We therefore need a new any_symbolic_variable construct that etisserant@0: * allows the use of any_identifier instead of previously declared etisserant@0: * variables, function blocks, etc... etisserant@0: */ etisserant@0: any_symbolic_variable: etisserant@0: // variable_name -> replaced by any_identifier etisserant@0: any_identifier etisserant@0: {$$ = new symbolic_variable_c($1);} etisserant@0: | any_multi_element_variable etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* for yet undeclared variable names ! */ etisserant@0: variable_name: identifier; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /********************************************/ etisserant@0: /* B.1.4.1 Directly Represented Variables */ etisserant@0: /********************************************/ etisserant@0: direct_variable: direct_variable_token {$$ = new direct_variable_c($1);}; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /*************************************/ etisserant@0: /* B.1.4.2 Multi-element Variables */ etisserant@0: /*************************************/ etisserant@0: multi_element_variable: etisserant@0: array_variable etisserant@0: | structured_variable etisserant@0: ; etisserant@0: etisserant@0: /* please see note above any_symbolic_variable */ etisserant@0: any_multi_element_variable: etisserant@0: any_array_variable etisserant@0: | any_structured_variable etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: array_variable: etisserant@0: subscripted_variable '[' subscript_list ']' etisserant@0: {$$ = new array_variable_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: /* please see note above any_symbolic_variable */ etisserant@0: any_array_variable: etisserant@0: any_subscripted_variable '[' subscript_list ']' etisserant@0: {$$ = new array_variable_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: subscripted_variable: etisserant@0: symbolic_variable etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* please see note above any_symbolic_variable */ etisserant@0: any_subscripted_variable: etisserant@0: any_symbolic_variable etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: subscript_list: etisserant@0: subscript etisserant@0: {$$ = new subscript_list_c(); $$->add_element($1);} etisserant@0: | subscript_list ',' subscript etisserant@0: {$$ = $1; $$->add_element($3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: subscript: expression; etisserant@0: etisserant@0: etisserant@0: structured_variable: etisserant@0: record_variable '.' field_selector etisserant@0: {$$ = new structured_variable_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* please see note above any_symbolic_variable */ etisserant@0: any_structured_variable: etisserant@0: any_record_variable '.' field_selector etisserant@0: {$$ = new structured_variable_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: record_variable: etisserant@0: symbolic_variable etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* please see note above any_symbolic_variable */ etisserant@0: any_record_variable: etisserant@0: any_symbolic_variable etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: field_selector: any_identifier; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /******************************************/ etisserant@0: /* B 1.4.3 - Declaration & Initialisation */ etisserant@0: /******************************************/ etisserant@0: input_declarations: etisserant@0: VAR_INPUT input_declaration_list END_VAR etisserant@0: {$$ = new input_declarations_c(NULL, $2);} etisserant@0: | VAR_INPUT RETAIN input_declaration_list END_VAR etisserant@0: {$$ = new input_declarations_c(new retain_option_c(), $3);} etisserant@0: | VAR_INPUT NON_RETAIN input_declaration_list END_VAR etisserant@0: {$$ = new input_declarations_c(new non_retain_option_c(), $3);} etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for input_declarations */ etisserant@0: input_declaration_list: etisserant@0: input_declaration ';' etisserant@0: {$$ = new input_declaration_list_c(); $$->add_element($1);} etisserant@0: | input_declaration_list input_declaration ';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: input_declaration: etisserant@0: var_init_decl etisserant@0: | edge_declaration etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: edge_declaration: etisserant@0: var1_list ':' BOOL R_EDGE etisserant@0: {$$ = new edge_declaration_c(new raising_edge_option_c(), $1);} etisserant@0: | var1_list ':' BOOL F_EDGE etisserant@0: {$$ = new edge_declaration_c(new falling_edge_option_c(), $1);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: var_init_decl: etisserant@0: var1_init_decl etisserant@0: | array_var_init_decl etisserant@0: | structured_var_init_decl etisserant@0: | fb_name_decl etisserant@0: | string_var_declaration etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: var1_init_decl: etisserant@0: var1_list ':' simple_spec_init etisserant@0: {$$ = new var1_init_decl_c($1, $3);} etisserant@0: | var1_list ':' subrange_spec_init etisserant@0: {$$ = new var1_init_decl_c($1, $3);} etisserant@0: | var1_list ':' enumerated_spec_init etisserant@0: {$$ = new var1_init_decl_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: var1_list: etisserant@0: variable_name etisserant@0: {$$ = new var1_list_c(); $$->add_element($1); etisserant@0: variable_name_symtable.insert($1, prev_declared_variable_name_token); etisserant@0: } etisserant@0: | var1_list ',' variable_name etisserant@0: {$$ = $1; $$->add_element($3); etisserant@0: variable_name_symtable.insert($3, prev_declared_variable_name_token); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: array_var_init_decl: etisserant@0: var1_list ':' array_spec_init etisserant@0: {$$ = new array_var_init_decl_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: structured_var_init_decl: etisserant@0: var1_list ':' initialized_structure etisserant@0: {$$ = new structured_var_init_decl_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* NOTE: see notes above fb_name_list and var1_list etisserant@0: * for reason why ':' was removed from this rule! etisserant@0: * In essence, to remove a shift/reduce conflict, etisserant@0: * the ':' was moved to var1_list and fb_name_list! etisserant@0: */ etisserant@0: fb_name_decl: etisserant@0: /* fb_name_list ':' function_block_type_name */ etisserant@0: fb_name_list_with_colon function_block_type_name etisserant@0: {$$ = new fb_name_decl_c($1, $2, NULL);} etisserant@0: /*| fb_name_list ':' function_block_type_name ASSIGN structure_initialization */ etisserant@0: | fb_name_list_with_colon function_block_type_name ASSIGN structure_initialization etisserant@0: {$$ = new fb_name_decl_c($1, $2, $4);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /* NOTE: In order to remove a reduce/reduce conflict between etisserant@0: * var1_list and fb_name_list, which are identical to each etisserant@0: * other, fb_name_list has been redefined to be a var1_list. etisserant@0: * etisserant@0: * In order to remove a further shift/reduce conflict, var1_list etisserant@0: * is imediately transfomred into var1_list_with_colon etisserant@0: * (i.e. it includes the ':' following the list), which etisserant@0: * means that fb_name_list is built from a etisserant@0: * var1_list_with_colon after all! etisserant@0: */ etisserant@0: /* etisserant@0: fb_name_list: etisserant@0: (* fb_name *) etisserant@0: identifier etisserant@0: {$$ = new fb_name_list_c($1); etisserant@0: variable_name_symtable.insert($1, prev_declared_fb_name_token); etisserant@0: } etisserant@0: (* | fb_name_list ',' fb_name *) etisserant@0: | fb_name_list ',' identifier etisserant@0: {$$ = $1; $$->add_element($3); etisserant@0: variable_name_symtable.insert($3, prev_declared_fb_name_token); etisserant@0: } etisserant@0: ; etisserant@0: */ etisserant@0: etisserant@0: fb_name_list_with_colon: etisserant@0: var1_list_with_colon etisserant@0: {$$ = new fb_name_list_c(); etisserant@0: /* fill up the new fb_name_list_c object with the references etisserant@0: * contained in the var1_list_c object. etisserant@0: */ etisserant@0: FOR_EACH_ELEMENT(elem, $1, {$$->add_element(elem);}); etisserant@0: delete $1; etisserant@0: /* change the tokens associated with the symbols stored in etisserant@0: * the variable name symbol table from prev_declared_variable_name_token etisserant@0: * to prev_declared_fb_name_token etisserant@0: */ etisserant@0: FOR_EACH_ELEMENT(elem, $$, {variable_name_symtable.set(elem, prev_declared_fb_name_token);}); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for fb_name_list_with_colon */ etisserant@0: var1_list_with_colon: etisserant@0: var1_list ':' etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: // fb_name: identifier; etisserant@0: etisserant@0: etisserant@0: etisserant@0: output_declarations: etisserant@0: VAR_OUTPUT var_init_decl_list END_VAR etisserant@0: {$$ = new output_declarations_c(NULL, $2);} etisserant@0: | VAR_OUTPUT RETAIN var_init_decl_list END_VAR etisserant@0: {$$ = new output_declarations_c(new retain_option_c(), $3);} etisserant@0: | VAR_OUTPUT NON_RETAIN var_init_decl_list END_VAR etisserant@0: {$$ = new output_declarations_c(new non_retain_option_c(), $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: input_output_declarations: etisserant@0: VAR_IN_OUT var_declaration_list END_VAR etisserant@0: {$$ = new input_output_declarations_c($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /* helper symbol for input_output_declarations */ etisserant@0: var_declaration_list: etisserant@0: var_declaration ';' etisserant@0: {$$ = new var_declaration_list_c(); $$->add_element($1);} etisserant@0: | var_declaration_list var_declaration ';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: var_declaration: etisserant@0: temp_var_decl etisserant@0: | fb_name_decl etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: temp_var_decl: etisserant@0: var1_declaration etisserant@0: | array_var_declaration etisserant@0: | structured_var_declaration etisserant@0: | string_var_declaration etisserant@0: ; etisserant@0: etisserant@0: var1_declaration: etisserant@0: var1_list ':' simple_specification etisserant@0: {$$ = new var1_init_decl_c($1, $3);} etisserant@0: | var1_list ':' subrange_specification etisserant@0: {$$ = new var1_init_decl_c($1, $3);} etisserant@0: | var1_list ':' enumerated_specification etisserant@0: {$$ = new var1_init_decl_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: array_var_declaration: etisserant@0: var1_list ':' array_specification etisserant@0: {$$ = new array_var_declaration_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: structured_var_declaration: etisserant@0: var1_list ':' prev_declared_structure_type_name etisserant@0: {$$ = new structured_var_declaration_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: var_declarations: etisserant@0: VAR var_init_decl_list END_VAR etisserant@0: {$$ = new var_declarations_c(NULL, $2);} etisserant@0: | VAR CONSTANT var_init_decl_list END_VAR etisserant@0: {$$ = new var_declarations_c(new constant_option_c(), $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: retentive_var_declarations: etisserant@0: VAR RETAIN var_init_decl_list END_VAR etisserant@0: {$$ = new retentive_var_declarations_c($3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: located_var_declarations: etisserant@0: VAR located_var_decl_list END_VAR etisserant@0: {$$ = new located_var_declarations_c(NULL, $2);} etisserant@0: | VAR CONSTANT located_var_decl_list END_VAR etisserant@0: {$$ = new located_var_declarations_c(new constant_option_c(), $3);} etisserant@0: | VAR RETAIN located_var_decl_list END_VAR etisserant@0: {$$ = new located_var_declarations_c(new retain_option_c(), $3);} etisserant@0: | VAR NON_RETAIN located_var_decl_list END_VAR etisserant@0: {$$ = new located_var_declarations_c(new non_retain_option_c(), $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* helper symbol for located_var_declarations */ etisserant@0: located_var_decl_list: etisserant@0: located_var_decl ';' etisserant@0: {$$ = new located_var_decl_list_c(); $$->add_element($1);} etisserant@0: | located_var_decl_list located_var_decl ';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: located_var_decl: etisserant@0: variable_name location ':' located_var_spec_init etisserant@0: {$$ = new located_var_decl_c($1, $2, $4); etisserant@0: variable_name_symtable.insert($1, prev_declared_variable_name_token); etisserant@0: } etisserant@0: | location ':' located_var_spec_init etisserant@0: {$$ = new located_var_decl_c(NULL, $1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: external_var_declarations: etisserant@0: VAR_EXTERNAL external_declaration_list END_VAR etisserant@0: {$$ = new external_var_declarations_c(NULL, $2);} etisserant@0: | VAR_EXTERNAL CONSTANT external_declaration_list END_VAR etisserant@0: {$$ = new external_var_declarations_c(new constant_option_c(), $3);} etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for external_var_declarations */ etisserant@0: external_declaration_list: etisserant@0: external_declaration ';' etisserant@0: {$$ = new external_declaration_list_c(); $$->add_element($1);} etisserant@0: | external_declaration_list external_declaration';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: external_declaration: etisserant@0: global_var_name ':' simple_specification etisserant@0: {$$ = new external_declaration_c($1, $3); etisserant@0: variable_name_symtable.insert($1, prev_declared_variable_name_token); etisserant@0: } etisserant@0: | global_var_name ':' subrange_specification etisserant@0: {$$ = new external_declaration_c($1, $3); etisserant@0: variable_name_symtable.insert($1, prev_declared_variable_name_token); etisserant@0: } etisserant@0: | global_var_name ':' enumerated_specification etisserant@0: {$$ = new external_declaration_c($1, $3); etisserant@0: variable_name_symtable.insert($1, prev_declared_variable_name_token); etisserant@0: } etisserant@0: | global_var_name ':' array_specification etisserant@0: {$$ = new external_declaration_c($1, $3); etisserant@0: variable_name_symtable.insert($1, prev_declared_variable_name_token); etisserant@0: } etisserant@0: | global_var_name ':' prev_declared_structure_type_name etisserant@0: {$$ = new external_declaration_c($1, $3); etisserant@0: variable_name_symtable.insert($1, prev_declared_variable_name_token); etisserant@0: } etisserant@0: | global_var_name ':' function_block_type_name etisserant@0: {$$ = new external_declaration_c($1, $3); etisserant@0: variable_name_symtable.insert($1, prev_declared_fb_name_token); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: global_var_name: identifier; etisserant@0: etisserant@0: etisserant@0: global_var_declarations: etisserant@0: VAR_GLOBAL global_var_decl_list END_VAR etisserant@0: {$$ = new global_var_declarations_c(NULL, $2);} etisserant@0: | VAR_GLOBAL CONSTANT global_var_decl_list END_VAR etisserant@0: {$$ = new global_var_declarations_c(new constant_option_c(), $3);} etisserant@0: | VAR_GLOBAL RETAIN global_var_decl_list END_VAR etisserant@0: {$$ = new global_var_declarations_c(new retain_option_c(), $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* helper symbol for global_var_declarations */ etisserant@0: global_var_decl_list: etisserant@0: global_var_decl ';' etisserant@0: {$$ = new global_var_decl_list_c(); $$->add_element($1);} etisserant@0: | global_var_decl_list global_var_decl ';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: global_var_decl: etisserant@0: global_var_spec ':' etisserant@0: {$$ = new global_var_decl_c($1, NULL);} etisserant@0: | global_var_spec ':' located_var_spec_init etisserant@0: {$$ = new global_var_decl_c($1, $3);} etisserant@0: | global_var_spec ':' function_block_type_name etisserant@0: {$$ = new global_var_decl_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: global_var_spec: etisserant@0: global_var_list {$$ = $1;} etisserant@0: | location etisserant@0: | global_var_name location etisserant@0: {$$ = new global_var_spec_c($1, $2); etisserant@0: variable_name_symtable.insert($1, prev_declared_global_var_name_token); etisserant@0: } etisserant@0: etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: located_var_spec_init: etisserant@0: simple_spec_init etisserant@0: | subrange_spec_init etisserant@0: | enumerated_spec_init etisserant@0: | array_spec_init etisserant@0: | initialized_structure etisserant@0: | single_byte_string_spec etisserant@0: | double_byte_string_spec etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: location: etisserant@0: AT direct_variable etisserant@0: {$$ = new location_c($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: global_var_list: etisserant@0: global_var_name etisserant@0: {$$ = new global_var_list_c(); $$->add_element($1); etisserant@0: variable_name_symtable.insert($1, prev_declared_global_var_name_token); etisserant@0: } etisserant@0: | global_var_list ',' global_var_name etisserant@0: {$$ = $1; $$->add_element($3); etisserant@0: variable_name_symtable.insert($3, prev_declared_global_var_name_token); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: string_var_declaration: etisserant@0: single_byte_string_var_declaration etisserant@0: | double_byte_string_var_declaration etisserant@0: ; etisserant@0: etisserant@0: single_byte_string_var_declaration: etisserant@0: var1_list ':' single_byte_string_spec etisserant@0: {$$ = new single_byte_string_var_declaration_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: /* NOTE: The constructs etisserant@0: * etisserant@0: * [W]STRING etisserant@0: * and etisserant@0: * [W]STRING ASSIGN single_byte_character_string etisserant@0: * etisserant@0: * were removed as they are already contained etisserant@0: * within a other constructs. etisserant@0: * etisserant@0: * single_byte_string_spec is used in: etisserant@0: * - single_byte_string_var_declaration -> etisserant@0: * -> string_var_declaration ---> var_init_decl etisserant@0: * |--> temp_var_decl etisserant@0: * |--> var2_init_decl etisserant@0: * - located_var_spec_init etisserant@0: * etisserant@0: * STRING [ASSIGN string_constant] -> elementary_string_type_name -> etisserant@0: * -> simple_spec -> simple_specification -> simple_spec_init -> etisserant@0: * -> located_var_spec_init etisserant@0: * etisserant@0: * STRING [ASSIGN string_constant] -> elementary_string_type_name -> etisserant@0: * -> simple_spec -> simple_specification -> simple_spec_init -> etisserant@0: * -> var1_init_decl -> var_init_decl etisserant@0: * etisserant@0: * STRING [ASSIGN string_constant] -> elementary_string_type_name -> etisserant@0: * -> simple_spec -> simple_specification -> simple_spec_init -> etisserant@0: * -> var1_init_decl -> var2_init_decl etisserant@0: * etisserant@0: * STRING [ASSIGN string_constant] -> elementary_string_type_name -> etisserant@0: * -> simple_spec -> simple_specification -> etisserant@0: * -> var1_declaration -> temp_var_decl etisserant@0: */ etisserant@0: single_byte_string_spec: etisserant@0: /* STRING etisserant@0: {$$ = new single_byte_string_spec_c(NULL, NULL);} etisserant@0: */ etisserant@0: STRING '[' integer ']' etisserant@0: {$$ = new single_byte_string_spec_c($3, NULL);} etisserant@0: /* etisserant@0: | STRING ASSIGN single_byte_character_string etisserant@0: {$$ = new single_byte_string_spec_c(NULL, $3);} etisserant@0: */ etisserant@0: | STRING '[' integer ']' ASSIGN single_byte_character_string etisserant@0: {$$ = new single_byte_string_spec_c($3, $6);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: double_byte_string_var_declaration: etisserant@0: var1_list ':' double_byte_string_spec etisserant@0: {$$ = new double_byte_string_var_declaration_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: double_byte_string_spec: etisserant@0: /* WSTRING etisserant@0: {$$ = new double_byte_string_spec_c(NULL, NULL);} etisserant@0: */ etisserant@0: WSTRING '[' integer ']' etisserant@0: {$$ = new double_byte_string_spec_c($3, NULL);} etisserant@0: /* etisserant@0: | WSTRING ASSIGN double_byte_character_string etisserant@0: {$$ = new double_byte_string_spec_c(NULL, $3);} etisserant@0: */ etisserant@0: | WSTRING '[' integer ']' ASSIGN double_byte_character_string etisserant@0: {$$ = new double_byte_string_spec_c($3, $6);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: incompl_located_var_declarations: etisserant@0: VAR incompl_located_var_decl_list END_VAR etisserant@0: {$$ = new incompl_located_var_declarations_c(NULL, $2);} etisserant@0: | VAR RETAIN incompl_located_var_decl_list END_VAR etisserant@0: {$$ = new incompl_located_var_declarations_c(new retain_option_c(), $3);} etisserant@0: | VAR NON_RETAIN incompl_located_var_decl_list END_VAR etisserant@0: {$$ = new incompl_located_var_declarations_c(new non_retain_option_c(), $3);} etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for incompl_located_var_declarations */ etisserant@0: incompl_located_var_decl_list: etisserant@0: incompl_located_var_decl ';' etisserant@0: {$$ = new incompl_located_var_decl_list_c(); $$->add_element($1);} etisserant@0: | incompl_located_var_decl_list incompl_located_var_decl ';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: incompl_located_var_decl: etisserant@0: variable_name incompl_location ':' var_spec etisserant@0: {$$ = new incompl_located_var_decl_c($1, $2, $4);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: incompl_location: etisserant@0: AT incompl_location_token etisserant@0: {$$ = new incompl_location_c($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: var_spec: etisserant@0: simple_specification etisserant@0: | subrange_specification etisserant@0: | enumerated_specification etisserant@0: | array_specification etisserant@0: | prev_declared_structure_type_name etisserant@0: | string_spec etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* helper symbol for var_spec */ etisserant@0: /* NOTE: The constructs etisserant@0: * etisserant@0: * STRING etisserant@0: * and etisserant@0: * WSTRING etisserant@0: * etisserant@0: * were removed as they are already contained etisserant@0: * within a simple_specification. etisserant@0: */ etisserant@0: string_spec: etisserant@0: /* STRING etisserant@0: {$$ = new single_byte_string_spec_c(NULL, NULL);} etisserant@0: */ etisserant@0: STRING '[' integer ']' etisserant@0: {$$ = new single_byte_string_spec_c($3, NULL);} etisserant@0: /* etisserant@0: | WSTRING etisserant@0: {$$ = new double_byte_string_spec_c(NULL, NULL);} etisserant@0: */ etisserant@0: | WSTRING '[' integer ']' etisserant@0: {$$ = new double_byte_string_spec_c($3, NULL);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /* intermediate helper symbol for: etisserant@0: * - non_retentive_var_decls etisserant@0: * - output_declarations etisserant@0: * - var_declarations etisserant@0: */ etisserant@0: var_init_decl_list: etisserant@0: var_init_decl ';' etisserant@0: {$$ = new var_init_decl_list_c(); $$->add_element($1);} etisserant@0: | var_init_decl_list var_init_decl ';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /***********************/ etisserant@0: /* B 1.5.1 - Functions */ etisserant@0: /***********************/ etisserant@0: /* The following rules should be set such as: etisserant@0: * function_name: function_name_no_clashes | function_name_simpleop_clashes | function_name_expression_clashes etisserant@0: * function_name: function_name_no_NOT_clashes | function_name_NOT_clashes; etisserant@0: */ etisserant@0: etisserant@0: function_name_no_clashes: prev_declared_derived_function_name | standard_function_name_no_clashes; etisserant@0: function_name_simpleop_clashes: standard_function_name_simpleop_clashes; etisserant@0: //function_name_expression_clashes: standard_function_name_expression_clashes; etisserant@0: etisserant@0: function_name_no_NOT_clashes: prev_declared_derived_function_name | standard_function_name_no_NOT_clashes; etisserant@0: //function_name_NOT_clashes: standard_function_name_NOT_clashes; etisserant@0: etisserant@0: /* etisserant@0: function_name: etisserant@0: prev_declared_derived_function_name etisserant@0: | standard_function_name etisserant@0: ; etisserant@0: */ etisserant@0: etisserant@0: /* NOTE: The list of standard function names etisserant@0: * includes the standard functions MOD(), NOT() etisserant@0: * etisserant@0: * Strangely enough, MOD and NOT are reserved keywords, etisserant@0: * so shouldn't be used for function names. etisserant@0: * etisserant@0: * The specification contradicts itself! etisserant@0: * Our workaround is to treat MOD as a token, etisserant@0: * but to include this token as a etisserant@0: * standard_function_name. etisserant@0: * etisserant@0: * The names of all other standard functions get etisserant@0: * preloaded into the library_element_symbol_table etisserant@0: * with the token value of etisserant@0: * standard_function_name_token etisserant@0: * Actually, simply for completeness, MOD is also etisserant@0: * loaded into the library_element_symbol_table, but etisserant@0: * it is irrelevant since flex will catch MOD as a etisserant@0: * token, before it interprets it as an identifier, etisserant@0: * and looks in the library_element_symbol_table to check etisserant@0: * whether it has been previously declared. etisserant@0: * etisserant@0: * NOTE: The same as the above also occurs with the IL etisserant@0: * operators NOT AND OR XOR ADD SUB MUL DIV MOD etisserant@0: * GT GE EQ LT LE NE. etisserant@0: * Note that MOD is once again in the list! etisserant@0: * Anyway, we give these the same treatement as etisserant@0: * MOD, since we are writing a parser for ST and etisserant@0: * IL simultaneously. If this were not the case, etisserant@0: * the ST parser would not need the tokens NOT AND ... etisserant@0: * etisserant@0: * NOTE: Note that 'NOT' is special, as it conflicts etisserant@0: * with two operators: the IL 'NOT' operator, and etisserant@0: * the unary operator 'NOT' in ST!! etisserant@0: * etisserant@0: * NOTE: The IL language is ambiguous, since using NOT, AND, ... etisserant@0: * may be interpreted as either an IL operator, or etisserant@0: * as a standard function call! etisserant@0: * I (Mario) opted to interpret it as an IL operator. etisserant@0: * This requires changing the syntax for IL language etisserant@0: * function calling, to exclude all function with etisserant@0: * names that clash with IL operators. I therefore etisserant@0: * created the constructs etisserant@0: * function_name_without_clashes etisserant@0: * standard_function_name_without_clashes etisserant@0: * to include all function names, except those that clash etisserant@0: * with IL operators. These constructs are only used etisserant@0: * within the IL language! etisserant@0: */ etisserant@0: /* The following rules should be set such as: etisserant@0: * standard_function_name: standard_function_name_no_clashes | standard_function_name_simpleop_clashes | standard_function_name_expression_clashes etisserant@0: * standard_function_name: standard_function_name_no_NOT_clashes | standard_function_name_NOT_clashes; etisserant@0: */ etisserant@0: etisserant@0: /* etisserant@0: standard_function_name: etisserant@0: standard_function_name_no_clashes etisserant@0: | standard_function_name_expression_clashes etisserant@0: | standard_function_name_NOT_clashes etisserant@0: //| standard_function_name_simpleop_only_clashes etisserant@0: ; etisserant@0: */ etisserant@0: etisserant@0: standard_function_name_no_NOT_clashes: etisserant@0: standard_function_name_no_clashes etisserant@0: | standard_function_name_expression_clashes etisserant@0: //| standard_function_name_simpleop_only_clashes etisserant@0: ; etisserant@0: etisserant@0: standard_function_name_no_clashes: etisserant@0: standard_function_name_token etisserant@0: {$$ = new identifier_c($1);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: standard_function_name_simpleop_clashes: etisserant@0: standard_function_name_NOT_clashes etisserant@0: //| standard_function_name_simpleop_only_clashes etisserant@0: ; etisserant@0: etisserant@0: standard_function_name_NOT_clashes: etisserant@0: NOT etisserant@0: {$$ = new identifier_c(strdup("NOT"));} etisserant@0: ; etisserant@0: etisserant@0: /* Add here any other IL simple operators that collide etisserant@0: * with standard function names! etisserant@0: * Don't forget to uncomment the equivalent lines in etisserant@0: * - standard_function_name_simpleop_clashes etisserant@0: * - standard_function_name etisserant@0: * - standard_function_name_no_NOT_clashes etisserant@0: */ etisserant@0: /* etisserant@0: standard_function_name_simpleop_only_clashes: etisserant@0: ; etisserant@0: */ etisserant@0: etisserant@0: standard_function_name_expression_clashes: etisserant@0: AND_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: //NOTE: AND2 (corresponding to the source code string '&') does not clash etisserant@0: // with a standard function name, so should be commented out! etisserant@0: //| AND2_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | OR_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | XOR_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | ADD_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | SUB_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | MUL_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | DIV_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | MOD_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | GT_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | GE_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | EQ_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | LT_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | LE_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: | NE_operator {$$ = il_operator_c_2_identifier_c($1);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: derived_function_name: etisserant@0: identifier etisserant@0: | prev_declared_derived_function_name etisserant@0: {$$ = $1; etisserant@0: if (not(allow_function_overloading)) etisserant@0: ERROR; etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: function_declaration: etisserant@0: /* FUNCTION derived_function_name ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ etisserant@0: function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION etisserant@0: {$$ = new function_declaration_c($1, $3, $4, $5); etisserant@0: variable_name_symtable.pop(); etisserant@0: if (allow_function_overloading) { etisserant@0: switch (library_element_symtable.find_value($1)) { etisserant@0: case prev_declared_derived_function_name_token: etisserant@0: /* do nothing, already in map. */ etisserant@0: break; etisserant@0: case BOGUS_TOKEN_ID: etisserant@0: /* Not yet in map. Must insert...*/ etisserant@0: library_element_symtable.insert($1, prev_declared_derived_function_name_token); etisserant@0: break; etisserant@0: default: etisserant@0: /* Already in map but associated with something else other than a funtion name! */ etisserant@0: ERROR; etisserant@0: } etisserant@0: } else { etisserant@0: library_element_symtable.insert($1, prev_declared_derived_function_name_token); etisserant@0: } etisserant@0: } etisserant@0: /* | FUNCTION derived_function_name ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ etisserant@0: | function_name_declaration ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION etisserant@0: {$$ = new function_declaration_c($1, $3, $4, $5); etisserant@0: variable_name_symtable.pop(); etisserant@0: if (allow_function_overloading) { etisserant@0: switch (library_element_symtable.find_value($1)) { etisserant@0: case prev_declared_derived_function_name_token: /* do nothing, already in map. */ break; etisserant@0: case BOGUS_TOKEN_ID: library_element_symtable.insert($1, prev_declared_derived_function_name_token); break; etisserant@0: default: ERROR; etisserant@0: } etisserant@0: } else { etisserant@0: library_element_symtable.insert($1, prev_declared_derived_function_name_token); etisserant@0: } etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for function_declaration */ etisserant@0: /* NOTE: due to reduce/reduce conflicts between identifiers etisserant@0: * being reduced to either a variable or an enumerator value, etisserant@0: * we were forced to keep a symbol table of the names etisserant@0: * of all declared variables. Variables are no longer etisserant@0: * created from simple identifier_token, but from etisserant@0: * prev_declared_variable_name_token. etisserant@0: * etisserant@0: * BUT, in functions the function name itself may be used as etisserant@0: * a variable! In order to be able to parse this correctly, etisserant@0: * the token parser (flex) must return a prev_declared_variable_name_token etisserant@0: * when it comes across the function name, while parsing etisserant@0: * the function itself. etisserant@0: * We do this by inserting the function name into the variable etisserant@0: * symbol table, and having flex return a prev_declared_variable_name_token etisserant@0: * whenever it comes across it. etisserant@0: * When we finish parsing the function the variable name etisserant@0: * symbol table is cleared of all entries, and the function etisserant@0: * name is inserted into the library element symbol table. This etisserant@0: * means that from then onwards flex will return a etisserant@0: * derived_function_name_token whenever it comes across the etisserant@0: * function name. etisserant@0: * etisserant@0: * In order to insert the function name into the variable_name etisserant@0: * symbol table BEFORE the function body gets parsed, we etisserant@0: * need the parser to reduce a construct that contains the etisserant@0: * the function name. That is why we created this extra etisserant@0: * construct (function_name_declaration), i.e. to force etisserant@0: * the parser to reduce it, before parsing the function body! etisserant@0: */ etisserant@0: function_name_declaration: etisserant@0: FUNCTION derived_function_name etisserant@0: {$$ = $2; etisserant@0: /* the function name functions as a etisserant@0: * variable within the function itself! etisserant@0: * etisserant@0: * Remember that the variable_name_symtable etisserant@0: * is cleared once the end of the function etisserant@0: * is parsed. etisserant@0: */ etisserant@0: variable_name_symtable.insert($2, prev_declared_variable_name_token); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /* intermediate helper symbol for function_declaration */ etisserant@0: io_OR_function_var_declarations_list: etisserant@0: /* empty */ etisserant@0: {$$ = new var_declarations_list_c();} etisserant@0: | io_OR_function_var_declarations_list io_var_declarations etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: | io_OR_function_var_declarations_list function_var_decls etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: io_var_declarations: etisserant@0: input_declarations etisserant@0: | output_declarations etisserant@0: | input_output_declarations etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: function_var_decls: etisserant@0: VAR CONSTANT var2_init_decl_list END_VAR etisserant@0: {$$ = new function_var_decls_c(new constant_option_c(), $3);} etisserant@0: | VAR var2_init_decl_list END_VAR etisserant@0: {$$ = new function_var_decls_c(NULL, $2);} etisserant@0: ; etisserant@0: etisserant@0: /* intermediate helper symbol for function_var_decls */ etisserant@0: var2_init_decl_list: etisserant@0: var2_init_decl ';' etisserant@0: {$$ = new var2_init_decl_list_c(); $$->add_element($1);} etisserant@0: | var2_init_decl_list var2_init_decl ';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: function_body: etisserant@0: statement_list {$$ = $1;} /* if we leave it for the default action we get a type clash! */ etisserant@0: | instruction_list {$$ = $1;} /* if we leave it for the default action we get a type clash! */ etisserant@0: /* etisserant@0: | ladder_diagram etisserant@0: | function_block_diagram etisserant@0: */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: var2_init_decl: etisserant@0: var1_init_decl etisserant@0: | array_var_init_decl etisserant@0: | structured_var_init_decl etisserant@0: | string_var_declaration etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /*****************************/ etisserant@0: /* B 1.5.2 - Function Blocks */ etisserant@0: /*****************************/ etisserant@0: function_block_type_name: etisserant@0: prev_declared_derived_function_block_name etisserant@0: | standard_function_block_name etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: standard_function_block_name: standard_function_block_name_token {$$ = new identifier_c($1);}; etisserant@0: etisserant@0: derived_function_block_name: identifier; etisserant@0: etisserant@0: etisserant@0: function_block_declaration: etisserant@0: FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK etisserant@0: {$$ = new function_block_declaration_c($2, $3, $4); etisserant@0: library_element_symtable.insert($2, prev_declared_derived_function_block_name_token); etisserant@0: /* Clear the variable_name_symtable. Since etisserant@0: * we have finished parsing the function block, etisserant@0: * the variable names are now out of scope, so etisserant@0: * are no longer valid! etisserant@0: */ etisserant@0: variable_name_symtable.pop(); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /* intermediate helper symbol for function_declaration */ etisserant@0: /* { io_var_declarations | other_var_declarations } */ etisserant@0: /* etisserant@0: * NOTE: we re-use the var_declarations_list_c etisserant@0: */ etisserant@0: io_OR_other_var_declarations_list: etisserant@0: /* empty */ etisserant@0: {$$ = new var_declarations_list_c();} etisserant@0: | io_OR_other_var_declarations_list io_var_declarations etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: | io_OR_other_var_declarations_list other_var_declarations etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: /* NOTE: etisserant@0: * The IEC specification gives the following definition: etisserant@0: * other_var_declarations ::= etisserant@0: * external_var_declarations etisserant@0: * | var_declarations etisserant@0: * | retentive_var_declarations etisserant@0: * | non_retentive_var_declarations etisserant@0: * | temp_var_decls etisserant@0: * | incompl_located_var_declarations etisserant@0: * etisserant@0: * Nvertheless, the symbol non_retentive_var_declarations etisserant@0: * is not defined in the spec. This seems to me (Mario) etisserant@0: * to be a typo, so non_retentive_var_declarations etisserant@0: * has been replaced with non_retentive_var_decls etisserant@0: * in the following rule! etisserant@0: */ etisserant@0: other_var_declarations: etisserant@0: temp_var_decls etisserant@0: | non_retentive_var_decls etisserant@0: | external_var_declarations etisserant@0: | var_declarations etisserant@0: | retentive_var_declarations etisserant@0: | incompl_located_var_declarations etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: temp_var_decls: etisserant@0: VAR_TEMP temp_var_decls_list END_VAR etisserant@0: {$$ = new temp_var_decls_c($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* intermediate helper symbol for temp_var_decls */ etisserant@0: temp_var_decls_list: etisserant@0: temp_var_decl ';' etisserant@0: {$$ = new temp_var_decls_list_c(); $$->add_element($1);} etisserant@0: | temp_var_decls_list temp_var_decl ';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: non_retentive_var_decls: etisserant@0: VAR NON_RETAIN var_init_decl_list END_VAR etisserant@0: {$$ = new non_retentive_var_decls_c($3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: function_block_body: etisserant@0: statement_list {$$ = $1;} etisserant@0: | instruction_list {$$ = $1;} etisserant@1: | sequential_function_chart {$$ = $1;} etisserant@0: /* etisserant@0: | ladder_diagram etisserant@0: | function_block_diagram etisserant@0: | etisserant@0: */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /**********************/ etisserant@0: /* B 1.5.3 - Programs */ etisserant@0: /**********************/ etisserant@0: program_type_name: identifier; etisserant@0: etisserant@0: etisserant@0: program_declaration: etisserant@0: PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM etisserant@0: {$$ = new program_declaration_c($2, $3, $4); etisserant@0: library_element_symtable.insert($2, prev_declared_program_type_name_token); etisserant@0: /* Clear the variable_name_symtable. Since etisserant@0: * we have finished parsing the program declaration, etisserant@0: * the variable names are now out of scope, so etisserant@0: * are no longer valid! etisserant@0: */ etisserant@0: variable_name_symtable.pop(); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* helper symbol for program_declaration */ etisserant@0: /* etisserant@0: * NOTE: we re-use the var_declarations_list_c etisserant@0: */ etisserant@0: program_var_declarations_list: etisserant@0: /* empty */ etisserant@0: {$$ = new var_declarations_list_c();} etisserant@0: | program_var_declarations_list io_var_declarations etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: | program_var_declarations_list other_var_declarations etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: | program_var_declarations_list located_var_declarations etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: /* etisserant@0: | program_var_declarations_list program_access_decls etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* TODO ... */ etisserant@0: /* etisserant@0: program_access_decls: etisserant@0: VAR_ACCESS program_access_decl_list END_VAR etisserant@0: ; etisserant@0: */ etisserant@0: etisserant@0: /* helper symbol for program_access_decls */ etisserant@0: /* etisserant@0: program_access_decl_list: etisserant@0: program_access_decl ';' etisserant@0: | program_access_decl_list program_access_decl ';' etisserant@0: ; etisserant@0: */ etisserant@0: etisserant@0: /* etisserant@0: program_access_decl: etisserant@0: access_name ':' symbolic_variable ':' non_generic_type_name etisserant@0: | access_name ':' symbolic_variable ':' non_generic_type_name direction etisserant@0: ; etisserant@0: */ etisserant@0: etisserant@0: etisserant@0: etisserant@0: /********************************************/ etisserant@1: /* B 1.6 Sequential Function Chart elements * lbessard@3: /********************************************/ etisserant@0: etisserant@0: sequential_function_chart: etisserant@0: sfc_network etisserant@1: {$$ = new sequential_function_chart_c(); $$->add_element($1);} etisserant@0: | sequential_function_chart sfc_network etisserant@1: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: sfc_network: etisserant@0: initial_step etisserant@1: {$$ = new sfc_network_c(); $$->add_element($1);} etisserant@0: | sfc_network step etisserant@1: {$$ = $1; $$->add_element($2);} etisserant@0: | sfc_network transition etisserant@1: {$$ = $1; $$->add_element($2);} etisserant@0: | sfc_network action etisserant@1: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: initial_step: etisserant@0: INITIAL_STEP step_name ':' action_association_list END_STEP etisserant@1: {$$ = new initial_step_c($2, $4);} etisserant@0: ; etisserant@0: etisserant@0: step: etisserant@0: STEP step_name ':' action_association_list END_STEP etisserant@1: {$$ = new step_c($2, $4);} etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for: etisserant@0: * - initial_step etisserant@0: * - step etisserant@1: */ etisserant@0: action_association_list: etisserant@1: /* empty */ etisserant@1: {$$ = new action_association_list_c();} etisserant@0: | action_association_list action_association ';' etisserant@1: {$$ = $1; $$->add_element($2);} etisserant@1: ; etisserant@1: etisserant@0: etisserant@0: step_name: identifier; etisserant@0: etisserant@0: action_association: etisserant@0: action_name '(' action_qualifier indicator_name_list ')' etisserant@1: {$$ = new action_association_c($1, $3, $4, NULL);} etisserant@1: ; etisserant@1: etisserant@1: /* helper symbol for action_association */ etisserant@0: indicator_name_list: etisserant@1: /* empty */ etisserant@1: {$$ = new indicator_name_list_c();} etisserant@0: | indicator_name_list ',' indicator_name etisserant@1: {$$ = $1; $$->add_element($3);} etisserant@0: ; etisserant@0: etisserant@0: action_name: identifier; etisserant@0: etisserant@0: action_qualifier: etisserant@1: /* empty */ etisserant@1: {$$ = NULL;} etisserant@1: | qualifier etisserant@1: {$$ = new action_qualifier_c($1, NULL);} etisserant@0: | timed_qualifier ',' action_time etisserant@1: {$$ = new action_qualifier_c($1, $3);} etisserant@1: ; etisserant@1: etisserant@1: qualifier: etisserant@1: N {$$ = new qualifier_c(strdup("N"));} etisserant@1: /* NOTE: the following two clash with the R and S IL operators. etisserant@1: * It will have to be handled when we include parsing of SFC... etisserant@1: */ etisserant@1: /* etisserant@1: | R {$$ = new identifier_c(strdup("R"));} etisserant@1: | S {$$ = new identifier_c(strdup("S"));} etisserant@1: */ etisserant@1: | P {$$ = new qualifier_c(strdup("P"));} etisserant@0: ; etisserant@0: etisserant@0: timed_qualifier: etisserant@1: L {$$ = new timed_qualifier_c(strdup("L"));} etisserant@1: | D {$$ = new timed_qualifier_c(strdup("D"));} etisserant@1: | SD {$$ = new timed_qualifier_c(strdup("SD"));} etisserant@1: | DS {$$ = new timed_qualifier_c(strdup("DS"));} etisserant@1: | SL {$$ = new timed_qualifier_c(strdup("SL"));} etisserant@0: ; etisserant@0: etisserant@0: action_time: etisserant@0: duration lbessard@10: | variable lbessard@10: ; lbessard@10: lbessard@10: indicator_name: variable; etisserant@0: etisserant@0: transition_name: identifier; etisserant@0: etisserant@0: steps: etisserant@0: step_name etisserant@1: {$$ = new steps_c($1, NULL);} etisserant@0: | '(' step_name_list ')' etisserant@1: {$$ = new steps_c(NULL, $2);} etisserant@1: ; etisserant@0: etisserant@0: step_name_list: etisserant@0: step_name ',' step_name etisserant@1: {$$ = new step_name_list_c(); $$->add_element($1); $$->add_element($3);} etisserant@0: | step_name_list ',' step_name etisserant@1: {$$ = $1; $$->add_element($3);} etisserant@1: ; etisserant@0: lbessard@3: transition_header: lbessard@3: TRANSITION FROM steps TO steps lbessard@3: {$$.first = NULL; $$.second = NULL; $$.third = $3; $$.fourth = $5; cmd_goto_body_state();} lbessard@3: | TRANSITION transition_name FROM steps TO steps lbessard@3: {$$.first = $2; $$.second = NULL; $$.third = $4; $$.fourth = $6; cmd_goto_body_state();} lbessard@3: | TRANSITION '(' PRIORITY ASSIGN integer ')' FROM steps TO steps lbessard@3: {$$.first = NULL; $$.second = $5; $$.third = $8; $$.fourth = $10; cmd_goto_body_state();} lbessard@3: | TRANSITION transition_name '(' PRIORITY ASSIGN integer ')' FROM steps TO steps lbessard@3: {$$.first = $2; $$.second = $6; $$.third = $9; $$.fourth = $11; cmd_goto_body_state();} lbessard@3: ; lbessard@3: lbessard@3: transition_condition_il: lbessard@10: ':' eol_list simple_instr_list lbessard@10: {$$ = new transition_condition_c($3, NULL);} lbessard@10: ; lbessard@3: lbessard@3: transition_condition_st: lbessard@3: ASSIGN expression ';' lbessard@10: {$$ = new transition_condition_c(NULL, $2);} lbessard@10: ; lbessard@3: lbessard@3: transition: lbessard@3: transition_header transition_condition_il END_TRANSITION mario@5: {$$ = new transition_c($1.first, $1.second, $1.third, $1.fourth, $2, NULL);} lbessard@3: | transition_header transition_condition_st END_TRANSITION mario@5: {$$ = new transition_c($1.first, $1.second, $1.third, $1.fourth, NULL, $2);} lbessard@3: ; lbessard@3: lbessard@3: action_header: lbessard@3: ACTION action_name ':' lbessard@3: {$$.first = $2; cmd_goto_body_state();} lbessard@3: ; lbessard@3: etisserant@0: etisserant@0: action: lbessard@3: action_header function_block_body END_ACTION lbessard@3: {$$ = new action_c($1.first, $2);} etisserant@1: ; etisserant@1: etisserant@0: etisserant@0: /********************************/ etisserant@0: /* B 1.7 Configuration elements */ etisserant@0: /********************************/ etisserant@0: /* NOTE: etisserant@0: * It is not clear from reading the specification to which namespace etisserant@0: * the names of resources, tasks and programs belong to. etisserant@0: * etisserant@0: * The following syntax assumes that resource and program names belong to the etisserant@0: * same namespace as the variables defined within etisserant@0: * the resource/configuration (i.e. VAR_GLOBAL). etisserant@0: * Task names belong to a namespace all of their own, since they don't etisserant@0: * produce conflicts in the syntax parser, so we might just as well etisserant@0: * leave them be! ;-) etisserant@0: * The above decision was made taking into etisserant@0: * account that inside a VAR_CONFIG declaration global variables etisserant@0: * may be referenced starting off from the resource name as: etisserant@0: * resource_name.program_name.variable_name etisserant@0: * Notice how resource names and program names are used in a very similar etisserant@0: * manner as are variable names. etisserant@0: * Using a single namespace for all the above mentioned names etisserant@0: * also makes it easier to write the syntax parser!! ;-) Using a private etisserant@0: * namespace for each of the name types (resource names, program names, etisserant@0: * global varaiable names), i.e. letting the names be re-used across etisserant@0: * each of the groups (resource, program, global variables), produces etisserant@0: * reduce/reduce conflicts in the syntax parser. Actually, it is only etisserant@0: * the resource names that need to be distinguished into a etisserant@0: * prev_delcared_resource_name so as not to conflict with [gloabl] variable etisserant@0: * names in the 'data' construct. etisserant@0: * The program names are only tracked to make sure that two programs do not etisserant@0: * get the same name. etisserant@0: * etisserant@0: * Using a single namespace does have the drawback that the user will etisserant@0: * not be able to re-use names for resources or programs if these etisserant@0: * have already been used to name a variable! etisserant@0: * etisserant@0: * If it ever becomes necessary to change this interpretation of etisserant@0: * the syntax, then this section of the syntax parser must be updated! etisserant@0: */ etisserant@0: prev_declared_global_var_name: prev_declared_global_var_name_token {$$ = new identifier_c($1);}; etisserant@0: prev_declared_resource_name: prev_declared_resource_name_token {$$ = new identifier_c($1);}; etisserant@0: prev_declared_program_name: prev_declared_program_name_token {$$ = new identifier_c($1);}; etisserant@0: // prev_declared_task_name: prev_declared_task_name_token {$$ = new identifier_c($1);}; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: configuration_name: identifier; etisserant@0: etisserant@0: /* NOTE: The specification states that valid resource type names etisserant@0: * are implementation defined, i.e. each implementaion will define etisserant@0: * what resource types it supports. etisserant@0: * We are implementing this syntax parser to be used by any etisserant@0: * implementation, so at the moment we accept any identifier etisserant@0: * as a resource type name. etisserant@0: * This implementation should probably be changed in the future. We etisserant@0: * should probably have a resource_type_name_token, and let the etisserant@0: * implementation load the global symbol library with the etisserant@0: * accepted resource type names before parsing the code. etisserant@0: * etisserant@0: */ etisserant@0: resource_type_name: any_identifier; etisserant@0: etisserant@0: configuration_declaration: etisserant@0: CONFIGURATION configuration_name etisserant@0: optional_global_var_declarations etisserant@0: single_resource_declaration etisserant@0: {variable_name_symtable.pop();} etisserant@0: optional_access_declarations etisserant@0: optional_instance_specific_initializations etisserant@0: END_CONFIGURATION etisserant@0: {$$ = new configuration_declaration_c($2, $3, $4, $6, $7); etisserant@0: library_element_symtable.insert($2, prev_declared_configuration_name_token); etisserant@0: variable_name_symtable.pop(); etisserant@0: } etisserant@0: | CONFIGURATION configuration_name etisserant@0: optional_global_var_declarations etisserant@0: resource_declaration_list etisserant@0: optional_access_declarations etisserant@0: optional_instance_specific_initializations etisserant@0: END_CONFIGURATION etisserant@0: {$$ = new configuration_declaration_c($2, $3, $4, $5, $6); etisserant@0: library_element_symtable.insert($2, prev_declared_configuration_name_token); etisserant@0: variable_name_symtable.pop(); etisserant@0: } etisserant@0: | CONFIGURATION error END_CONFIGURATION etisserant@0: {$$ = NULL; etisserant@0: print_err_msg(current_filename, @2.last_line, "error in configuration declaration."); etisserant@0: /* yychar */ etisserant@0: yyerrok; etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: // helper symbol for etisserant@0: // - configuration_declaration etisserant@0: // - resource_declaration etisserant@0: // etisserant@0: optional_global_var_declarations: etisserant@0: // empty etisserant@0: {$$ = NULL;} etisserant@0: | global_var_declarations etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: // helper symbol for configuration_declaration // etisserant@0: optional_access_declarations: etisserant@0: // empty etisserant@0: {$$ = NULL;} etisserant@0: //| access_declarations etisserant@0: ; etisserant@0: etisserant@0: // helper symbol for configuration_declaration // etisserant@0: optional_instance_specific_initializations: etisserant@0: // empty etisserant@0: {$$ = NULL;} etisserant@0: | instance_specific_initializations etisserant@0: ; etisserant@0: etisserant@0: // helper symbol for configuration_declaration // etisserant@0: resource_declaration_list: etisserant@0: resource_declaration etisserant@0: {$$ = new resource_declaration_list_c(); $$->add_element($1);} etisserant@0: | resource_declaration_list resource_declaration etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: resource_declaration: etisserant@0: RESOURCE {variable_name_symtable.push();} resource_name ON resource_type_name etisserant@0: optional_global_var_declarations etisserant@0: single_resource_declaration etisserant@0: END_RESOURCE etisserant@0: {$$ = new resource_declaration_c($3, $5, $6, $7); etisserant@0: variable_name_symtable.pop(); etisserant@0: variable_name_symtable.insert($3, prev_declared_resource_name_token); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: single_resource_declaration: etisserant@0: task_configuration_list program_configuration_list etisserant@0: {$$ = new single_resource_declaration_c($1, $2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: // helper symbol for single_resource_declaration // etisserant@0: task_configuration_list: etisserant@0: // empty etisserant@0: {$$ = new task_configuration_list_c();} etisserant@0: | task_configuration_list task_configuration ';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: // helper symbol for single_resource_declaration // etisserant@0: program_configuration_list: etisserant@0: program_configuration ';' etisserant@0: {$$ = new program_configuration_list_c(); $$->add_element($1);} etisserant@0: | program_configuration_list program_configuration ';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: resource_name: identifier; etisserant@0: etisserant@0: /* etisserant@0: access_declarations: etisserant@0: VAR_ACCESS access_declaration_list END_VAR etisserant@0: {$$ = NULL;} etisserant@0: ; etisserant@0: etisserant@0: // helper symbol for access_declarations // etisserant@0: access_declaration_list: etisserant@0: access_declaration ';' etisserant@0: | access_declaration_list access_declaration ';' etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: access_declaration: etisserant@0: access_name ':' access_path ':' non_generic_type_name etisserant@0: | access_name ':' access_path ':' non_generic_type_name direction etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: access_path: etisserant@0: direct_variable etisserant@0: | prev_delcared_resource_name '.' direct_variable etisserant@0: | any_fb_name_list symbolic_variable etisserant@0: | prev_delcared_resource_name '.' any_fb_name_list symbolic_variable etisserant@0: | prev_delcared_program_name '.' any_fb_name_list symbolic_variable etisserant@0: | prev_delcared_resource_name '.' prev_delcared_program_name '.' any_fb_name_list symbolic_variable etisserant@0: ; etisserant@0: */ etisserant@0: etisserant@0: // helper symbol for etisserant@0: // - access_path etisserant@0: // - instance_specific_init etisserant@0: // etisserant@0: /* NOTE: The fb_name_list refers to funtion block variables etisserant@0: * that have been declared in a scope outside the one we are etisserant@0: * currently parsing, so we must accept them to be any_identifier! etisserant@0: * etisserant@0: * Beware that other locations of this syntax parser also require etisserant@0: * a fb_name_list. In those locations the function blocks are being declared, etisserant@0: * so only currently un-used identifiers (i.e. identifier) may be accepted. etisserant@0: * etisserant@0: * In order to distinguish the two, here we use any_fb_name_list, while etisserant@0: * in the the locations we simply use fb_name_list! etisserant@0: */ etisserant@0: any_fb_name_list: etisserant@0: // empty etisserant@0: {$$ = new any_fb_name_list_c();} etisserant@0: //| fb_name_list fb_name '.' etisserant@0: | any_fb_name_list any_identifier '.' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: global_var_reference: etisserant@0: // [resource_name '.'] global_var_name ['.' structure_element_name] // etisserant@0: prev_declared_global_var_name etisserant@0: {$$ = new global_var_reference_c(NULL, $1, NULL);} etisserant@0: | prev_declared_global_var_name '.' structure_element_name etisserant@0: {$$ = new global_var_reference_c(NULL, $1, $3);} etisserant@0: | prev_declared_resource_name '.' prev_declared_global_var_name etisserant@0: {$$ = new global_var_reference_c($1, $3, NULL);} etisserant@0: | prev_declared_resource_name '.' prev_declared_global_var_name '.' structure_element_name etisserant@0: {$$ = new global_var_reference_c($1, $3, $5);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: //access_name: identifier; etisserant@0: etisserant@0: etisserant@0: program_output_reference: etisserant@0: /* NOTE: etisserant@0: * program_output_reference is merely used within data_source. etisserant@0: * data_source is merely used within task_initialization etisserant@0: * task_initialization appears in a configuration declaration etisserant@0: * _before_ the programs are declared, so we cannot use etisserant@0: * prev_declared_program_name, as what might seem correct at first. etisserant@0: * etisserant@0: * The semantic checker must later check whether the identifier etisserant@0: * used really refers to a program declared after the task etisserant@0: * initialization! etisserant@0: */ etisserant@0: // prev_declared_program_name '.' symbolic_variable etisserant@0: program_name '.' symbolic_variable etisserant@0: {$$ = new program_output_reference_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: program_name: identifier; etisserant@0: etisserant@0: /* etisserant@0: direction: etisserant@0: READ_WRITE etisserant@0: {$$ = NULL;} etisserant@0: | READ_ONLY etisserant@0: {$$ = NULL;} etisserant@0: ; etisserant@0: */ etisserant@0: etisserant@0: task_configuration: etisserant@0: TASK task_name task_initialization etisserant@0: {$$ = new task_configuration_c($2, $3);} etisserant@0: ; etisserant@0: etisserant@0: /* NOTE: The specification does nopt mention the namespace to which task names etisserant@0: * should belong to. Unlike resource and program names, for the moment we etisserant@0: * let the task names belong to their own private namespace, as they do not etisserant@0: * produce any conflicts in the syntax parser. etisserant@0: * If in the future our interpretation of the spec. turns out to be incorrect, etisserant@0: * the definition of task_name may have to be changed! etisserant@0: */ etisserant@0: task_name: any_identifier; etisserant@0: etisserant@0: task_initialization: etisserant@0: // '(' [SINGLE ASSIGN data_source ','] [INTERVAL ASSIGN data_source ','] PRIORITY ASSIGN integer ')' // etisserant@0: '(' PRIORITY ASSIGN integer ')' etisserant@0: {$$ = new task_initialization_c(NULL, NULL, $4);} etisserant@0: | '(' SINGLE ASSIGN data_source ',' PRIORITY ASSIGN integer ')' etisserant@0: {$$ = new task_initialization_c($4, NULL, $8);} etisserant@0: | '(' INTERVAL ASSIGN data_source ',' PRIORITY ASSIGN integer ')' etisserant@0: {$$ = new task_initialization_c(NULL, $4, $8);} etisserant@0: | '(' SINGLE ASSIGN data_source ',' INTERVAL ASSIGN data_source ',' PRIORITY ASSIGN integer ')' etisserant@0: {$$ = new task_initialization_c($4, $8, $12);} etisserant@0: ; etisserant@0: etisserant@0: data_source: etisserant@0: constant etisserant@0: | global_var_reference etisserant@0: | program_output_reference etisserant@0: | direct_variable etisserant@0: ; etisserant@0: etisserant@0: program_configuration: etisserant@0: // PROGRAM [RETAIN | NON_RETAIN] program_name [WITH task_name] ':' program_type_name ['(' prog_conf_elements ')'] // etisserant@0: PROGRAM program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements etisserant@0: {$$ = new program_configuration_c(NULL, $2, $3, $5, $6); etisserant@0: variable_name_symtable.insert($2, prev_declared_program_name_token); etisserant@0: } etisserant@0: | PROGRAM RETAIN program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements etisserant@0: {$$ = new program_configuration_c(new retain_option_c(), $3, $4, $6, $7); etisserant@0: variable_name_symtable.insert($3, prev_declared_program_name_token); etisserant@0: } etisserant@0: | PROGRAM NON_RETAIN program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements etisserant@0: {$$ = new program_configuration_c(new non_retain_option_c(), $3, $4, $6, $7); etisserant@0: variable_name_symtable.insert($3, prev_declared_program_name_token); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: // helper symbol for program_configuration // etisserant@0: optional_task_name: etisserant@0: // empty // etisserant@0: {$$ = NULL;} etisserant@0: | WITH task_name etisserant@0: {$$ = $2;} etisserant@0: ; etisserant@0: etisserant@0: // helper symbol for program_configuration // etisserant@0: optional_prog_conf_elements: etisserant@0: // empty // etisserant@0: {$$ = NULL;} etisserant@0: | '(' prog_conf_elements ')' etisserant@0: {$$ = $2;} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: prog_conf_elements: etisserant@0: prog_conf_element etisserant@0: {$$ = new prog_conf_elements_c(); $$->add_element($1);} etisserant@0: | prog_conf_elements ',' prog_conf_element etisserant@0: {$$ = $1; $$->add_element($3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: prog_conf_element: etisserant@0: fb_task etisserant@0: | prog_cnxn etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: fb_task: etisserant@0: // fb_name WITH task_name etisserant@0: /* NOTE: The fb_name refers to funtion block variables etisserant@0: * that have been declared in a scope outside the one we are etisserant@0: * currently parsing, so we must accept them to be any_identifier! etisserant@0: */ etisserant@0: any_identifier WITH task_name etisserant@0: {$$ = new fb_task_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* NOTE: etisserant@0: * The semantics of configuring a program are rather confusing, so here is etisserant@0: * my (Mario) understanding on the issue... etisserant@0: * etisserant@0: * A function/program may have as its input variables a simple variable etisserant@0: * (BYTE, WORD, etc...), an array (ARRAY [1 .. 3] OF BYTE, ...) , or a structure. etisserant@0: * Nevertheless, when calling this function from within a st or il language statement etisserant@0: * it is not possible to allocate a value to a single element of the array or structure etisserant@0: * typed input variable, as the accepted syntax is simply '(' variable_name ':=' variable ')' etisserant@0: * Notice how the variable_name does not include things such as 'a.elem1' or 'a[1]'! etisserant@0: * etisserant@0: * Nevertheless, when configuring a program from within a configuration, etisserant@0: * it becomes possible to allocate values to individual elements of the etisserant@0: * array or structured type input variable, as the syntax is now etisserant@0: * '(' symbolic_variable ':=' data_sink|prog_data_source ')' etisserant@0: * Notice how the symbolic_variable _does_ include things such as 'a.elem1' or 'a[1]'! etisserant@0: * etisserant@0: * Conclusion: Unlike other locations in the syntax where SENDTO appears, etisserant@0: * here it is not valid to replace symbolic_variable with any_identifier! etisserant@0: * Nevertheless, it is also not correct to leave symbolic_variable as it is, etisserant@0: * as we have defined it to only include previously declared variables, etisserant@0: * which is not the case in this situation. Here symbolic_variable is refering etisserant@0: * to variables that were defined within the scope of the program that is being etisserant@0: * called, and _not_ within the scope of the configuration that is calling the etisserant@0: * program, so the variables in question are not declared in the current scope! etisserant@0: * etisserant@0: * We therefore need to define a new symbolic_variable, that accepts any_identifier etisserant@0: * instead of previosuly declared variable names, to be used in the definition of etisserant@0: * prog_cnxn! etisserant@0: */ etisserant@0: prog_cnxn: etisserant@0: any_symbolic_variable ASSIGN prog_data_source etisserant@0: {$$ = new prog_cnxn_assign_c($1, $3);} etisserant@0: | any_symbolic_variable SENDTO data_sink etisserant@0: {$$ = new prog_cnxn_sendto_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: prog_data_source: etisserant@0: constant etisserant@0: | enumerated_value etisserant@0: | global_var_reference etisserant@0: | direct_variable etisserant@0: ; etisserant@0: etisserant@0: data_sink: etisserant@0: global_var_reference etisserant@0: | direct_variable etisserant@0: ; etisserant@0: etisserant@0: instance_specific_initializations: etisserant@0: VAR_CONFIG instance_specific_init_list END_VAR etisserant@0: {$$ = new instance_specific_initializations_c($2);} etisserant@0: ; etisserant@0: etisserant@0: // helper symbol for instance_specific_initializations // etisserant@0: instance_specific_init_list: etisserant@0: instance_specific_init ';' etisserant@0: {$$ = new instance_specific_init_list_c(); $$->add_element($1);} etisserant@0: | instance_specific_init_list instance_specific_init ';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: instance_specific_init: etisserant@0: // etisserant@0: // resource_name '.' program_name '.' {fb_name '.'} etisserant@0: // ((variable_name [location] ':' located_var_spec_init) | (fb_name ':' function_block_type_name ':=' structure_initialization)) etisserant@0: // etisserant@0: // prev_declared_resource_name '.' prev_declared_program_name '.' any_fb_name_list variable_name ':' located_var_spec_init etisserant@0: /* NOTE: variable_name has been changed to any_identifier (and not simply identifier) because the etisserant@0: * variables being referenced have been declared outside the scope currently being parsed! etisserant@0: */ etisserant@0: /* NOTE: program_name has not been changed to prev_declared_program_name because the etisserant@0: * programs being referenced have been declared outside the scope currently being parsed! etisserant@0: * The programs are only kept inside the scope of the resource in which they are defined. etisserant@0: */ etisserant@0: prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier ':' located_var_spec_init etisserant@0: {$$ = new instance_specific_init_c($1, $3, $5, $6, NULL, $8);} etisserant@0: | prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier location ':' located_var_spec_init etisserant@0: {$$ = new instance_specific_init_c($1, $3, $5, $6, $7, $9);} etisserant@0: | prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier ':' fb_initialization etisserant@0: {$5->add_element($6); $$ = new instance_specific_init_c($1, $3, $5, NULL, NULL, $8);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* helper symbol for instance_specific_init */ etisserant@0: fb_initialization: etisserant@0: function_block_type_name ASSIGN structure_initialization etisserant@0: {$$ = new fb_initialization_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: /***********************************/ etisserant@0: /* B 2.1 Instructions and Operands */ etisserant@0: /***********************************/ etisserant@0: /* helper symbol for many IL instructions, etc... */ etisserant@0: /* eat up any extra EOL tokens... */ etisserant@0: etisserant@0: eol_list: etisserant@0: EOL etisserant@0: | eol_list EOL etisserant@0: ; etisserant@0: etisserant@0: /* etisserant@0: eol_list: etisserant@0: '\n' etisserant@0: | eol_list '\n' etisserant@0: ; etisserant@0: */ etisserant@0: etisserant@0: instruction_list: etisserant@0: il_instruction etisserant@0: {$$ = new instruction_list_c(); $$->add_element($1);} etisserant@0: | instruction_list il_instruction etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: | instruction_list pragma etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: | instruction_list error etisserant@0: {$$ = $1; etisserant@0: print_err_msg(current_filename, @2.last_line, "error in IL instruction."); etisserant@0: /* yychar */ etisserant@0: yyerrok; etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: il_instruction: etisserant@0: il_incomplete_instruction eol_list etisserant@0: {$$ = new il_instruction_c(NULL, $1);} etisserant@0: | label ':' il_incomplete_instruction eol_list etisserant@0: {$$ = new il_instruction_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* helper symbol for il_instruction */ etisserant@0: il_incomplete_instruction: etisserant@0: il_simple_operation etisserant@0: | il_expression etisserant@0: | il_jump_operation etisserant@0: | il_fb_call etisserant@0: | il_formal_funct_call etisserant@0: | il_return_operator etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: label: identifier; etisserant@0: etisserant@0: etisserant@0: etisserant@0: il_simple_operation: etisserant@0: il_simple_operator etisserant@0: {$$ = new il_simple_operation_c($1, NULL);} etisserant@0: | il_simple_operator_noclash il_operand etisserant@0: {$$ = new il_simple_operation_c($1, $2);} etisserant@0: | il_simple_operator_clash_il_operand etisserant@0: {$$ = new il_simple_operation_c($1.first, $1.second);} etisserant@0: /* NOTE: the line etisserant@0: * | il_simple_operator etisserant@0: * already contains the 'NOT' operator, as well as all the etisserant@0: * expression operators ('MOD', 'AND', etc...), all of which etisserant@0: * may also be a function name! This means that these operators/functions, etisserant@0: * without any operands, could be reduced to either an operator or a etisserant@0: * function call. I (Mario) have chosen to reduce it to an operator. etisserant@0: * etisserant@0: * The line etisserant@0: * | function_name etisserant@0: * has been replaced with the lines etisserant@0: * | function_name_no_clashes etisserant@0: * in order to include all possible function names except etisserant@0: * those whose names coincide with operators !! etisserant@0: */ etisserant@0: | function_name_no_clashes etisserant@0: {$$ = new il_function_call_c($1, NULL);} etisserant@0: /* NOTE: the line etisserant@0: * | il_simple_operator il_operand etisserant@0: * already contains the 'NOT', 'MOD', etc. operators, followed by a single il_operand, etisserant@0: * which may also be reduced to a function name with an operand_list of a single etisserant@0: * il_operand! This would lead us to a reduce/reduce conflict! etisserant@0: * etisserant@0: * I (Mario) have chosen to reduce it to an operand, rather than a function call. etisserant@0: * etisserant@0: * The line etisserant@0: * | function_name il_operand_list etisserant@0: * has been replaced with the line etisserant@0: * | function_name_no_clashes il_operand_list etisserant@0: * in order to include all possible function names except etisserant@0: * for the function names which clash with expression and simple operators. etisserant@0: * etisserant@0: * Note that: etisserant@0: * this alternative syntax does not cover the possibility of etisserant@0: * the function 'NOT', 'MOD', etc... being called with more than one il_operand! etisserant@0: * We therefore need to include an extra rule where the etisserant@0: * function_name_expression_clashes and function_name_simpleop_clashes etisserant@0: * are followed by a il_operand_list with __two__ or more il_operands!! etisserant@0: */ etisserant@0: | function_name_no_clashes il_operand_list etisserant@0: {$$ = new il_function_call_c($1, $2);} etisserant@0: | il_simple_operator_clash_il_operand ',' il_operand_list etisserant@0: {list_c *list = new il_operand_list_c(); etisserant@0: list->add_element($1.second); etisserant@0: FOR_EACH_ELEMENT(elem, $3, {list->add_element(elem);}) etisserant@0: $$ = new il_function_call_c(il_operator_c_2_identifier_c($1.first), list); etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: il_simple_operator_clash_il_operand: etisserant@0: il_simple_operator_clash il_operand etisserant@0: {$$.first = $1; $$.second = $2;} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: il_expression: etisserant@0: il_expr_operator_noclash '(' eol_list ')' etisserant@0: {$$ = new il_expression_c($1, NULL, NULL);} etisserant@0: | il_expr_operator_noclash '(' il_operand eol_list ')' etisserant@0: {$$ = new il_expression_c($1, $3, NULL);} etisserant@0: | il_expr_operator_noclash '(' eol_list simple_instr_list ')' etisserant@0: {$$ = new il_expression_c($1, NULL, $4);} etisserant@0: | il_expr_operator_noclash '(' il_operand eol_list simple_instr_list ')' etisserant@0: {$$ = new il_expression_c($1, $3, $5);} etisserant@0: /* etisserant@0: */ etisserant@0: | il_expr_operator_clash '(' eol_list ')' etisserant@0: {$$ = new il_expression_c($1, NULL, NULL);} etisserant@0: | il_expr_operator_clash '(' il_operand eol_list ')' etisserant@0: {$$ = new il_expression_c($1, $3, NULL);} etisserant@0: | il_expr_operator_clash '(' il_operand eol_list simple_instr_list ')' etisserant@0: {$$ = new il_expression_c($1, $3, $5);} etisserant@0: /* etisserant@0: */ etisserant@0: | il_expr_operator_clash_eol_list simple_instr_list ')' etisserant@0: {$$ = new il_expression_c($1, NULL, $2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_jump_operation: etisserant@0: il_jump_operator label etisserant@0: {$$ = new il_jump_operation_c($1, $2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_fb_call: etisserant@0: il_call_operator prev_declared_fb_name etisserant@0: {$$ = new il_fb_call_c($1, $2, NULL, NULL);} etisserant@0: | il_call_operator prev_declared_fb_name '(' ')' etisserant@0: {$$ = new il_fb_call_c($1, $2, NULL, NULL);} etisserant@0: | il_call_operator prev_declared_fb_name '(' eol_list ')' etisserant@0: {$$ = new il_fb_call_c($1, $2, NULL, NULL);} etisserant@0: | il_call_operator prev_declared_fb_name '(' il_operand_list ')' etisserant@0: {$$ = new il_fb_call_c($1, $2, $4, NULL);} etisserant@0: | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')' etisserant@0: {$$ = new il_fb_call_c($1, $2, NULL, $5);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* NOTE: Please read note above the definition of function_name_without_clashes */ etisserant@0: il_formal_funct_call: etisserant@0: /* function_name '(' eol_list ')' */ etisserant@0: /* NOTE: il_formal_funct_call is only used in the definition of etisserant@0: * - il_incomplete_instruction etisserant@0: * - il_simple_instruction etisserant@0: * In both of the above, il_expression also etisserant@0: * shows up as another option. This means that the functions whose etisserant@0: * names clash with expressions, followed by '(' eol_list ')', are etisserant@0: * already included. We must therefore leave them out in this etisserant@0: * definition in order to remove reduce/reduce conflicts. etisserant@0: * etisserant@0: * In summary: 'MOD' '(' eol_list ')', and all other functions whose etisserant@0: * names clash with expressions may be interpreted by the syntax by etisserant@0: * two different routes. I (Mario) chose to interpret them etisserant@0: * as operators, rather than as function calls! etisserant@0: */ etisserant@0: function_name_no_clashes '(' eol_list ')' etisserant@0: {$$ = new il_formal_funct_call_c($1, NULL);} etisserant@0: | function_name_simpleop_clashes '(' eol_list ')' etisserant@0: {$$ = new il_formal_funct_call_c($1, NULL);} etisserant@0: /* | function_name '(' eol_list il_param_list ')' */ etisserant@0: | function_name_no_clashes '(' eol_list il_param_list ')' etisserant@0: {$$ = new il_formal_funct_call_c($1, $4);} etisserant@0: | function_name_simpleop_clashes '(' eol_list il_param_list ')' etisserant@0: {$$ = new il_formal_funct_call_c($1, $4);} etisserant@0: /* the function_name_expression_clashes had to be first reduced to etisserant@0: * an intermediary symbol in order to remove a reduce/reduce conflict. etisserant@0: * In essence, the syntax requires more than one look ahead token etisserant@0: * in order to be parsed. We resolve this by reducing a collection of etisserant@0: * symbols into a temporary symbol (il_expr_operator_clash_eol_list), that etisserant@0: * will later be replaced by the correct symbol. The correct symbol will etisserant@0: * now be determined by a single look ahead token, as all the common etisserant@0: * symbols have been reduced to the temporary symbol etisserant@0: * il_expr_operator_clash_eol_list ! etisserant@0: * etisserant@0: * Unfortunately, this work around results in the wrong symbol etisserant@0: * being created for the abstract syntax tree. etisserant@0: * We need to figure out which symbol was created, destroy it, etisserant@0: * and create the correct symbol for our case. etisserant@0: * This is a lot of work, so I put it in a function etisserant@0: * at the end of this file... il_operator_c_2_identifier_c() etisserant@0: */ etisserant@0: | il_expr_operator_clash_eol_list il_param_list ')' etisserant@0: {$$ = new il_formal_funct_call_c(il_operator_c_2_identifier_c($1), $2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_expr_operator_clash_eol_list: etisserant@0: il_expr_operator_clash '(' eol_list etisserant@0: {$$ = $1;} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_operand: etisserant@0: variable etisserant@0: | enumerated_value etisserant@0: | constant etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_operand_list: etisserant@0: il_operand etisserant@0: {$$ = new il_operand_list_c(); $$->add_element($1);} etisserant@0: | il_operand_list ',' il_operand etisserant@0: {$$ = $1; $$->add_element($3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: simple_instr_list: etisserant@0: il_simple_instruction etisserant@0: {$$ = new simple_instr_list_c(); $$->add_element($1);} etisserant@0: | simple_instr_list il_simple_instruction etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_simple_instruction: etisserant@0: il_simple_operation eol_list etisserant@0: | il_expression eol_list etisserant@0: | il_formal_funct_call eol_list etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* NOTE: the correct definition of il_param_list is etisserant@0: * il_param_list ::= {il_param_instruction} il_param_last_instruction etisserant@0: * etisserant@0: * where {...} denotes zero or many il_param_instruction's. etisserant@0: * etisserant@0: * We could do this by defining the following: etisserant@0: * il_param_list: il_param_instruction_list il_param_last_instruction; etisserant@0: * il_param_instruction_list : ** empty ** | il_param_instruction_list il_param_instruction; etisserant@0: * etisserant@0: * Unfortunately, the above leads to reduce/reduce conflicts. etisserant@0: * The chosen alternative (as follows) does not have any conflicts! etisserant@0: * il_param_list: il_param_last_instruction | il_param_instruction_list il_param_last_instruction; etisserant@0: * il_param_instruction_list : il_param_instruction_list | il_param_instruction_list il_param_instruction; etisserant@0: */ etisserant@0: il_param_list: etisserant@0: il_param_instruction_list il_param_last_instruction etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: | il_param_last_instruction etisserant@0: {$$ = new il_param_list_c(); $$->add_element($1);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* Helper symbol for il_param_list */ etisserant@0: il_param_instruction_list: etisserant@0: il_param_instruction etisserant@0: {$$ = new il_param_list_c(); $$->add_element($1);} etisserant@0: | il_param_instruction_list il_param_instruction etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_param_instruction: etisserant@0: il_param_assignment ',' eol_list etisserant@0: | il_param_out_assignment ',' eol_list etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_param_last_instruction: etisserant@0: il_param_assignment eol_list etisserant@0: | il_param_out_assignment eol_list etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_param_assignment: etisserant@0: il_assign_operator il_operand etisserant@0: {$$ = new il_param_assignment_c($1, $2, NULL);} etisserant@0: | il_assign_operator '(' eol_list simple_instr_list ')' etisserant@0: {$$ = new il_param_assignment_c($1, NULL, $4);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_param_out_assignment: etisserant@0: il_assign_out_operator variable etisserant@0: {$$ = new il_param_out_assignment_c($1, $2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /*******************/ etisserant@0: /* B 2.2 Operators */ etisserant@0: /*******************/ etisserant@0: sendto_identifier: sendto_identifier_token {$$ = new identifier_c($1);}; etisserant@0: etisserant@0: etisserant@0: /* NOTE: etisserant@0: * The spec includes the operator 'EQ ' etisserant@0: * Note that EQ is followed by a space. etisserant@0: * I am considering this a typo, and defining the operator etisserant@0: * as 'EQ' etisserant@0: * (Mario) etisserant@0: */ etisserant@0: LD_operator: LD {$$ = new LD_operator_c();}; etisserant@0: LDN_operator: LDN {$$ = new LDN_operator_c();}; etisserant@0: ST_operator: ST {$$ = new ST_operator_c();}; etisserant@0: STN_operator: STN {$$ = new STN_operator_c();}; etisserant@0: NOT_operator: NOT {$$ = new NOT_operator_c();}; etisserant@0: S_operator: S {$$ = new S_operator_c();}; etisserant@0: R_operator: R {$$ = new R_operator_c();}; etisserant@0: S1_operator: S1 {$$ = new S1_operator_c();}; etisserant@0: R1_operator: R1 {$$ = new R1_operator_c();}; etisserant@0: CLK_operator: CLK {$$ = new CLK_operator_c();}; etisserant@0: CU_operator: CU {$$ = new CU_operator_c();}; etisserant@0: CD_operator: CD {$$ = new CD_operator_c();}; etisserant@0: PV_operator: PV {$$ = new PV_operator_c();}; etisserant@0: IN_operator: IN {$$ = new IN_operator_c();}; etisserant@0: PT_operator: PT {$$ = new PT_operator_c();}; etisserant@0: AND_operator: AND {$$ = new AND_operator_c();}; etisserant@0: AND2_operator: AND2 {$$ = new AND_operator_c();}; /* '&' in the source code! */ etisserant@0: OR_operator: OR {$$ = new OR_operator_c();}; etisserant@0: XOR_operator: XOR {$$ = new XOR_operator_c();}; etisserant@0: ANDN_operator: ANDN {$$ = new ANDN_operator_c();}; etisserant@0: ANDN2_operator: ANDN2 {$$ = new ANDN_operator_c();}; /* '&N' in the source code! */ etisserant@0: ORN_operator: ORN {$$ = new ORN_operator_c();}; etisserant@0: XORN_operator: XORN {$$ = new XORN_operator_c();}; etisserant@0: ADD_operator: ADD {$$ = new ADD_operator_c();}; etisserant@0: SUB_operator: SUB {$$ = new SUB_operator_c();}; etisserant@0: MUL_operator: MUL {$$ = new MUL_operator_c();}; etisserant@0: DIV_operator: DIV {$$ = new DIV_operator_c();}; etisserant@0: MOD_operator: MOD {$$ = new MOD_operator_c();}; etisserant@0: GT_operator: GT {$$ = new GT_operator_c();}; etisserant@0: GE_operator: GE {$$ = new GE_operator_c();}; etisserant@0: EQ_operator: EQ {$$ = new EQ_operator_c();}; etisserant@0: LT_operator: LT {$$ = new LT_operator_c();}; etisserant@0: LE_operator: LE {$$ = new LE_operator_c();}; etisserant@0: NE_operator: NE {$$ = new NE_operator_c();}; etisserant@0: CAL_operator: CAL {$$ = new CAL_operator_c();}; etisserant@0: CALC_operator: CALC {$$ = new CALC_operator_c();}; etisserant@0: CALCN_operator: CALCN {$$ = new CALCN_operator_c();}; etisserant@0: RET_operator: RET {$$ = new RET_operator_c();}; etisserant@0: RETC_operator: RETC {$$ = new RETC_operator_c();}; etisserant@0: RETCN_operator: RETCN {$$ = new RETCN_operator_c();}; etisserant@0: JMP_operator: JMP {$$ = new JMP_operator_c();}; etisserant@0: JMPC_operator: JMPC {$$ = new JMPC_operator_c();}; etisserant@0: JMPCN_operator: JMPCN {$$ = new JMPCN_operator_c();}; etisserant@0: etisserant@0: /* etisserant@0: MAY CONFLICT WITH STANDARD FUNCTION NAMES!!! etisserant@0: etisserant@0: NOT_operator: NOT {new NOT_operator_c();}; etisserant@0: etisserant@0: AND_operator: AND {new AND_operator_c();}; etisserant@0: OR_operator: OR {new OR_operator_c();}; etisserant@0: XOR_operator: XOR {new XOR_operator_c();}; etisserant@0: etisserant@0: ADD_operator: ADD {new ADD_operator_c();}; etisserant@0: SUB_operator: SUB {new SUB_operator_c();}; etisserant@0: MUL_operator: MUL {new MUL_operator_c();}; etisserant@0: DIV_operator: DIV {new DIV_operator_c();}; etisserant@0: MOD_operator: MOD {new MOD_operator_c();}; etisserant@0: etisserant@0: GT_operator: GT {new GT_operator_c();}; etisserant@0: GE_operator: GE {new GE_operator_c();}; etisserant@0: EQ_operator: EQ {new EQ_operator_c();}; etisserant@0: LT_operator: LT {new LT_operator_c();}; etisserant@0: LE_operator: LE {new LE_operator_c();}; etisserant@0: NE_operator: NE {new NE_operator_c();}; etisserant@0: */ etisserant@0: etisserant@0: etisserant@0: il_simple_operator: etisserant@0: il_simple_operator_clash etisserant@0: | il_simple_operator_noclash etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_simple_operator_noclash: etisserant@0: LD_operator etisserant@0: | LDN_operator etisserant@0: | ST_operator etisserant@0: | STN_operator etisserant@0: | S_operator etisserant@0: | R_operator etisserant@0: | S1_operator etisserant@0: | R1_operator etisserant@0: | CLK_operator etisserant@0: | CU_operator etisserant@0: | CD_operator etisserant@0: | PV_operator etisserant@0: | IN_operator etisserant@0: | PT_operator etisserant@0: | il_expr_operator_noclash etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_simple_operator_clash: etisserant@0: il_simple_operator_clash1 etisserant@0: | il_simple_operator_clash2 etisserant@0: ; etisserant@0: etisserant@0: il_simple_operator_clash1: etisserant@0: NOT_operator etisserant@0: ; etisserant@0: etisserant@0: il_simple_operator_clash2: etisserant@0: il_expr_operator_clash etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* etisserant@0: il_expr_operator: etisserant@0: il_expr_operator_noclash etisserant@0: | il_expr_operator_clash etisserant@0: ; etisserant@0: */ etisserant@0: etisserant@0: il_expr_operator_clash: etisserant@0: AND_operator etisserant@0: | OR_operator etisserant@0: | XOR_operator etisserant@0: | ADD_operator etisserant@0: | SUB_operator etisserant@0: | MUL_operator etisserant@0: | DIV_operator etisserant@0: | MOD_operator etisserant@0: | GT_operator etisserant@0: | GE_operator etisserant@0: | EQ_operator etisserant@0: | LT_operator etisserant@0: | LE_operator etisserant@0: | NE_operator etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_expr_operator_noclash: etisserant@0: ANDN_operator etisserant@0: | ANDN2_operator /* string '&N' in source code! */ etisserant@0: | AND2_operator /* string '&' in source code! */ etisserant@0: | ORN_operator etisserant@0: | XORN_operator etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: il_assign_operator: etisserant@0: /* variable_name ASSIGN */ etisserant@0: any_identifier ASSIGN etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_assign_out_operator: etisserant@0: /* variable_name SENDTO */ etisserant@0: /* any_identifier SENDTO */ etisserant@0: sendto_identifier SENDTO etisserant@0: {$$ = new il_assign_out_operator_c(NULL, $1);} etisserant@0: /*| NOT variable_name SENDTO */ etisserant@0: | NOT sendto_identifier SENDTO etisserant@0: {$$ = new il_assign_out_operator_c(new not_paramassign_c(), $2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_call_operator: etisserant@0: CAL_operator etisserant@0: | CALC_operator etisserant@0: | CALCN_operator etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_return_operator: etisserant@0: RET_operator etisserant@0: | RETC_operator etisserant@0: | RETCN_operator etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_jump_operator: etisserant@0: JMP_operator etisserant@0: | JMPC_operator etisserant@0: | JMPCN_operator etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /***********************/ etisserant@0: /* B 3.1 - Expressions */ etisserant@0: /***********************/ etisserant@0: expression: etisserant@0: xor_expression etisserant@0: | expression OR xor_expression etisserant@0: {$$ = new or_expression_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: xor_expression: etisserant@0: and_expression etisserant@0: | xor_expression XOR and_expression etisserant@0: {$$ = new xor_expression_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: and_expression: etisserant@0: comparison etisserant@0: | and_expression '&' comparison etisserant@0: {$$ = new and_expression_c($1, $3);} etisserant@0: | and_expression AND comparison etisserant@0: {$$ = new and_expression_c($1, $3);} etisserant@0: /* NOTE: The lexical parser never returns the token '&'. etisserant@0: * The '&' string is interpreted by the lexcial parser as the token etisserant@0: * AND2! etisserant@0: * This means that the first rule with '&' is actually not required, etisserant@0: * but we leave it in nevertheless just in case we later decide etisserant@0: * to remove theh AND2 token... etisserant@0: */ etisserant@0: | and_expression AND2 comparison etisserant@0: {$$ = new and_expression_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: comparison: etisserant@0: equ_expression etisserant@0: | comparison '=' equ_expression etisserant@0: {$$ = new equ_expression_c($1, $3);} etisserant@0: | comparison OPER_NE equ_expression etisserant@0: {$$ = new notequ_expression_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: equ_expression: etisserant@0: add_expression etisserant@0: | equ_expression '<' add_expression etisserant@0: {$$ = new lt_expression_c($1, $3);} etisserant@0: | equ_expression '>' add_expression etisserant@0: {$$ = new gt_expression_c($1, $3);} etisserant@0: | equ_expression OPER_LE add_expression etisserant@0: {$$ = new le_expression_c($1, $3);} etisserant@0: | equ_expression OPER_GE add_expression etisserant@0: {$$ = new ge_expression_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: /* Not required... etisserant@0: comparison_operator: '<' | '>' | '>=' '<=' etisserant@0: */ etisserant@0: etisserant@0: add_expression: etisserant@0: term etisserant@0: | add_expression '+' term etisserant@0: {$$ = new add_expression_c($1, $3);} etisserant@0: | add_expression '-' term etisserant@0: {$$ = new sub_expression_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: /* Not required... etisserant@0: add_operator: '+' | '-' etisserant@0: */ etisserant@0: etisserant@0: term: etisserant@0: power_expression etisserant@0: | term '*' power_expression etisserant@0: {$$ = new mul_expression_c($1, $3);} etisserant@0: | term '/' power_expression etisserant@0: {$$ = new div_expression_c($1, $3);} etisserant@0: | term MOD power_expression etisserant@0: {$$ = new mod_expression_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: /* Not required... etisserant@0: multiply_operator: '*' | '/' | 'MOD' etisserant@0: */ etisserant@0: etisserant@0: power_expression: etisserant@0: unary_expression etisserant@0: | power_expression OPER_EXP unary_expression etisserant@0: {$$ = new power_expression_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: unary_expression: etisserant@0: primary_expression etisserant@0: | '-' primary_expression etisserant@0: {$$ = new neg_expression_c($2);} etisserant@0: | NOT primary_expression etisserant@0: {$$ = new not_expression_c($2);} etisserant@0: ; etisserant@0: etisserant@0: /* Not required... etisserant@0: unary_operator: '-' | 'NOT' etisserant@0: */ etisserant@0: etisserant@0: etisserant@0: /* NOTE: using constant as a possible symbol for primary_expression etisserant@0: * leads to a reduce/reduce conflict. etisserant@0: * etisserant@0: * The text '-9' may be parsed as either a etisserant@0: * expression<-primary_expression<-constant<-signed_integer etisserant@0: * (i.e. the constant 9 negative) etisserant@0: * OR etisserant@0: * expression<-unary_expression<-constant<-integer etisserant@0: * (i.e. the constant 9, preceded by a unary negation) etisserant@0: * etisserant@0: * To remove the conlfict, we only allow constants without etisserant@0: * a preceding '-' to be used in primary_expression etisserant@0: */ etisserant@0: primary_expression: etisserant@0: /* constant */ etisserant@0: non_negative_constant etisserant@0: | enumerated_value etisserant@0: | variable etisserant@0: | '(' expression ')' etisserant@0: {$$ = $2;} etisserant@0: | function_invocation etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* intermediate helper symbol for primary_expression */ etisserant@0: /* NOTE: function_name includes the standard function name 'NOT' ! etisserant@0: * This introduces a reduce/reduce conflict, as NOT(var) etisserant@0: * may be parsed as either a function_invocation, or a etisserant@0: * unary_expression. etisserant@0: * etisserant@0: * I (Mario) have opted to remove the possible reduction etisserant@0: * to function invocation, which means replacing the rule etisserant@0: * function_name '(' param_assignment_list ')' etisserant@0: * with etisserant@0: * function_name_no_NOT_clashes '(' param_assignment_list ')' etisserant@0: * etisserant@0: * Notice how the new rule does not include the situation where etisserant@0: * the function NOT is called with more than one parameter, which etisserant@0: * the original rule does include! Callinf the NOT function with more etisserant@0: * than one argument is probably a semantic error anyway, so it etisserant@0: * doesn't make much sense to take it into account. etisserant@0: * etisserant@0: * Nevertheless, if we were to to it entirely correctly, etisserant@0: * leaving the semantic checks for the next compiler stage, etisserant@0: * this syntax parser would need to include such a possibility. etisserant@0: * etisserant@0: * We will leave this out for now. No need to complicate the syntax etisserant@0: * more than the specification does by contradicting itself, and etisserant@0: * letting names clash! etisserant@0: */ etisserant@0: function_invocation: etisserant@0: /* function_name '(' param_assignment_list ')' */ etisserant@0: function_name_no_NOT_clashes '(' param_assignment_list ')' etisserant@0: {$$ = new function_invocation_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /********************/ etisserant@0: /* B 3.2 Statements */ etisserant@0: /********************/ etisserant@0: statement_list: etisserant@0: /* empty */ etisserant@0: {$$ = new statement_list_c();} etisserant@0: | statement_list statement ';' etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: | statement_list pragma etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: | statement_list error ';' etisserant@0: {$$ = $1; etisserant@0: print_err_msg(current_filename, @2.last_line, "error in statement."); etisserant@0: /* yychar */ etisserant@0: yyerrok; etisserant@0: } etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: statement: etisserant@0: assignment_statement etisserant@0: | subprogram_control_statement etisserant@0: | selection_statement etisserant@0: | iteration_statement etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /*********************************/ etisserant@0: /* B 3.2.1 Assignment Statements */ etisserant@0: /*********************************/ etisserant@0: assignment_statement: etisserant@0: variable ASSIGN expression etisserant@0: {$$ = new assignment_statement_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /*****************************************/ etisserant@0: /* B 3.2.2 Subprogram Control Statements */ etisserant@0: /*****************************************/ etisserant@0: subprogram_control_statement: etisserant@0: fb_invocation etisserant@0: | return_statement etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: return_statement: etisserant@0: RETURN {$$ = new return_statement_c();} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: fb_invocation: etisserant@0: prev_declared_fb_name '(' ')' etisserant@0: {$$ = new fb_invocation_c($1, NULL); } etisserant@0: | prev_declared_fb_name '(' param_assignment_list ')' etisserant@0: {$$ = new fb_invocation_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* helper symbol for etisserant@0: * - fb_invocation etisserant@0: * - function_invocation etisserant@0: */ etisserant@0: param_assignment_list: etisserant@0: param_assignment etisserant@0: {$$ = new param_assignment_list_c(); $$->add_element($1);} etisserant@0: | param_assignment_list ',' param_assignment etisserant@0: {$$ = $1; $$->add_element($3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: param_assignment: etisserant@0: /* variable_name ASSIGN expression */ etisserant@0: any_identifier ASSIGN expression etisserant@0: {$$ = new input_variable_param_assignment_c($1, $3);} etisserant@0: | expression etisserant@0: /*| variable_name SENDTO variable */ etisserant@0: /*| any_identifier SENDTO variable */ etisserant@0: | sendto_identifier SENDTO variable etisserant@0: {$$ = new output_variable_param_assignment_c(NULL,$1, $3);} etisserant@0: /*| variable_name SENDTO variable */ etisserant@0: /*| NOT any_identifier SENDTO variable*/ etisserant@0: | NOT sendto_identifier SENDTO variable etisserant@0: {$$ = new output_variable_param_assignment_c(new not_paramassign_c(),$2, $4);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /********************************/ etisserant@0: /* B 3.2.3 Selection Statements */ etisserant@0: /********************************/ etisserant@0: selection_statement: etisserant@0: if_statement etisserant@0: | case_statement etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: if_statement: etisserant@0: IF expression THEN statement_list elseif_statement_list END_IF etisserant@0: {$$ = new if_statement_c($2, $4, $5, NULL);} etisserant@0: | IF expression THEN statement_list elseif_statement_list ELSE statement_list END_IF etisserant@0: {$$ = new if_statement_c($2, $4, $5, $7);} etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for if_statement */ etisserant@0: elseif_statement_list: etisserant@0: /* empty */ etisserant@0: {$$ = new elseif_statement_list_c();} etisserant@0: | elseif_statement_list elseif_statement etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for elseif_statement_list */ etisserant@0: elseif_statement: etisserant@0: ELSIF expression THEN statement_list etisserant@0: {$$ = new elseif_statement_c($2, $4);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: case_statement: etisserant@0: CASE expression OF case_element_list END_CASE etisserant@0: {$$ = new case_statement_c($2, $4, NULL);} etisserant@0: | CASE expression OF case_element_list ELSE statement_list END_CASE etisserant@0: {$$ = new case_statement_c($2, $4, $6);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* helper symbol for case_statement */ etisserant@0: case_element_list: etisserant@0: case_element etisserant@0: {$$ = new case_element_list_c(); $$->add_element($1);} etisserant@0: | case_element_list case_element etisserant@0: {$$ = $1; $$->add_element($2);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: case_element: etisserant@0: case_list ':' statement_list etisserant@0: {$$ = new case_element_c($1, $3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: case_list: etisserant@0: case_list_element etisserant@0: {$$ = new case_list_c(); $$->add_element($1);} etisserant@0: | case_list ',' case_list_element etisserant@0: {$$ = $1; $$->add_element($3);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: case_list_element: etisserant@0: signed_integer etisserant@0: | enumerated_value etisserant@0: | subrange etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /********************************/ etisserant@0: /* B 3.2.4 Iteration Statements */ etisserant@0: /********************************/ etisserant@0: iteration_statement: etisserant@0: for_statement etisserant@0: | while_statement etisserant@0: | repeat_statement etisserant@0: | exit_statement etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: for_statement: etisserant@0: FOR control_variable ASSIGN expression TO expression BY expression DO statement_list END_FOR etisserant@0: {$$ = new for_statement_c($2, $4, $6, $8, $10);} etisserant@0: | FOR control_variable ASSIGN expression TO expression DO statement_list END_FOR etisserant@0: {$$ = new for_statement_c($2, $4, $6, NULL, $8);} etisserant@0: ; etisserant@0: etisserant@0: /* The spec has the syntax etisserant@0: * control_variable: identifier; etisserant@0: * but then defines the semantics of control_variable etisserant@0: * (Section 3.3.2.4) as being of an integer type etisserant@0: * (e.g., SINT, INT, or DINT). etisserant@0: * etisserant@0: * Obviously this presuposes that the control_variable etisserant@0: * must have been declared in some VAR .. END_VAR etisserant@0: * construct, so I (Mario) changed the syntax to read etisserant@0: * control_variable: prev_declared_variable_name; etisserant@0: */ etisserant@0: control_variable: prev_declared_variable_name {$$ = $1;}; etisserant@0: etisserant@0: /* Integrated directly into for_statement */ etisserant@0: /* etisserant@0: for_list: etisserant@0: expression TO expression [BY expression] etisserant@0: ; etisserant@0: */ etisserant@0: etisserant@0: etisserant@0: while_statement: etisserant@0: WHILE expression DO statement_list END_WHILE etisserant@0: {$$ = new while_statement_c($2, $4);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: repeat_statement: etisserant@0: REPEAT statement_list UNTIL expression END_REPEAT etisserant@0: {$$ = new repeat_statement_c($2, $4);} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: exit_statement: etisserant@0: EXIT {$$ = new exit_statement_c();} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: %% etisserant@0: etisserant@0: #include /* required for printf() */ etisserant@0: #include etisserant@0: #include "../util/symtable.hh" etisserant@0: etisserant@0: /* variables defined in code generated by flex... */ etisserant@0: extern FILE *yyin; etisserant@0: extern int yylineno; etisserant@0: etisserant@0: /* The following function is called automatically by bison whenever it comes across etisserant@0: * an error. Unfortunately it calls this function before executing the code that handles etisserant@0: * the error itself, so we cannot print out the correct line numbers of the error location etisserant@0: * over here. etisserant@0: * Our solution is to store the current error message in a global variable, and have all etisserant@0: * error action handlers call the function print_err_msg() after setting the location etisserant@0: * (line number) variable correctly. etisserant@0: */ etisserant@0: const char *current_error_msg; etisserant@0: void yyerror (const char *error_msg) { etisserant@0: current_error_msg = error_msg; etisserant@0: /* fprintf(stderr, "error %d: %s\n", yynerrs // global variable //, error_msg); */ etisserant@0: print_include_stack(); etisserant@0: } etisserant@0: etisserant@0: etisserant@0: void print_err_msg(const char *filename, int lineno, const char *additional_error_msg) { etisserant@0: fprintf(stderr, "error %d: %s\n", yynerrs, additional_error_msg); etisserant@0: print_include_stack(); etisserant@0: fprintf(stderr, "%s:%d: %s\n", filename, lineno, current_error_msg); etisserant@0: } etisserant@0: etisserant@0: /* Function only called from within flex! etisserant@0: * etisserant@0: * search for a symbol in either of the two symbol tables etisserant@0: * declared above, and return the token id of the first etisserant@0: * symbol found. etisserant@0: * Searches first in the variables, and only if not found etisserant@0: * does it continue searching in the library elements etisserant@0: */ etisserant@0: int get_identifier_token(const char *identifier_str) { etisserant@0: // std::cout << "get_identifier_token(" << identifier_str << "): \n"; etisserant@0: int token_id; etisserant@0: etisserant@0: if ((token_id = variable_name_symtable.find_value(identifier_str)) == variable_name_symtable.end_value()) etisserant@0: if ((token_id = library_element_symtable.find_value(identifier_str)) == library_element_symtable.end_value()) etisserant@0: return identifier_token; etisserant@0: return token_id; etisserant@0: } etisserant@0: etisserant@0: etisserant@0: etisserant@0: /* convert between an il_operator to a function name */ etisserant@0: /* This a kludge! etisserant@0: * It is required because our language requires more than one etisserant@0: * look ahead token, and bison only works with one! etisserant@0: */ etisserant@0: #define op_2_str(op, str) {\ etisserant@0: op ## _operator_c *ptr = dynamic_cast(il_operator); \ etisserant@0: if (ptr != NULL) name = str; \ etisserant@0: } etisserant@0: etisserant@0: /* NOTE: this code is very ugly and un-eficient, but I (Mario) have many etisserant@0: * more things to worry about right now, so just let it be... etisserant@0: */ etisserant@0: symbol_c *il_operator_c_2_identifier_c(symbol_c *il_operator) { etisserant@0: const char *name = NULL; etisserant@0: etisserant@0: op_2_str(NOT, "NOT"); etisserant@0: etisserant@0: op_2_str(AND, "AND"); etisserant@0: op_2_str(OR, "OR"); etisserant@0: op_2_str(XOR, "XOR"); etisserant@0: op_2_str(ADD, "ADD"); etisserant@0: op_2_str(SUB, "SUB"); etisserant@0: op_2_str(MUL, "MUL"); etisserant@0: op_2_str(DIV, "DIV"); etisserant@0: op_2_str(MOD, "MOD"); etisserant@0: op_2_str(GT, "GT"); etisserant@0: op_2_str(GE, "GE"); etisserant@0: op_2_str(EQ, "EQ"); etisserant@0: op_2_str(LT, "LT"); etisserant@0: op_2_str(LE, "LE"); etisserant@0: op_2_str(NE, "NE"); etisserant@0: etisserant@0: op_2_str(LD, "LD"); etisserant@0: op_2_str(LDN, "LDN"); etisserant@0: op_2_str(ST, "ST"); etisserant@0: op_2_str(STN, "STN"); etisserant@0: etisserant@0: op_2_str(S, "S"); etisserant@0: op_2_str(R, "R"); etisserant@0: op_2_str(S1, "S1"); etisserant@0: op_2_str(R1, "R1"); etisserant@0: etisserant@0: op_2_str(CLK, "CLK"); etisserant@0: op_2_str(CU, "CU"); etisserant@0: op_2_str(CD, "CD"); etisserant@0: op_2_str(PV, "PV"); etisserant@0: op_2_str(IN, "IN"); etisserant@0: op_2_str(PT, "PT"); etisserant@0: etisserant@0: op_2_str(ANDN, "ANDN"); etisserant@0: op_2_str(ORN, "ORN"); etisserant@0: op_2_str(XORN, "XORN"); etisserant@0: etisserant@0: op_2_str(ADD, "ADD"); etisserant@0: op_2_str(SUB, "SUB"); etisserant@0: op_2_str(MUL, "MUL"); etisserant@0: op_2_str(DIV, "DIV"); etisserant@0: etisserant@0: op_2_str(GT, "GT"); etisserant@0: op_2_str(GE, "GE"); etisserant@0: op_2_str(EQ, "EQ"); etisserant@0: op_2_str(LT, "LT"); etisserant@0: op_2_str(LE, "LE"); etisserant@0: op_2_str(NE, "NE"); etisserant@0: etisserant@0: op_2_str(CAL, "CAL"); etisserant@0: op_2_str(CALC, "CALC"); etisserant@0: op_2_str(CALCN, "CALCN"); etisserant@0: op_2_str(RET, "RET"); etisserant@0: op_2_str(RETC, "RETC"); etisserant@0: op_2_str(RETCN, "RETCN"); etisserant@0: op_2_str(JMP, "JMP"); etisserant@0: op_2_str(JMPC, "JMPC"); etisserant@0: op_2_str(JMPCN, "JMPCN"); etisserant@0: etisserant@0: if (name == NULL) etisserant@0: ERROR; etisserant@0: etisserant@0: free(il_operator); etisserant@0: return new identifier_c(strdup(name)); etisserant@0: } etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /* etisserant@0: * Join two strings together. Allocate space with malloc(3). etisserant@0: */ etisserant@0: static char *strdup2(const char *a, const char *b) { etisserant@0: char *res = (char *)malloc(strlen(a) + strlen(b) + 1); etisserant@0: etisserant@0: if (!res) etisserant@0: return NULL; etisserant@0: return strcat(strcpy(res, a), b); /* safe, actually */ etisserant@0: } etisserant@0: etisserant@0: /* etisserant@0: * Join three strings together. Allocate space with malloc(3). etisserant@0: */ etisserant@0: static char *strdup3(const char *a, const char *b, const char *c) { etisserant@0: char *res = (char *)malloc(strlen(a) + strlen(b) + strlen(c) + 1); etisserant@0: etisserant@0: if (!res) etisserant@0: return NULL; etisserant@0: return strcat(strcat(strcpy(res, a), b), c); /* safe, actually */ etisserant@0: } etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: const char *standard_function_names[] = { etisserant@0: // 2.5.1.5.1 Type conversion functions etisserant@0: /* etisserant@0: *_TO_** etisserant@0: TRUNC etisserant@0: *_BCD_TO_** etisserant@0: **_TO_BCD_* etisserant@0: (REAL or LREAL to SINT, INT, DINT or LINT) etisserant@0: */ etisserant@0: "TRUNC", etisserant@0: "TIME_TO_REAL", etisserant@0: // 2.5.1.5.2 Numerical functions etisserant@0: // Table 23 - Standard functions of one numeric variable etisserant@0: "ABS","SQRT","LN","LOG","EXP","SIN","COS","TAN","ASIN","ACOS","ATAN", etisserant@0: // Table 24 - Standard arithmetic functions etisserant@0: "ADD","MUL","SUB","DIV","MOD"/* See note (a) */,"EXPT","MOVE", etisserant@0: // 2.5.1.5.3 Bit string functions etisserant@0: // Table 25 - Standard bit shift functions etisserant@0: "SHL","SHR","ROR","ROL", etisserant@0: // 2.5.1.5.4 Selection and comparison functions etisserant@0: // Table 26 - Standard bitwise Boolean functions etisserant@0: "AND","OR","XOR","NOT", etisserant@0: // Table 27 - Standard selection functions etisserant@0: "SEL","MAX","MIN","LIMIT","MUX", etisserant@0: // Table 28 - Standard comparison functions etisserant@0: "GT","GE","EQ","LE","LT","NE", etisserant@0: // 2.5.1.5.5 Character string functions etisserant@0: // Table 29 - Standard character string functions etisserant@0: "LEN","LEFT","RIGHT","MID","CONCAT","INSERT","DELETE","REPLACE","FIND", etisserant@0: // 2.5.1.5.6 Functions of time data types etisserant@0: // Table 30 - Functions of time data types etisserant@0: "ADD_TIME","ADD_TOD_TIME","ADD_DT_TIME","SUB_TIME","SUB_DATE_DATE", etisserant@0: "SUB_TOD_TIME","SUB_TOD_TOD","SUB_DT_TIME","SUB_DT_DT","MULTIME", etisserant@0: "DIVTIME","CONCAT_DATE_TOD", etisserant@0: // 2.5.1.5.7 Functions of enumerated data types etisserant@0: // Table 31 - Functions of enumerated data types etisserant@0: // "SEL", /* already above! We cannot have duplicates! */ etisserant@0: // "MUX", /* already above! We cannot have duplicates! */ etisserant@0: // "EQ", /* already above! We cannot have duplicates! */ etisserant@0: // "NE", /* already above! We cannot have duplicates! */ etisserant@0: etisserant@0: /* end of array marker! Do not remove! */ etisserant@0: NULL etisserant@0: etisserant@0: /* Note (a): etisserant@0: * This function has a name equal to a reserved keyword. etisserant@0: * This means that adding it here is irrelevant because the etisserant@0: * lexical parser will consider it the XXX token before etisserant@0: * it interprets it as an identifier and looks it up etisserant@0: * in the library elements symbol table. etisserant@0: */ etisserant@0: }; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: const char *standard_function_block_names[] = { etisserant@0: // 2.5.2.3.1 Bistable elements etisserant@0: // Table 34 - Standard bistable function blocks etisserant@0: //"SR","RS", etisserant@0: // 2.5.2.3.2 Edge detection etisserant@0: // Table 35 - Standard edge detection function blocks etisserant@0: "R_TRIG","F_TRIG", etisserant@0: // 2.5.2.3.3 Counters etisserant@0: // Table 36 - Standard counter function blocks etisserant@0: "CTU","CTU_LINT","CTU_UDINT","CTU_ULINT", etisserant@0: "CTD","CTD_DINT","CTD_LINT","CTD_UDINT", etisserant@0: "CTUD","CTUD_DINT","CTUD_LINT","CTUD_ULINT", etisserant@0: // 2.5.2.3.4 Timers etisserant@0: // Table 37 - Standard timer function blocks etisserant@0: "TP","TON","TOF", etisserant@0: /* end of array marker! Do not remove! */ etisserant@0: NULL etisserant@0: }; etisserant@0: etisserant@0: etisserant@0: #define LIBFILE "ieclib.txt" etisserant@0: #define DEF_LIBFILENAME LIBDIRECTORY "/" LIBFILE etisserant@0: etisserant@0: int stage1_2(const char *filename, const char *includedir, symbol_c **tree_root_ref) { etisserant@0: FILE *in_file = NULL, *lib_file = NULL; etisserant@0: char *libfilename = NULL; etisserant@0: etisserant@0: if((in_file = fopen(filename, "r")) == NULL) { etisserant@0: char *errmsg = strdup2("Error opening main file ", filename); etisserant@0: perror(errmsg); etisserant@0: free(errmsg); etisserant@0: return -1; etisserant@0: } etisserant@0: etisserant@0: if (includedir != NULL) { etisserant@0: if ((libfilename = strdup3(includedir, "/", LIBFILE)) == NULL) { etisserant@0: fprintf (stderr, "Out of memory. Bailing out!\n"); etisserant@0: return -1; etisserant@0: } etisserant@0: etisserant@0: if((lib_file = fopen(libfilename, "r")) == NULL) { etisserant@0: char *errmsg = strdup2("Error opening library file ", libfilename); etisserant@0: perror(errmsg); etisserant@0: free(errmsg); etisserant@0: } etisserant@0: } etisserant@0: etisserant@0: if (lib_file == NULL) { etisserant@0: /* we try again... */ etisserant@0: if ((libfilename = strdup(DEF_LIBFILENAME)) == NULL) { etisserant@0: fprintf (stderr, "Out of memory. Bailing out!\n"); etisserant@0: return -1; etisserant@0: } etisserant@0: etisserant@0: if((lib_file = fopen(libfilename, "r")) == NULL) { etisserant@0: char *errmsg = strdup2("Error opening library file ", libfilename); etisserant@0: perror(errmsg); etisserant@0: free(errmsg); etisserant@0: } etisserant@0: } etisserant@0: etisserant@0: if (lib_file == NULL) { etisserant@0: /* we give up... */ etisserant@0: free(libfilename); etisserant@0: fclose(in_file); etisserant@0: return -1; etisserant@0: } etisserant@0: etisserant@0: /* first parse the standard library file... */ etisserant@0: yyin = lib_file; etisserant@0: yylineno = 1; etisserant@0: allow_function_overloading = true; etisserant@0: current_filename = libfilename; etisserant@0: if (yyparse() != 0) etisserant@0: ERROR; etisserant@0: etisserant@0: if (yynerrs > 0) { etisserant@0: fprintf (stderr, "\nFound %d error(s) in %s. Bailing out!\n", yynerrs /* global variable */, libfilename); etisserant@0: ERROR; etisserant@0: } etisserant@0: free(libfilename); etisserant@0: fclose(lib_file); etisserant@0: etisserant@0: /* if by any chance the library is not complete, we etisserant@0: * now add the missing reserved keywords to the list!!! etisserant@0: */ etisserant@0: for(int i = 0; standard_function_names[i] != NULL; i++) etisserant@0: if (library_element_symtable.find_value(standard_function_names[i]) == etisserant@0: library_element_symtable.end_value()) etisserant@0: library_element_symtable.insert(standard_function_names[i], standard_function_name_token); etisserant@0: etisserant@0: for(int i = 0; standard_function_block_names[i] != NULL; i++) etisserant@0: if (library_element_symtable.find_value(standard_function_block_names[i]) == etisserant@0: library_element_symtable.end_value()) etisserant@0: library_element_symtable.insert(standard_function_block_names[i], standard_function_block_name_token); etisserant@0: etisserant@0: #if YYDEBUG etisserant@0: yydebug = 1; etisserant@0: #endif etisserant@0: etisserant@0: /* now parse the input file... */ etisserant@0: yyin = in_file; etisserant@0: yylineno = 1; etisserant@0: allow_function_overloading = false; etisserant@0: current_filename = filename; etisserant@0: if (yyparse() != 0) etisserant@0: exit(EXIT_FAILURE); etisserant@0: etisserant@0: if (yynerrs > 0) { etisserant@0: fprintf (stderr, "\nFound %d error(s). Bailing out!\n", yynerrs /* global variable */); etisserant@0: exit(EXIT_FAILURE); etisserant@0: } etisserant@0: etisserant@0: if (tree_root_ref != NULL) etisserant@0: *tree_root_ref = tree_root; etisserant@0: etisserant@0: fclose(in_file); etisserant@0: return 0; etisserant@0: } etisserant@0: etisserant@0: etisserant@0: