etisserant@0: /* msousa@264: * matiec - a compiler for the programming languages defined in IEC 61131-3 msousa@264: * msousa@264: * Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt) Edouard@279: * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant msousa@264: * msousa@264: * This program is free software: you can redistribute it and/or modify msousa@264: * it under the terms of the GNU General Public License as published by msousa@264: * the Free Software Foundation, either version 3 of the License, or msousa@264: * (at your option) any later version. msousa@264: * msousa@264: * This program is distributed in the hope that it will be useful, msousa@264: * but WITHOUT ANY WARRANTY; without even the implied warranty of msousa@264: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the msousa@264: * GNU General Public License for more details. msousa@264: * msousa@264: * You should have received a copy of the GNU General Public License msousa@264: * along with this program. If not, see . msousa@264: * 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: /* msousa@264: * An IEC 61131-3 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 mario@91: * languages IL and ST, as well as the textual version of SFC. mario@91: * The syntax parser, comprising the 2nd stage of the overall mario@91: * compiler, is generated by runing 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: msousa@547: /* NOTE: the following file contains many rules used merely for detecting errors in msousa@547: * the IEC source code being parsed. msousa@547: * To remove all these rules, simply execute the command (first replace all '%' with '/'): msousa@547: * $sed '\:%\* ERROR_CHECK_BEGIN \*%:,\:%\* ERROR_CHECK_END \*%: d' iec_bison.yy msousa@547: * msousa@547: * The above command had to be edited ('/' replaced by '%') so as not to include the C syntax that closes msousa@547: * comments inside this comment! msousa@547: * If you place the command in a shell script, be sure to remove the backslashes '\' before each asterisk '*' !! msousa@547: */ msousa@547: msousa@547: 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@41: #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! */ Edouard@822: #include "iec_bison.hh" mario@15: mario@68: /* The interface through which bison and flex interact. */ mario@15: #include "stage1_2_priv.hh" conti@748: #include "create_enumtype_conversion_functions.hh" etisserant@0: msousa@315: #include "../absyntax_utils/add_en_eno_param_decl.hh" /* required for add_en_eno_param_decl_c */ msousa@315: 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++) { \ msousa@1041: elem = list->get_element(i); \ etisserant@0: code; \ etisserant@0: } \ etisserant@0: } etisserant@0: etisserant@0: mario@68: mario@68: /* Macros used to pass the line and column locations when mario@68: * creating a new object for the abstract syntax tree. mario@68: */ msousa@287: #define locloc(foo) foo.first_line, foo.first_column, foo.first_file, foo.first_order, foo.last_line, foo.last_column, foo.last_file, foo.last_order msousa@287: #define locf(foo) foo.first_line, foo.first_column, foo.first_file, foo.first_order msousa@287: #define locl(foo) foo.last_line, foo.last_column, foo.last_file, foo.last_order msousa@286: msousa@286: /* Redefine the default action to take for each rule, so that the filenames are correctly processed... */ msousa@286: # define YYLLOC_DEFAULT(Current, Rhs, N) \ msousa@286: do \ msousa@286: if (N) \ msousa@286: { \ msousa@286: (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ msousa@286: (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \ msousa@286: (Current).first_file = YYRHSLOC(Rhs, 1).first_file; \ msousa@287: (Current).first_order = YYRHSLOC(Rhs, 1).first_order; \ msousa@286: (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ msousa@286: (Current).last_column = YYRHSLOC(Rhs, N).last_column; \ msousa@286: (Current).last_file = YYRHSLOC(Rhs, 1).last_file; \ msousa@287: (Current).last_order = YYRHSLOC(Rhs, 1).last_order; \ msousa@286: } \ msousa@286: else \ msousa@286: { \ msousa@286: (Current).first_line = (Current).last_line = \ msousa@286: YYRHSLOC(Rhs, 0).last_line; \ msousa@286: (Current).first_column = (Current).last_column = \ msousa@286: YYRHSLOC(Rhs, 0).last_column; \ msousa@286: (Current).first_file = (Current).last_file = \ msousa@286: YYRHSLOC(Rhs, 0).last_file; \ msousa@287: (Current).first_order = (Current).last_order = \ msousa@287: YYRHSLOC(Rhs, 0).last_order; \ msousa@286: } \ msousa@286: while (0) mario@68: mario@68: msousa@596: #include "../main.hh" // required for ERROR() and ERROR_MSG() macros. etisserant@0: etisserant@0: etisserant@0: etisserant@0: /*************************/ etisserant@0: /* global variables... */ etisserant@0: /*************************/ mario@15: /* NOTE: For some strange reason bison ver 2.3 is including these declarations Edouard@822: * in the iec_bison.hh file, which is in turn included by flex. mario@15: * We cannot therefore define any variables over here, but merely declare mario@15: * their existance (otherwise we get errors when linking the code, since we Edouard@822: * would get a new variable defined each time iec_bison.hh is included!). mario@15: * Even though the variables are declared 'extern' over here, they will in mario@15: * fact be defined towards the end of this same file (i.e. in the prologue) mario@15: */ etisserant@0: mario@177: mario@177: /* NOTE: These variable are really parameters we would like the stage2__ function to pass mario@177: * to the yyparse() function. However, the yyparse() function is created automatically mario@177: * by bison, so we cannot add parameters to this function. The only other mario@177: * option is to use global variables! yuck! mario@177: */ mario@177: 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: */ mario@15: extern bool allow_function_overloading; mario@15: msousa@350: /* A flag to tell the compiler whether to allow the declaration msousa@350: * of extensible function (i.e. functions that may have a variable number of msousa@350: * input parameters, such as AND(word#33, word#44, word#55, word#66). msousa@350: * This is an extension to the standard syntax. msousa@350: * See comments below for details why we support this! msousa@350: */ msousa@350: extern bool allow_extensible_function_parameters; msousa@350: mjsousa@934: /* A global flag used to tell the parser whether to allow use of DREF and '^' operators (defined in IEC 61131-3 v3) */ mjsousa@934: extern bool allow_ref_dereferencing; mjsousa@934: mjsousa@934: /* A global flag used to tell the parser whether to allow use of REF_TO ANY datatypes (non-standard extension to IEC 61131-3 v3) */ mjsousa@924: extern bool allow_ref_to_any; mjsousa@924: mjsousa@932: /* A global flag used to tell the parser whether to allow use of REF_TO as a struct or array element (non-standard extension) */ mjsousa@932: extern bool allow_ref_to_in_derived_datatypes; mjsousa@932: mjsousa@932: /* A pointer to the root of the parsing tree that will be generated by bison. */ mario@15: extern symbol_c *tree_root; mario@15: 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 */ mjsousa@958: identifier_c *il_operator_c_2_identifier_c (symbol_c *il_operator); mjsousa@958: /* Convert an il_operator_c into an poutype_identifier_c */ mjsousa@958: poutype_identifier_c *il_operator_c_2_poutype_identifier_c(symbol_c *il_operator); mjsousa@958: etisserant@0: lbessard@136: /* return if current token is a syntax element */ ccb@202: /* ERROR_CHECK_BEGIN */ lbessard@136: bool is_current_syntax_token(); ccb@202: /* ERROR_CHECK_END */ lbessard@136: etisserant@0: /* print an error message */ lbessard@136: void print_err_msg(int first_line, mario@95: int first_column, msousa@286: const char *first_filename, msousa@287: long int first_order, mario@95: int last_line, mario@95: int last_column, msousa@286: const char *last_filename, msousa@287: long int last_order, msousa@756: const char *additional_error_msg); etisserant@0: %} etisserant@0: etisserant@0: etisserant@0: mario@15: mario@20: // %glr-parser mario@13: // %expect-rr 1 mario@13: mario@13: msousa@286: /* The following definitions need to be inside a '%code requires' msousa@286: * so that they are also included in the header files. If this were not the case, msousa@286: * YYLTYPE would be delcared as something in the iec.cc file, and another thing Edouard@822: * (actually the default value of YYLTYPE) in the iec_bison.hh heder file. msousa@286: */ msousa@286: %code requires { msousa@286: /* define a new data type to store the locations, so we can also store msousa@286: * the filename in which the token is expressed. msousa@286: */ Edouard@822: /* NOTE: since this code will be placed in the iec_bison.hh header file, Edouard@822: * as well as the iec.cc file that also includes the iec_bison.hh header file, msousa@286: * declaring the typedef struct yyltype__local here would result in a msousa@286: * compilation error when compiling iec.cc, as this struct would be msousa@286: * declared twice. msousa@286: * We therefore use the #if !defined YYLTYPE ... msousa@286: * to make sure only the first declaration is parsed by the C++ compiler. msousa@286: */ msousa@286: #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED conti@415: typedef struct YYLTYPE { msousa@287: int first_line; msousa@287: int first_column; msousa@286: const char *first_file; msousa@287: long int first_order; msousa@287: int last_line; msousa@287: int last_column; msousa@286: const char *last_file; msousa@287: long int last_order; conti@415: } YYLTYPE; conti@415: #define YYLTYPE_IS_DECLARED 1 msousa@823: #define YYLTYPE_IS_TRIVIAL 0 msousa@286: #endif conti@415: msousa@286: } msousa@286: mario@13: mario@13: etisserant@0: %union { etisserant@0: symbol_c *leaf; etisserant@0: list_c *list; etisserant@0: char *ID; /* token value */ etisserant@0: } etisserant@0: mario@68: /* mario@68: TODO: DO we need to define a destructor do free mario@68: memory when recovering from errors, or do the mario@68: class destructors already handle this? mario@68: Following is example on how to define mario@68: detructors, using the syntax: mario@68: %destructor { CODE } SYMBOLS mario@68: %union mario@68: { mario@68: char *string; mario@68: } mario@68: %token STRING mario@68: %type string mario@68: %destructor { free ($$); } STRING string mario@68: */ etisserant@0: etisserant@0: etisserant@0: etisserant@0: ccb@202: /*************************************/ ccb@202: /* Prelimenary helpful constructs... */ ccb@202: /*************************************/ mario@73: /* A token used to identify the very end of the input file mario@73: * after all includes have already been processed. mario@73: * mario@73: * Flex automatically returns the token with value 0 mario@74: * at the end of the file. We therefore specify here mario@74: * a token with that exact same value here, so we can use it mario@74: * to detect the very end of the input files. mario@73: */ mario@73: %token END_OF_INPUT 0 mario@73: 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: mario@68: %type start mario@15: mario@15: %type any_identifier mario@15: mario@15: %token prev_declared_variable_name_token lbessard@175: %token prev_declared_direct_variable_token mario@15: %token prev_declared_fb_name_token mario@15: %type prev_declared_variable_name lbessard@175: %type prev_declared_direct_variable mario@15: %type prev_declared_fb_name mario@15: mario@15: %token prev_declared_simple_type_name_token mario@15: %token prev_declared_subrange_type_name_token mario@15: %token prev_declared_enumerated_type_name_token mario@15: %token prev_declared_array_type_name_token mario@15: %token prev_declared_structure_type_name_token mario@15: %token prev_declared_string_type_name_token mjsousa@876: %token prev_declared_ref_type_name_token /* defined in IEC 61131-3 v3 */ mario@15: mario@15: %type prev_declared_simple_type_name mario@15: %type prev_declared_subrange_type_name mario@15: %type prev_declared_enumerated_type_name mario@15: %type prev_declared_array_type_name mario@15: %type prev_declared_structure_type_name mario@15: %type prev_declared_string_type_name mjsousa@876: %type prev_declared_ref_type_name /* defined in IEC 61131-3 v3 */ mario@15: mario@15: %token prev_declared_derived_function_name_token mario@15: %token prev_declared_derived_function_block_name_token mario@15: %token prev_declared_program_type_name_token mario@15: %type prev_declared_derived_function_name mario@15: %type prev_declared_derived_function_block_name mario@15: %type prev_declared_program_type_name mario@15: mjsousa@1016: /* Tokens used to help resolve a reduce/reduce conflict */ mjsousa@1016: /* The mentioned conflict only arises due to a non-standard feature added to matiec. mjsousa@1016: * Namely, the permission to call functions returning VOID as an ST statement. mjsousa@1016: * e.g.: FUNCTION foo: VOID mjsousa@1016: * VAR_INPUT i: INT; END_VAR; mjsousa@1016: * ... mjsousa@1016: * END_FUNCTION mjsousa@1016: * mjsousa@1016: * FUNCTION BAR: BOOL mjsousa@1016: * VAR b: bool; END_VAR mjsousa@1016: * foo(i:=42); <--- Calling foo outside an expression. Function invocation is considered an ST statement!! mjsousa@1016: * END_FUNCTION mjsousa@1016: * mjsousa@1016: * The above function invocation may also be reduced to a formal IL function invocation, so we get a mjsousa@1016: * reduce/reduce conflict to st_statement_list/instruction_list (or something equivalent). mjsousa@1016: * mjsousa@1016: * We solve this by having flex determine if it is ST or IL invocation (ST ends with a ';' !!). mjsousa@1016: * At the start of a function/FB/program body, flex will tell bison whether to expect ST or IL code! mjsousa@1016: * This is why we need the following two tokens! mjsousa@1016: * mjsousa@1016: * NOTE: flex was already determing whther it was parsing ST or IL code as it can only send mjsousa@1016: * EOL tokens when parsing IL. However, did this silently without telling bison about this. mjsousa@1016: * Now, it does mjsousa@1016: */ mjsousa@1016: %token start_ST_body_token mjsousa@1016: %token start_IL_body_token mario@15: mario@15: mario@15: ccb@202: /**********************************************************************************/ ccb@202: /* B XXX - Things that are missing from the standard, but should have been there! */ ccb@202: /**********************************************************************************/ ccb@202: msousa@267: /* Pragmas that our compiler will accept. msousa@267: * See the comment in iec.flex for why these pragmas exist. msousa@267: */ msousa@267: %token disable_code_generation_pragma_token msousa@267: %token enable_code_generation_pragma_token msousa@267: %type disable_code_generation_pragma msousa@267: %type enable_code_generation_pragma msousa@267: msousa@267: msousa@267: /* All other pragmas that we do not support... */ msousa@267: /* In most stage 4, the text inside the pragmas will simply be copied to the output file. msousa@267: * This allows us to insert C code (if using stage 4 generating C code) msousa@267: * inside/interningled with the IEC 61131-3 code! msousa@267: */ etisserant@0: %token pragma_token etisserant@0: %type pragma etisserant@0: msousa@267: /* The joining of all previous pragmas, i.e. any possible pragma */ msousa@267: %type any_pragma msousa@267: etisserant@0: ccb@202: /* Where do these tokens belong?? They are missing from the standard! */ ccb@202: /* NOTE: There are other tokens related to these 'EN' ENO', that are also ccb@202: * missing from the standard. However, their location in the annex B is ccb@202: * relatively obvious, so they have been inserted in what seems to us their ccb@202: * correct place in order to ease understanding of the parser... msousa@315: * msousa@315: * please read the comment above the definition of 'variable' in section B1.4 for details. ccb@202: */ etisserant@0: %token EN etisserant@0: %token ENO ccb@202: %type en_identifier ccb@202: %type eno_identifier ccb@202: mjsousa@919: /* Keywords in IEC 61131-3 v3 */ mjsousa@873: %token REF mjsousa@933: %token DREF mjsousa@876: %token REF_TO mjsousa@919: %token NULL_token /* cannot use simply 'NULL', as it conflicts with the NULL keyword in C++ */ 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: /* B 1.2 - Constants */ etisserant@0: /*********************/ etisserant@0: %type constant msousa@643: %type non_int_or_real_constant etisserant@0: mjsousa@919: /*********************************/ mjsousa@919: /* B 1.2.XX - Reference Literals */ mjsousa@919: /*********************************/ mjsousa@919: /* NOTE: The following syntax was added by MJS in order to add support for the NULL keyword, defined in IEC 61131-3 v3 mjsousa@919: * In v3 expressions that reduce to a reference datatype (REF_TO) are handled explicitly in the syntax mjsousa@919: * (e.g., any variable that is a of reference datatpe falls under the 'ref_name' rule), which means mjsousa@919: * that we would need to keep track of which variables are declared as REF_TO. mjsousa@919: * In order to reduce the changes to the current IEC 61131-3 v2 syntax, I have opted not to do this, mjsousa@919: * and simply let the ref_expressions (Ref_Assign, Ref_Compare) be interpreted as all other standard expressions mjsousa@919: * in v2. However, ref_expressions allow the use of the 'NULL' constant, which is handled explicitly mjsousa@919: * in the ref_expressions syntax of v3. mjsousa@919: * To allow the use of the 'NULL' constant in this extended v2, I have opted to interpret this 'NULL' constant mjsousa@919: * as a literal. mjsousa@919: */ mjsousa@919: %type ref_value_null_literal /* defined in IEC 61131-3 v3 - Basically the 'NULL' keyword! */ mjsousa@919: mjsousa@919: 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: %type integer_literal etisserant@0: %type 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: %type real_literal etisserant@0: // %type exponent etisserant@0: %type bit_string_literal etisserant@0: %type boolean_literal etisserant@0: msousa@257: %token safeboolean_true_literal_token msousa@257: %token safeboolean_false_literal_token msousa@257: %token boolean_true_literal_token msousa@257: %token boolean_false_literal_token msousa@257: 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: %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 msousa@547: %token end_interval_token msousa@547: %token erroneous_interval_token msousa@257: // %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: msousa@257: // %token TIME_OF_DAY msousa@257: // %token DATE etisserant@0: %token D_SHARP msousa@257: // %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: msousa@257: %token TIME msousa@257: %token DATE msousa@257: %token DATE_AND_TIME etisserant@0: %token DT msousa@257: %token TIME_OF_DAY etisserant@0: %token TOD etisserant@0: mjsousa@1014: /* A non-standard extension! */ mjsousa@1014: %token VOID mjsousa@1014: msousa@257: /******************************************************/ msousa@257: /* Symbols defined in */ msousa@257: /* "Safety Software Technical Specification, */ msousa@257: /* Part 1: Concepts and Function Blocks, */ msousa@257: /* Version 1.0 – Official Release" */ msousa@257: /* by PLCopen - Technical Committee 5 - 2006-01-31 */ msousa@257: /******************************************************/ msousa@257: msousa@257: %token SAFEBYTE msousa@257: %token SAFEWORD msousa@257: %token SAFEDWORD msousa@257: %token SAFELWORD msousa@257: msousa@257: %token SAFELREAL msousa@257: %token SAFEREAL msousa@257: msousa@257: %token SAFESINT msousa@257: %token SAFEINT msousa@257: %token SAFEDINT msousa@257: %token SAFELINT msousa@257: msousa@257: %token SAFEUSINT msousa@257: %token SAFEUINT msousa@257: %token SAFEUDINT msousa@257: %token SAFEULINT msousa@257: msousa@257: %token SAFEWSTRING msousa@257: %token SAFESTRING msousa@257: %token SAFEBOOL msousa@257: msousa@257: %token SAFETIME msousa@257: %token SAFEDATE msousa@257: %token SAFEDATE_AND_TIME msousa@257: %token SAFEDT msousa@257: %token SAFETIME_OF_DAY msousa@257: %token SAFETOD 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 mjsousa@960: /* A non standard construct, used to support the use of variables in array subranges. e.g.: ARRAY [12..max] OF INT */ mjsousa@960: %type subrange_with_var 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 mario@85: //%type enumerated_value_without_identifier 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: mjsousa@932: %type ref_spec /* defined in IEC 61131-3 v3 */ mjsousa@932: %type ref_spec_non_recursive /* helper symbol */ mjsousa@932: %type ref_spec_init /* defined in IEC 61131-3 v3 */ mjsousa@932: %type ref_type_decl /* defined in IEC 61131-3 v3 */ mjsousa@876: mjsousa@876: 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 lbessard@175: //%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 ccb@202: /* en_param_declaration is not in the standard, but should be! */ lbessard@146: %type en_param_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 lbessard@146: %type var_output_init_decl lbessard@146: %type var_output_init_decl_list ccb@202: /* eno_param_declaration is not in the standard, but should be! */ lbessard@147: %type eno_param_declaration 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 lbessard@146: * - var_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: /***********************/ mario@68: // %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 mario@15: // %token END_VAR etisserant@0: %token VAR mario@15: // %token NON_RETAIN mario@15: // %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@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@131: %type transition_priority mario@85: %type transition_condition etisserant@0: %type action lbessard@151: %type action_body etisserant@1: %type transition_name etisserant@1: etisserant@0: mario@15: // %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 Laurent@627: %token P0 Laurent@627: %token P1 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: // mjsousa@862: %type global_var_declarations_list 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 mario@74: // 3 helper symbols for task_initialization mario@75: %type task_initialization_single mario@75: %type task_initialization_interval mario@75: %type task_initialization_priority mario@74: 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: mjsousa@952: %type prev_declared_configuration_name 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 mario@15: // %token END_VAR etisserant@0: %token WITH mario@15: // %token PROGRAM mario@15: // %token RETAIN mario@15: // %token NON_RETAIN mario@15: // %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 mario@91: //%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 mario@91: // helper symbol for il_simple_operation mario@91: %type il_operand_list2 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 laurent@382: %type il_simple_operator_clash3 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: */ mjsousa@933: %type ref_expression /* an extension to the IEC 61131-3 v2 standard, based on the IEC 61131-3 v3 standard */ mjsousa@933: %type deref_expression /* an extension to the IEC 61131-3 v2 standard, based on the IEC 61131-3 v3 standard */ 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 msousa@643: %type non_int_or_real_primary_expression etisserant@0: /* intermediate helper symbol for primary_expression */ etisserant@0: %type function_invocation etisserant@0: mario@15: // %token AND mario@15: // %token XOR mario@15: // %token OR mario@15: // %token MOD mario@15: // %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 mario@15: // %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 mario@85: // %type param_assignment mario@85: %type param_assignment_formal mario@85: %type param_assignment_nonformal mario@85: /* helper symbols for fb_invocation */ mario@85: %type param_assignment_formal_list mario@85: %type param_assignment_nonformal_list etisserant@0: mario@15: // %token ASSIGN mario@15: // %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 mario@15: // %token OF mario@15: // %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 mario@15: // %token ASSIGN mario@15: // %token TO etisserant@0: %token BY etisserant@0: %token DO etisserant@0: %token END_FOR etisserant@0: etisserant@0: %token WHILE mario@15: // %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: mario@177: 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: start: etisserant@0: library {$$ = $1;} etisserant@0: ; etisserant@0: ccb@202: ccb@202: /**********************************************************************************/ ccb@202: /* B XXX - Things that are missing from the standard, but should have been there! */ ccb@202: /**********************************************************************************/ ccb@202: ccb@202: etisserant@0: /* the pragmas... */ msousa@267: msousa@267: msousa@267: disable_code_generation_pragma: msousa@267: disable_code_generation_pragma_token {$$ = new disable_code_generation_pragma_c(locloc(@$));} msousa@267: msousa@267: enable_code_generation_pragma: msousa@267: enable_code_generation_pragma_token {$$ = new enable_code_generation_pragma_c(locloc(@$));} msousa@267: etisserant@0: pragma: mario@68: pragma_token {$$ = new pragma_c($1, locloc(@$));} etisserant@0: msousa@267: any_pragma: msousa@267: disable_code_generation_pragma msousa@267: | enable_code_generation_pragma msousa@267: | pragma msousa@267: ; msousa@267: ccb@202: lbessard@143: /* EN/ENO */ ccb@202: /* Tese tokens are essentially used as variable names, so we handle them ccb@202: * similarly to these... ccb@202: */ ccb@202: en_identifier: ccb@202: EN {$$ = new identifier_c("EN", locloc(@$));} ccb@202: ; ccb@202: ccb@202: eno_identifier: ccb@202: ENO {$$ = new identifier_c("ENO", locloc(@$));} ccb@202: ; ccb@202: ccb@202: ccb@202: ccb@202: /*************************************/ ccb@202: /* Prelimenary helpful constructs... */ ccb@202: /*************************************/ 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: /**/ mjsousa@953: /* ref_type_name is defined in IEC 61131-3 v3 */ mjsousa@953: | prev_declared_ref_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! mjsousa@953: | prev_declared_simple_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! mjsousa@953: | prev_declared_subrange_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! mjsousa@953: | prev_declared_enumerated_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! mjsousa@953: | prev_declared_array_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! mjsousa@953: | prev_declared_structure_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! mjsousa@953: | prev_declared_string_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! mjsousa@958: | prev_declared_derived_function_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the poutype_identifier_c into an identifier_c, as it will be taking the place of an identifier! mjsousa@958: | prev_declared_derived_function_block_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the poutype_identifier_c into an identifier_c, as it will be taking the place of an identifier! mjsousa@958: | prev_declared_program_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the poutype_identifier_c into an identifier_c, as it will be taking the place of an identifier! 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: mjsousa@958: /* NOTE: Notice that the symbol classes: mjsousa@958: * - derived_datatype_identifier_c mjsousa@958: * - poutype_identifier_c mjsousa@958: * are only inserted into the AST when referencing a derived dataype or a POU mjsousa@958: * (e.g. when declaring a variable, making a function call, instantiating a program in a resource, mjsousa@958: * or delaring a derived datatype that derives from another previously delcared datatype). mjsousa@958: * mjsousa@958: * In the declaration of the datatype or POU itself, the name of the datatype or POU will be stored mjsousa@958: * inside an identifier_c instead!! mjsousa@958: */ mjsousa@952: prev_declared_variable_name: prev_declared_variable_name_token {$$ = new identifier_c($1, locloc(@$));}; mjsousa@952: prev_declared_fb_name: prev_declared_fb_name_token {$$ = new identifier_c($1, locloc(@$));}; mjsousa@952: mjsousa@952: prev_declared_simple_type_name: prev_declared_simple_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; mjsousa@952: prev_declared_subrange_type_name: prev_declared_subrange_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; mjsousa@945: prev_declared_enumerated_type_name: prev_declared_enumerated_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; mjsousa@952: prev_declared_array_type_name: prev_declared_array_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; mjsousa@952: prev_declared_structure_type_name: prev_declared_structure_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; mjsousa@952: prev_declared_string_type_name: prev_declared_string_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; mjsousa@952: prev_declared_ref_type_name: prev_declared_ref_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; /* defined in IEC 61131-3 v3 */ mjsousa@952: mjsousa@958: prev_declared_derived_function_name: prev_declared_derived_function_name_token {$$ = new poutype_identifier_c($1, locloc(@$));}; mjsousa@958: prev_declared_derived_function_block_name: prev_declared_derived_function_block_name_token {$$ = new poutype_identifier_c($1, locloc(@$));}; mjsousa@958: prev_declared_program_type_name: prev_declared_program_type_name_token {$$ = new poutype_identifier_c($1, locloc(@$));}; mjsousa@958: /* NOTE: The poutype_identifier_c was introduced to allow the implementation of remove_forward_dependencies_c */ mjsousa@958: 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);} msousa@267: | library any_pragma msousa@267: {$$ = $1; $$->add_element($2);} mario@77: /* ERROR_CHECK_BEGIN */ lbessard@136: | library error library_element_declaration lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unknown syntax error."); yyerrok;} mario@73: | library error END_OF_INPUT lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unknown syntax error."); yyerrok;} mario@77: /* ERROR_CHECK_END */ 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... mario@78: * In order to solve this potential ambiguity, flex only parses the above mario@78: * identifiers as keywords / tokens if we are currently parsing IL code. mario@78: * When parsing all code other than IL code, the above identifiers are treated mario@78: * just like any other identifier. 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: mario@68: identifier_token {$$ = new identifier_c($1, locloc(@$));} mario@78: ; mario@78: mario@78: etisserant@0: etisserant@0: /*********************/ etisserant@0: /* B 1.2 - Constants */ etisserant@0: /*********************/ etisserant@0: constant: msousa@643: character_string etisserant@0: | time_literal etisserant@0: | bit_string_literal etisserant@0: | boolean_literal msousa@643: | numeric_literal msousa@643: /* NOTE: Our definition of numeric_literal is diferent than the one in the standard. msousa@643: * We will now add what is missing in our definition of numeric literal, so our msousa@643: * definition of constant matches what the definition of constant in the standard. msousa@643: */ etisserant@0: /* NOTE: in order to remove reduce/reduce conflicts, msousa@257: * [between -9.5 being parsed as msousa@257: * (i) a signed real, msousa@257: * (ii) or as a real preceded by the '-' operator msousa@257: * ] msousa@257: * we need to define a variant of the constant construct msousa@643: * where any real or integer constant is always preceded by msousa@643: * a sign (i.e. the '-' or '+' characters). msousa@643: * (For more info, see comment in the construct non_int_or_real_primary_expression) msousa@643: * msousa@643: * For the above reason, our definition of the numeric_literal construct msousa@643: * is missing the integer and real constrcuts (when not preceded by a sign) msousa@643: * so we add then here explicitly! msousa@643: */ msousa@643: | real msousa@643: | integer 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: */ mjsousa@919: | ref_value_null_literal /* defined in IEC 61131-3 v3. Basically the 'NULL' keyword! */ msousa@643: ; msousa@643: msousa@643: msousa@643: msousa@643: msousa@643: non_int_or_real_constant: msousa@643: character_string msousa@643: | time_literal msousa@643: | bit_string_literal msousa@643: | boolean_literal msousa@643: | numeric_literal msousa@643: /* NOTE: Our definition of numeric_literal is diferent than the one in the standard. msousa@643: * It is missing the integer and real when not prefixed by a sign msousa@643: * (i.e. -54, +42 is included in numerical_literal, msousa@643: * but 54, 42 is not parsed as a numeric_literal!!) msousa@643: */ msousa@257: /* NOTE: in order to remove reduce/reduce conflicts, msousa@257: * [between -9.5 being parsed as msousa@257: * (i) a signed real, msousa@257: * (ii) or as a real preceded by the '-' operator msousa@257: * ] msousa@643: * [and a similar situation for integers!] msousa@257: * we need to define a variant of the constant construct msousa@643: * where any real or integer constant is always preceded by msousa@643: * a sign (i.e. the '-' or '+' characters). msousa@643: * msousa@643: * For the above reason, our definition of the numeric_literal construct msousa@643: * is missing the integer and real constrcuts (when not preceded by a sign) msousa@643: */ etisserant@0: ; etisserant@0: mjsousa@919: /*********************************/ mjsousa@919: /* B 1.2.XX - Reference Literals */ mjsousa@919: /*********************************/ mjsousa@919: /* NOTE: The following syntax was added by MJS in order to add support for the NULL keyword, defined in IEC 61131-3 v3 mjsousa@919: * Please read the comment where the 'ref_value_null_literal' is declared as a mjsousa@919: */ mjsousa@919: /* defined in IEC 61131-3 v3 - Basically the 'NULL' keyword! */ mjsousa@919: ref_value_null_literal: mjsousa@919: NULL_token {$$ = new ref_value_null_literal_c(locloc(@$));} mjsousa@919: ; 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: * msousa@257: * - According to the spec, integer '.' 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: mario@68: real_token {$$ = new real_c($1, locloc(@$));} mario@68: | fixed_point_token {$$ = new real_c($1, locloc(@$));} mario@68: ; mario@68: mario@68: integer: integer_token {$$ = new integer_c($1, locloc(@$));}; mario@68: binary_integer: binary_integer_token {$$ = new binary_integer_c($1, locloc(@$));}; mario@68: octal_integer: octal_integer_token {$$ = new octal_integer_c($1, locloc(@$));}; mario@68: hex_integer: hex_integer_token {$$ = new hex_integer_c($1, locloc(@$));}; etisserant@0: etisserant@0: numeric_literal: etisserant@0: integer_literal etisserant@0: | real_literal etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: integer_literal: etisserant@0: integer_type_name '#' signed_integer msousa@520: {$$ = new integer_literal_c($1, $3, locloc(@$));} etisserant@0: | integer_type_name '#' binary_integer msousa@520: {$$ = new integer_literal_c($1, $3, locloc(@$));} etisserant@0: | integer_type_name '#' octal_integer msousa@520: {$$ = new integer_literal_c($1, $3, locloc(@$));} etisserant@0: | integer_type_name '#' hex_integer msousa@520: {$$ = new integer_literal_c($1, $3, locloc(@$));} msousa@643: | binary_integer msousa@643: | octal_integer msousa@643: | hex_integer msousa@643: //|signed_integer /* We expand the construct signed_integer here, so we can remove one of its constituents */ msousa@643: //| integer /* REMOVED! see note in the definition of constant for reason why integer is missing here! */ msousa@643: | '+' integer {$$ = $2;} msousa@643: | '-' integer {$$ = new neg_integer_c($2, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | integer_type_name signed_integer lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} lbessard@131: | integer_type_name binary_integer lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} lbessard@131: | integer_type_name octal_integer lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} lbessard@131: | integer_type_name hex_integer lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} lbessard@131: | integer_type_name '#' error lbessard@136: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for integer literal.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid value for integer literal."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: msousa@643: /* NOTE: this construct is used in the definition of integer_literal. However, in order to remove msousa@643: * a reduce/reduce conflict (see NOTE in definition of constant for reason why) msousa@643: * it is not used directly, but rather its expansion is copied there. msousa@643: * msousa@643: * If for some reason you need to change the definition of signed_integer, don't forget msousa@643: * to change its expansion in integer_literal too! msousa@643: */ etisserant@0: signed_integer: etisserant@0: integer etisserant@0: | '+' integer {$$ = $2;} msousa@257: | '-' integer {$$ = new neg_integer_c($2, locloc(@$));} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: real_literal: msousa@643: // signed_real /* We expand the construct signed_integer here, so we can remove one of its constituents */ msousa@643: // real /* REMOVED! see note in the definition of constant for reason why real is missing here! */ msousa@643: '+' real {$$ = $2;} msousa@643: | '-' real {$$ = new neg_real_c($2, locloc(@2));} msousa@643: | real_type_name '#' signed_real msousa@520: {$$ = new real_literal_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | real_type_name signed_real lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between real type name and value in real literal."); yynerrs++;} lbessard@131: | real_type_name '#' error lbessard@136: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for real literal.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid value for real literal."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: msousa@643: /* NOTE: this construct is used in the definition of real_literal. However, in order to remove msousa@643: * a reduce/reduce conflict (see NOTE in definition of constant for reason why) msousa@643: * it is not used directly, but rather its expansion is copied there. msousa@643: * msousa@643: * If for some reason you need to change the definition of signed_real, don't forget msousa@643: * to change its expansion in real_literal too! msousa@643: */ etisserant@0: signed_real: etisserant@0: real etisserant@0: | '+' real {$$ = $2;} msousa@257: | '-' real {$$ = new neg_real_c($2, locloc(@2));} msousa@257: ; msousa@257: etisserant@0: etisserant@0: bit_string_literal: etisserant@0: bit_string_type_name '#' integer /* i.e. unsigned_integer */ msousa@520: {$$ = new bit_string_literal_c($1, $3, locloc(@$));} etisserant@0: | bit_string_type_name '#' binary_integer msousa@520: {$$ = new bit_string_literal_c($1, $3, locloc(@$));} etisserant@0: | bit_string_type_name '#' octal_integer msousa@520: {$$ = new bit_string_literal_c($1, $3, locloc(@$));} etisserant@0: | bit_string_type_name '#' hex_integer msousa@520: {$$ = new bit_string_literal_c($1, $3, locloc(@$));} 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: */ lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | bit_string_type_name integer lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} lbessard@131: | bit_string_type_name binary_integer lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} lbessard@131: | bit_string_type_name octal_integer lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} lbessard@131: | bit_string_type_name hex_integer lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} lbessard@131: | bit_string_type_name '#' error msousa@257: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for bit string literal.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid value for bit string literal."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: boolean_literal: msousa@257: boolean_true_literal_token msousa@257: {$$ = new boolean_literal_c(new bool_type_name_c(locloc(@$)), msousa@257: new boolean_true_c(locloc(@$)), msousa@257: locloc(@$)); msousa@257: } msousa@257: | boolean_false_literal_token msousa@257: {$$ = new boolean_literal_c(new bool_type_name_c(locloc(@$)), mario@68: new boolean_false_c(locloc(@$)), msousa@257: locloc(@$)); msousa@257: } msousa@257: | safeboolean_true_literal_token msousa@257: {$$ = new boolean_literal_c(new safebool_type_name_c(locloc(@$)), msousa@257: new boolean_true_c(locloc(@$)), msousa@257: locloc(@$)); msousa@257: } msousa@257: | safeboolean_false_literal_token msousa@257: {$$ = new boolean_literal_c(new safebool_type_name_c(locloc(@$)), msousa@257: new boolean_false_c(locloc(@$)), msousa@257: locloc(@$)); msousa@257: } msousa@257: | FALSE msousa@257: {$$ = new boolean_literal_c(NULL, msousa@257: new boolean_false_c(locloc(@$)), msousa@257: locloc(@$)); msousa@257: } msousa@257: | TRUE msousa@257: {$$ = new boolean_literal_c(NULL, msousa@257: new boolean_true_c(locloc(@$)), msousa@257: locloc(@$)); msousa@257: } 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 mario@68: {$$ = new single_byte_character_string_c($1, locloc(@$));}; etisserant@0: etisserant@0: double_byte_character_string: double_byte_character_string_token mario@68: {$$ = new double_byte_character_string_c($1, locloc(@$));}; 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 msousa@257: {$$ = new duration_c(new time_type_name_c(locloc(@1)), NULL, $3, locloc(@$));} etisserant@0: | TIME '#' '-' interval msousa@257: {$$ = new duration_c(new time_type_name_c(locloc(@1)), new neg_time_c(locloc(@$)), $4, locloc(@$));} etisserant@0: | T_SHARP interval msousa@257: {$$ = new duration_c(new time_type_name_c(locloc(@1)), NULL, $2, locloc(@$));} etisserant@0: | T_SHARP '-' interval msousa@257: {$$ = new duration_c(new time_type_name_c(locloc(@1)), new neg_time_c(locloc(@$)), $3, locloc(@$));} msousa@257: | SAFETIME '#' interval msousa@257: {$$ = new duration_c(new safetime_type_name_c(locloc(@1)), NULL, $3, locloc(@$));} msousa@257: | SAFETIME '#' '-' interval msousa@257: {$$ = new duration_c(new safetime_type_name_c(locloc(@1)), new neg_time_c(locloc(@$)), $4, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | TIME interval lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME' and interval in duration."); yynerrs++;} lbessard@131: | TIME '-' interval lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME' and interval in duration."); yynerrs++;} msousa@547: | TIME '#' erroneous_interval_token msousa@547: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value for duration."); yynerrs++;} msousa@547: | T_SHARP erroneous_interval_token msousa@547: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid value for duration."); yynerrs++;} msousa@547: | TIME '#' '-' erroneous_interval_token msousa@547: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value for duration."); yynerrs++;} msousa@547: | T_SHARP '-' erroneous_interval_token msousa@547: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid value for duration."); yynerrs++;} msousa@547: /* ERROR_CHECK_END */ msousa@547: ; msousa@547: msousa@547: fixed_point: msousa@547: integer msousa@547: | fixed_point_token {$$ = new fixed_point_c($1, locloc(@$));}; etisserant@0: etisserant@0: etisserant@0: interval: msousa@547: days hours minutes seconds milliseconds end_interval_token msousa@547: {$$ = new interval_c($1, $2, $3, $4, $5, locloc(@$));}; msousa@547: ; msousa@547: msousa@547: msousa@547: days: /* fixed_point ('d') */ msousa@547: /* empty */ {$$ = NULL;} msousa@547: | fixed_point_d_token {$$ = new fixed_point_c($1, locloc(@$));}; msousa@547: | integer_d_token {$$ = new integer_c($1, locloc(@$));}; msousa@547: ; msousa@547: msousa@547: hours: /* fixed_point ('h') */ msousa@547: /* empty */ {$$ = NULL;} msousa@547: | fixed_point_h_token {$$ = new fixed_point_c($1, locloc(@$));}; msousa@547: | integer_h_token {$$ = new integer_c($1, locloc(@$));}; msousa@547: ; msousa@547: msousa@547: minutes: /* fixed_point ('m') */ msousa@547: /* empty */ {$$ = NULL;} msousa@547: | fixed_point_m_token {$$ = new fixed_point_c($1, locloc(@$));}; msousa@547: | integer_m_token {$$ = new integer_c($1, locloc(@$));}; msousa@547: ; msousa@547: msousa@547: seconds: /* fixed_point ('s') */ msousa@547: /* empty */ {$$ = NULL;} msousa@547: | fixed_point_s_token {$$ = new fixed_point_c($1, locloc(@$));}; msousa@547: | integer_s_token {$$ = new integer_c($1, locloc(@$));}; msousa@547: ; msousa@547: msousa@547: milliseconds: /* fixed_point ('ms') */ msousa@547: /* empty */ {$$ = NULL;} msousa@547: | fixed_point_ms_token {$$ = new fixed_point_c($1, locloc(@$));}; msousa@547: | integer_ms_token {$$ = new integer_c($1, locloc(@$));}; 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 msousa@257: {$$ = new time_of_day_c(new tod_type_name_c(locloc(@1)), $3, locloc(@$));} msousa@257: | SAFETIME_OF_DAY '#' daytime msousa@257: {$$ = new time_of_day_c(new safetod_type_name_c(locloc(@1)), $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | TIME_OF_DAY daytime lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME_OF_DAY' and daytime in time of day."); yynerrs++;} lbessard@131: | TIME_OF_DAY '#' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for time of day.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid value for time of day."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: daytime: etisserant@0: day_hour ':' day_minute ':' day_second mario@68: {$$ = new daytime_c($1, $3, $5, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@136: | ':' day_minute ':' day_second lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@4), "no value defined for hours in daytime."); yynerrs++;} lbessard@136: | error ':' day_minute ':' day_second lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid value defined for hours in daytime."); yyerrok;} lbessard@131: | day_hour day_minute ':' day_second lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between hours and minutes in daytime."); yynerrs++;} lbessard@131: | day_hour ':' ':' day_second lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no value defined for minutes in daytime."); yynerrs++;} lbessard@131: | day_hour ':' error ':' day_second lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value defined for minutes in daytime."); yyerrok;} lbessard@131: | day_hour ':' day_minute day_second lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "':' missing between minutes and seconds in daytime."); yynerrs++;} lbessard@131: | day_hour ':' day_minute ':' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@4), locf(@5), "no value defined for seconds in daytime.");} lbessard@136: else {print_err_msg(locf(@5), locl(@5), "invalid value for seconds in daytime."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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 msousa@257: {$$ = new date_c(new date_type_name_c(locloc(@1)), $3, locloc(@$));} etisserant@0: | D_SHARP date_literal msousa@257: {$$ = new date_c(new date_type_name_c(locloc(@1)), $2, locloc(@$));} msousa@257: | SAFEDATE '#' date_literal msousa@257: {$$ = new date_c(new safedate_type_name_c(locloc(@1)), $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | DATE date_literal lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'DATE' and date literal in date."); yynerrs++;} lbessard@131: | DATE '#' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for date.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid value for date."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | D_SHARP error lbessard@136: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no value defined for date.");} lbessard@136: else {print_err_msg(locf(@2), locl(@2), "invalid value for date."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: date_literal: etisserant@0: year '-' month '-' day mario@68: {$$ = new date_literal_c($1, $3, $5, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@136: | '-' month '-' day lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no value defined for year in date literal."); yynerrs++;} lbessard@131: | year month '-' day lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'-' missing between year and month in date literal."); yynerrs++;} lbessard@136: | year '-' '-' day lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no value defined for month in date literal."); yynerrs++;} lbessard@136: | year '-' error '-' day lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value defined for month in date literal."); yyerrok;} lbessard@136: | year '-' month day lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "'-' missing between month and day in date literal."); yynerrs++;} lbessard@136: | year '-' month '-' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@4), locf(@5), "no value defined for day in date literal.");} lbessard@136: else {print_err_msg(locf(@5), locl(@5), "invalid value for day in date literal."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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 msousa@257: {$$ = new date_and_time_c(new dt_type_name_c(locloc(@1)), $3, $5, locloc(@$));} msousa@257: | SAFEDATE_AND_TIME '#' date_literal '-' daytime msousa@257: {$$ = new date_and_time_c(new safedt_type_name_c(locloc(@1)), $3, $5, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | DATE_AND_TIME date_literal '-' daytime lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'DATE_AND_TIME' and date literal in date and time."); yynerrs++;} lbessard@131: | DATE_AND_TIME '#' '-' daytime lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no value defined for date literal in date and time."); yynerrs++;} lbessard@131: | DATE_AND_TIME '#' error '-' daytime lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value for date literal in date and time."); yyerrok;} lbessard@131: | DATE_AND_TIME '#' date_literal daytime lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "'-' missing between date literal and daytime in date and time."); yynerrs++;} lbessard@131: | DATE_AND_TIME '#' date_literal '-' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@4), locf(@5), "no value defined for daytime in date and time.");} lbessard@136: else {print_err_msg(locf(@5), locl(@5), "invalid value for daytime in date and time."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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: /***********************************/ msousa@257: /******************************************************/ msousa@257: /* SAFExxxx Symbols defined in */ msousa@257: /* "Safety Software Technical Specification, */ msousa@257: /* Part 1: Concepts and Function Blocks, */ msousa@257: /* Version 1.0 – Official Release" */ msousa@257: /* by PLCopen - Technical Committee 5 - 2006-01-31 */ msousa@257: /******************************************************/ msousa@257: 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 mario@68: | TIME {$$ = new time_type_name_c(locloc(@$));} mario@68: | BOOL {$$ = new bool_type_name_c(locloc(@$));} 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: */ msousa@257: | SAFETIME {$$ = new safetime_type_name_c(locloc(@$));} mario@177: | SAFEBOOL {$$ = new safebool_type_name_c(locloc(@$));} 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: msousa@257: SINT {$$ = new sint_type_name_c(locloc(@$));} msousa@257: | INT {$$ = new int_type_name_c(locloc(@$));} msousa@257: | DINT {$$ = new dint_type_name_c(locloc(@$));} msousa@257: | LINT {$$ = new lint_type_name_c(locloc(@$));} msousa@257: | SAFESINT {$$ = new safesint_type_name_c(locloc(@$));} msousa@257: | SAFEINT {$$ = new safeint_type_name_c(locloc(@$));} msousa@257: | SAFEDINT {$$ = new safedint_type_name_c(locloc(@$));} msousa@257: | SAFELINT {$$ = new safelint_type_name_c(locloc(@$));} etisserant@0: ; etisserant@0: etisserant@0: unsigned_integer_type_name: msousa@257: USINT {$$ = new usint_type_name_c(locloc(@$));} msousa@257: | UINT {$$ = new uint_type_name_c(locloc(@$));} msousa@257: | UDINT {$$ = new udint_type_name_c(locloc(@$));} msousa@257: | ULINT {$$ = new ulint_type_name_c(locloc(@$));} msousa@257: | SAFEUSINT {$$ = new safeusint_type_name_c(locloc(@$));} msousa@257: | SAFEUINT {$$ = new safeuint_type_name_c(locloc(@$));} msousa@257: | SAFEUDINT {$$ = new safeudint_type_name_c(locloc(@$));} msousa@257: | SAFEULINT {$$ = new safeulint_type_name_c(locloc(@$));} etisserant@0: ; etisserant@0: etisserant@0: real_type_name: msousa@257: REAL {$$ = new real_type_name_c(locloc(@$));} msousa@257: | LREAL {$$ = new lreal_type_name_c(locloc(@$));} msousa@257: | SAFEREAL {$$ = new safereal_type_name_c(locloc(@$));} msousa@257: | SAFELREAL {$$ = new safelreal_type_name_c(locloc(@$));} etisserant@0: ; etisserant@0: etisserant@0: date_type_name: msousa@257: DATE {$$ = new date_type_name_c(locloc(@$));} msousa@257: | TIME_OF_DAY {$$ = new tod_type_name_c(locloc(@$));} msousa@257: | TOD {$$ = new tod_type_name_c(locloc(@$));} msousa@257: | DATE_AND_TIME {$$ = new dt_type_name_c(locloc(@$));} msousa@257: | DT {$$ = new dt_type_name_c(locloc(@$));} msousa@257: | SAFEDATE {$$ = new safedate_type_name_c(locloc(@$));} msousa@257: | SAFETIME_OF_DAY {$$ = new safetod_type_name_c(locloc(@$));} msousa@257: | SAFETOD {$$ = new safetod_type_name_c(locloc(@$));} msousa@257: | SAFEDATE_AND_TIME {$$ = new safedt_type_name_c(locloc(@$));} msousa@257: | SAFEDT {$$ = new safedt_type_name_c(locloc(@$));} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: bit_string_type_name: msousa@257: BYTE {$$ = new byte_type_name_c(locloc(@$));} msousa@257: | WORD {$$ = new word_type_name_c(locloc(@$));} msousa@257: | DWORD {$$ = new dword_type_name_c(locloc(@$));} msousa@257: | LWORD {$$ = new lword_type_name_c(locloc(@$));} msousa@257: | SAFEBYTE {$$ = new safebyte_type_name_c(locloc(@$));} msousa@257: | SAFEWORD {$$ = new safeword_type_name_c(locloc(@$));} msousa@257: | SAFEDWORD {$$ = new safedword_type_name_c(locloc(@$));} msousa@257: | SAFELWORD {$$ = new safelword_type_name_c(locloc(@$));} 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: mario@68: STRING {$$ = new string_type_name_c(locloc(@$));} mario@68: | WSTRING {$$ = new wstring_type_name_c(locloc(@$));} msousa@257: | SAFESTRING {$$ = new safestring_type_name_c(locloc(@$));} msousa@257: | SAFEWSTRING {$$ = new safewstring_type_name_c(locloc(@$));} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /********************************/ etisserant@0: /* B 1.3.2 - Generic data types */ etisserant@0: /********************************/ mario@68: /* Strangely, the following symbol does not 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 mario@68: | prev_declared_array_type_name mario@68: | prev_declared_structure_type_name mario@68: | prev_declared_string_type_name mjsousa@876: | prev_declared_ref_type_name /* as defined in IEC 61131-3 v3 */ etisserant@0: ; etisserant@0: etisserant@0: single_element_type_name: mario@68: prev_declared_simple_type_name 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: */ mario@68: //| prev_declared_derived_function_block_name mario@68: | prev_declared_subrange_type_name mario@68: | prev_declared_enumerated_type_name 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 mjsousa@1012: {$$ = new data_type_declaration_c($2, locloc(@$)); if (runtime_options.conversion_functions) include_string((create_enumtype_conversion_functions_c::get_declaration($$)).c_str());} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | TYPE END_TYPE lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no data type declared in data type(s) declaration."); yynerrs++;} lbessard@131: | TYPE error type_declaration_list END_TYPE lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'TYPE' in data type(s) declaration."); yyerrok;} lbessard@136: | TYPE type_declaration_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed data type(s) declaration."); yyerrok;} lbessard@131: | TYPE error END_TYPE lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in data type(s) declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for data_type_declaration */ etisserant@0: type_declaration_list: etisserant@0: type_declaration ';' mario@68: {$$ = new type_declaration_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | type_declaration_list type_declaration ';' etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@134: | error ';' lbessard@136: {$$ = new type_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid data type declaration."); yyerrok;} lbessard@131: | type_declaration error lbessard@136: {$$ = new type_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of data type declaration."); yyerrok;} lbessard@131: | type_declaration_list type_declaration error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of data type declaration."); yyerrok;} lbessard@133: | type_declaration_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid data type declaration."); yyerrok;} lbessard@131: | type_declaration_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after data type declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ 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 mjsousa@876: | ref_type_decl /* defined in IEC 61131-3 v3 */ etisserant@0: ; etisserant@0: etisserant@0: simple_type_declaration: etisserant@0: /* simple_type_name ':' simple_spec_init */ msousa@734: /* To understand why simple_spec_init was brocken up into its consituent components in the following rules, please see note in the definition of 'enumerated_type_declaration'. */ mjsousa@954: /* PRE_PARSING or SINGLE_PHASE_PARSING */ mjsousa@954: /* The following rules will be run either by: mjsousa@954: * - the pre_parsing phase of two phase parsing (when preparsing command line option is chosen). mjsousa@954: * - the standard single phase parser (when preparsing command line option is not chosen). mjsousa@954: */ msousa@734: identifier ':' simple_specification {library_element_symtable.insert($1, prev_declared_simple_type_name_token);} mjsousa@954: {if (!get_preparse_state()) $$ = new simple_type_declaration_c($1, $3, locloc(@$));} mjsousa@952: | identifier ':' elementary_type_name {library_element_symtable.insert($1, prev_declared_simple_type_name_token);} ASSIGN constant mjsousa@954: {if (!get_preparse_state()) $$ = new simple_type_declaration_c($1, new simple_spec_init_c($3, $6, locf(@3), locl(@5)), locloc(@$));} mjsousa@952: | identifier ':' prev_declared_simple_type_name {library_element_symtable.insert($1, prev_declared_simple_type_name_token);} ASSIGN constant mjsousa@954: {if (!get_preparse_state()) $$ = new simple_type_declaration_c($1, new simple_spec_init_c($3, $6, locf(@3), locl(@5)), locloc(@$));} mjsousa@954: /* POST_PARSING */ mjsousa@954: /* These rules will be run after the preparser phase of two phase parsing has finished (only gets to execute if preparsing command line option is chosen). */ mjsousa@952: | prev_declared_simple_type_name ':' simple_spec_init mjsousa@954: {$$ = new simple_type_declaration_c(new identifier_c(((token_c *)$1)->value, locloc(@1)), $3, locloc(@$));} // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! mjsousa@952: /* These three rules can now be safely replaced by the original rule abvoe!! */ mjsousa@952: /* mjsousa@952: | prev_declared_simple_type_name ':' simple_specification msousa@734: {$$ = new simple_type_declaration_c($1, $3, locloc(@$));} mjsousa@952: | prev_declared_simple_type_name ':' elementary_type_name ASSIGN constant mjsousa@952: {$$ = new simple_type_declaration_c($1, new simple_spec_init_c($3, $5, locf(@3), locl(@5)), locloc(@$));} mjsousa@952: | prev_declared_simple_type_name ':' prev_declared_simple_type_name ASSIGN constant mjsousa@952: {$$ = new simple_type_declaration_c($1, new simple_spec_init_c($3, $5, locf(@3), locl(@5)), locloc(@$));} mjsousa@952: */ lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@136: | error ':' simple_spec_init lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for data type declaration.");yyerrok;} lbessard@131: | identifier simple_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in simple type declaration."); yynerrs++;} lbessard@131: | identifier ':' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in data type declaration.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid specification in data type declaration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: simple_spec_init: etisserant@0: simple_specification mario@68: /* The following commented line was changed to the mario@68: * next two lines 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 mario@68: {$$ = new simple_spec_init_c($1, $3, locloc(@$));} etisserant@0: | prev_declared_simple_type_name ASSIGN constant mario@68: {$$ = new simple_spec_init_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | elementary_type_name constant lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in specification with initialization."); yynerrs++;} lbessard@136: | prev_declared_simple_type_name constant lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in specification with initialization."); yynerrs++;} lbessard@136: | elementary_type_name ASSIGN error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in specification with initialization.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid initial value in specification with initialization."); yyclearin;} lbessard@136: yyerrok; lbessard@136: } lbessard@136: | prev_declared_simple_type_name ASSIGN error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in specification with initialization.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid initial value in specification with initialization."); yyclearin;} lbessard@136: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new simple_spec_init_c($1, NULL, locloc(@$));} etisserant@0: | prev_declared_simple_type_name mario@68: {$$ = new simple_spec_init_c($1, NULL, locloc(@$));} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: subrange_type_declaration: etisserant@0: /* subrange_type_name ':' subrange_spec_init */ mjsousa@954: /* PRE_PARSING or SINGLE_PHASE_PARSING */ mjsousa@954: /* The following rules will be run either by: mjsousa@954: * - the pre_parsing phase of two phase parsing (when preparsing command line option is chosen). mjsousa@954: * - the standard single phase parser (when preparsing command line option is not chosen). mjsousa@954: */ mjsousa@952: identifier ':' subrange_spec_init {library_element_symtable.insert($1, prev_declared_subrange_type_name_token);} mjsousa@954: {if (!get_preparse_state()) $$ = new subrange_type_declaration_c($1, $3, locloc(@$));} mjsousa@954: /* POST_PARSING */ mjsousa@954: /* These rules will be run after the preparser phase of two phase parsing has finished (only gets to execute if preparsing command line option is chosen). */ mjsousa@952: | prev_declared_subrange_type_name ':' subrange_spec_init mjsousa@954: {$$ = new subrange_type_declaration_c(new identifier_c(((token_c *)$1)->value, locloc(@1)), $3, locloc(@$));} // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@136: | error ':' subrange_spec_init lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for subrange type declaration."); yyerrok;} lbessard@131: | identifier subrange_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in subrange type declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: subrange_spec_init: etisserant@0: subrange_specification mario@68: {$$ = new subrange_spec_init_c($1, NULL, locloc(@$));} etisserant@0: | subrange_specification ASSIGN signed_integer mario@68: {$$ = new subrange_spec_init_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | subrange_specification signed_integer lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in subrange specification with initialization."); yynerrs++;} lbessard@136: | subrange_specification ASSIGN error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in subrange specification with initialization.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid initial value in subrange specification with initialization."); yyclearin;} lbessard@136: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: subrange_specification: lbessard@131: integer_type_name '(' subrange ')' mario@68: {$$ = new subrange_specification_c($1, $3, locloc(@$));} mario@68: | prev_declared_subrange_type_name lbessard@98: {$$ = new subrange_specification_c($1, NULL, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | integer_type_name '(' ')' lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no subrange defined in subrange specification."); yynerrs++;} lbessard@131: | integer_type_name '(' error ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid subrange defined in subrange specification."); yyerrok;} lbessard@131: | integer_type_name '(' subrange error lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing after subrange defined in subrange specification."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: mjsousa@960: /* a non standard construct, used to allow the declaration of array subranges using a variable */ mjsousa@960: subrange_with_var: etisserant@0: signed_integer DOTDOT signed_integer mario@68: {$$ = new subrange_c($1, $3, locloc(@$));} mjsousa@960: | any_identifier DOTDOT signed_integer mjsousa@980: {$$ = new subrange_c(new symbolic_constant_c($1, locloc(@1)), $3, locloc(@$)); mjsousa@980: if (!runtime_options.nonliteral_in_array_size) { mjsousa@980: print_err_msg(locf(@1), locl(@1), "Use of variables in array size limits is not allowed in IEC 61131-3 (use -a option to activate support for this non-standard feature)."); mjsousa@980: yynerrs++; mjsousa@980: } mjsousa@980: } mjsousa@960: | signed_integer DOTDOT any_identifier mjsousa@980: {$$ = new subrange_c($1, new symbolic_constant_c($3, locloc(@3)), locloc(@$)); mjsousa@980: if (!runtime_options.nonliteral_in_array_size) { mjsousa@980: print_err_msg(locf(@3), locl(@3), "Use of variables in array size limits is not allowed in IEC 61131-3 (use -a option to activate support for this non-standard feature)."); mjsousa@980: yynerrs++; mjsousa@980: } mjsousa@980: } mjsousa@960: | any_identifier DOTDOT any_identifier mjsousa@980: {$$ = new subrange_c(new symbolic_constant_c($1, locloc(@1)), new symbolic_constant_c($3, locloc(@3)), locloc(@$)); mjsousa@980: if (!runtime_options.nonliteral_in_array_size) { mjsousa@980: print_err_msg(locf(@$), locl(@$), "Use of variables in array size limits is not allowed in IEC 61131-3 (use -a option to activate support for this non-standard feature)."); mjsousa@980: yynerrs++; mjsousa@980: } mjsousa@980: } lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | signed_integer signed_integer lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'..' missing between bounds in subrange definition."); yynerrs++;} lbessard@131: | signed_integer DOTDOT error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for upper bound in subrange definition.");} msousa@584: else {print_err_msg(locf(@3), locl(@3), "invalid value for upper bound in subrange definition."); yyclearin;} lbessard@134: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: mjsousa@960: mjsousa@960: subrange: mjsousa@960: signed_integer DOTDOT signed_integer mjsousa@960: {$$ = new subrange_c($1, $3, locloc(@$));} mjsousa@960: /* ERROR_CHECK_BEGIN */ mjsousa@960: | signed_integer signed_integer mjsousa@960: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'..' missing between bounds in subrange definition."); yynerrs++;} mjsousa@960: | signed_integer DOTDOT error mjsousa@960: {$$ = NULL; mjsousa@960: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for upper bound in subrange definition.");} mjsousa@960: else {print_err_msg(locf(@3), locl(@3), "invalid value for upper bound in subrange definition."); yyclearin;} mjsousa@960: yyerrok; mjsousa@960: } mjsousa@960: /* ERROR_CHECK_END */ mjsousa@960: ; mjsousa@960: mjsousa@960: etisserant@0: enumerated_type_declaration: etisserant@0: /* enumerated_type_name ':' enumerated_spec_init */ msousa@734: /* NOTE: The 'identifier' used for the name of the new enumerated type is inserted early into the library_element_symtable so it may be used msousa@734: * in defining the default initial value of this type, using the fully qualified enumerated constant syntax: type_name#enum_value msousa@734: * In other words, this allows us to correclty parse the following IEC 61131-3 code: msousa@734: * TYPE enum_t : (x1, x2, x3) := enum_t#x3; END_TYPE msousa@734: * ^^^^^^^ msousa@734: * msousa@734: * However, we can only introduce it after we are sure we are parsing an enumerated_spec. For this reason, instead of using the msousa@734: * symbol enumerated_spec_init in this rule, we decompose it here instead! msousa@734: * msousa@734: * If it were not for the above, we could use the rule msousa@734: * identifier ':' enumerated_spec_init msousa@734: * and include the library_element_symtable.insert(...) code in the rule actions! msousa@734: */ mjsousa@954: /* PRE_PARSING or SINGLE_PHASE_PARSING */ mjsousa@954: /* The following rules will be run either by: mjsousa@954: * - the pre_parsing phase of two phase parsing (when preparsing command line option is chosen). mjsousa@954: * - the standard single phase parser (when preparsing command line option is not chosen). mjsousa@954: */ msousa@734: identifier ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} mjsousa@954: {if (!get_preparse_state()) $$ = new enumerated_type_declaration_c($1, new enumerated_spec_init_c($3, NULL, locloc(@3)), locloc(@$));} mjsousa@952: | identifier ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} ASSIGN enumerated_value mjsousa@954: {if (!get_preparse_state()) $$ = new enumerated_type_declaration_c($1, new enumerated_spec_init_c($3, $6, locf(@3), locl(@6)), locloc(@$));} mjsousa@954: /* POST_PARSING */ mjsousa@954: /* These rules will be run after the preparser phase of two phase parsing has finished (only gets to execute if preparsing command line option is chosen). */ mjsousa@952: /* Since the enumerated type name is placed in the library_element_symtable during preparsing, we can now safely use the single rule: */ mjsousa@952: | prev_declared_enumerated_type_name ':' enumerated_spec_init mjsousa@954: {$$ = new enumerated_type_declaration_c(new identifier_c(((token_c *)$1)->value, locloc(@1)), $3, locloc(@$));} // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! mjsousa@952: /* These two rules are equivalent to the above rule */ mjsousa@952: /* mjsousa@952: | prev_declared_enumerated_type_name ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} msousa@756: {$$ = new enumerated_type_declaration_c($1, new enumerated_spec_init_c($3, NULL, locloc(@3)), locloc(@$));} mjsousa@952: | prev_declared_enumerated_type_name ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} ASSIGN enumerated_value msousa@734: {$$ = new enumerated_type_declaration_c($1, new enumerated_spec_init_c($3, $6, locf(@3), locl(@6)), locloc(@$));} mjsousa@952: */ lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@136: | error ':' enumerated_spec_init lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for enumerated type declaration."); yyerrok;} lbessard@131: | identifier enumerated_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in enumerated type declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: enumerated_spec_init: etisserant@0: enumerated_specification mario@68: {$$ = new enumerated_spec_init_c($1, NULL, locloc(@$));} etisserant@0: | enumerated_specification ASSIGN enumerated_value mario@68: {$$ = new enumerated_spec_init_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | enumerated_specification enumerated_value lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in enumerated specification with initialization."); yynerrs++;} lbessard@136: | enumerated_specification ASSIGN error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined in enumerated specification with initialization.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid value in enumerated specification with initialization."); yyclearin;} lbessard@136: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: enumerated_specification: etisserant@0: '(' enumerated_value_list ')' etisserant@0: {$$ = $2;} mario@68: | prev_declared_enumerated_type_name lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | '(' ')' lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no enumerated value list defined in enumerated specification."); yynerrs++;} lbessard@131: | '(' error ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid enumerated value list defined in enumerated specification.");yyerrok;} lbessard@131: | '(' enumerated_value_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of enumerated specification."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for enumerated_specification */ etisserant@0: enumerated_value_list: etisserant@0: enumerated_value mario@68: {$$ = new enumerated_value_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | enumerated_value_list ',' enumerated_value etisserant@0: {$$ = $1; $$->add_element($3);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | enumerated_value_list enumerated_value lbessard@136: {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in enumerated value list.");} lbessard@131: | enumerated_value_list ',' error lbessard@134: {$$ = $1; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined in enumerated value list.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid value in enumerated value list."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: enumerated_value: mario@85: identifier lbessard@121: {$$ = new enumerated_value_c(NULL, $1, locloc(@$));} etisserant@0: | prev_declared_enumerated_type_name '#' any_identifier mario@68: {$$ = new enumerated_value_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | prev_declared_enumerated_type_name any_identifier lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between enumerated type name and value in enumerated literal."); yynerrs++;} lbessard@131: | prev_declared_enumerated_type_name '#' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for enumerated literal.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid value for enumerated literal."); yyclearin;} lbessard@136: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: mario@85: /* mario@13: enumerated_value_without_identifier: mario@13: prev_declared_enumerated_type_name '#' any_identifier mario@68: {$$ = new enumerated_value_c($1, $3, locloc(@$));} mario@13: ; mario@85: */ mario@13: etisserant@0: etisserant@0: array_type_declaration: etisserant@0: /* array_type_name ':' array_spec_init */ mjsousa@954: /* PRE_PARSING or SINGLE_PHASE_PARSING */ mjsousa@954: /* The following rules will be run either by: mjsousa@954: * - the pre_parsing phase of two phase parsing (when preparsing command line option is chosen). mjsousa@954: * - the standard single phase parser (when preparsing command line option is not chosen). mjsousa@954: */ mjsousa@952: identifier ':' array_spec_init {library_element_symtable.insert($1, prev_declared_array_type_name_token);} mjsousa@955: {if (!get_preparse_state()) $$ = new array_type_declaration_c($1, $3, locloc(@$));} mjsousa@954: /* POST_PARSING */ mjsousa@954: /* These rules will be run after the preparser phase of two phase parsing has finished (only gets to execute if preparsing command line option is chosen). */ mjsousa@952: | prev_declared_array_type_name ':' array_spec_init mjsousa@954: {$$ = new array_type_declaration_c(new identifier_c(((token_c *)$1)->value, locloc(@1)), $3, locloc(@$));} // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | identifier array_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in array type declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: array_spec_init: etisserant@0: array_specification mario@68: {$$ = new array_spec_init_c($1, NULL, locloc(@$));} etisserant@0: | array_specification ASSIGN array_initialization mario@68: {$$ = new array_spec_init_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | array_specification array_initialization lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in array specification with initialization."); yynerrs++;} lbessard@136: | array_specification ASSIGN error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in array specification with initialization.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid initial value in array specification with initialization."); yyclearin;} lbessard@136: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: array_specification: etisserant@0: prev_declared_array_type_name etisserant@0: | ARRAY '[' array_subrange_list ']' OF non_generic_type_name mario@68: {$$ = new array_specification_c($3, $6, locloc(@$));} mjsousa@932: | ARRAY '[' array_subrange_list ']' OF ref_spec_non_recursive mjsousa@932: /* non standard extension: Allow use of arrays storing REF_TO datatypes that are declared as 'ARRAY [1..3] OF REF_TO INT' */ mjsousa@932: /* ^^^^^^ */ mjsousa@932: /* NOTE: We use ref_spec and not ref_spec_init as for the moment I do not want to allow direct specification of initial value. mjsousa@932: * I (MJS) am not too sure whether this is currently supported in code generation, so leave it out for now. mjsousa@932: * It also does not seem to be a very good idea to allow initial value specification when declaring the array, mjsousa@932: * since the standard syntax does not allow it either for any other datatype! mjsousa@932: * NOTE: We use ref_spec_non_recursive instead of ref_spec in order to remove a reduce/reduce conflict. mjsousa@932: * Note that non_generic_type_name that is used in the previous rule already include the prev_declared_ref_type_name. mjsousa@932: * which leads to the reduce/reduce conflict, as it is also included in ref_spec. mjsousa@932: */ mjsousa@932: {$$ = new array_specification_c($3, $6, locloc(@$)); mjsousa@932: if (!allow_ref_to_in_derived_datatypes) { mjsousa@932: print_err_msg(locf(@$), locl(@$), "REF_TO may not be used in an ARRAY specification (use -R option to activate support for this non-standard syntax)."); mjsousa@932: yynerrs++; mjsousa@932: } mjsousa@932: } lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | ARRAY array_subrange_list ']' OF non_generic_type_name lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'[' missing before subrange list in array specification."); yynerrs++;} lbessard@131: | ARRAY '[' ']' OF non_generic_type_name lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no subrange list defined in array specification."); yynerrs++;} lbessard@131: | ARRAY '[' error ']' OF non_generic_type_name lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid subrange list defined in array specification."); yyerrok;} lbessard@131: | ARRAY OF non_generic_type_name lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no subrange list defined in array specification."); yynerrs++;} lbessard@131: | ARRAY error OF non_generic_type_name lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid subrange list defined in array specification."); yyerrok;} lbessard@131: | ARRAY '[' array_subrange_list OF non_generic_type_name lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "']' missing after subrange list in array specification."); yynerrs++;} lbessard@131: | ARRAY '[' array_subrange_list ']' non_generic_type_name lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "'OF' missing between subrange list and item type name in array specification."); yynerrs++;} lbessard@131: | ARRAY '[' array_subrange_list ']' OF error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no item data type defined in array specification.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid item data type in array specification."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for array_specification */ etisserant@0: array_subrange_list: mjsousa@960: /* the construct 'subrange' has been replaced with 'subrange_with_var' in order to support the declaration of array ranges using a varable: e.g. ARRAY [2..max] OF INT */ mjsousa@960: subrange_with_var mario@68: {$$ = new array_subrange_list_c(locloc(@$)); $$->add_element($1);} mjsousa@960: | array_subrange_list ',' subrange_with_var lbessard@98: {$$ = $1; $$->add_element($3);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | array_subrange_list subrange lbessard@136: {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in subrange list."); yynerrs++;} lbessard@131: | array_subrange_list ',' error lbessard@134: {$$ = $1; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no subrange defined in subrange list.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid subrange in subrange list."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: array_initialization: etisserant@0: '[' array_initial_elements_list ']' etisserant@0: {$$ = $2;} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | '[' ']' lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no initial values list defined in array initialization."); yynerrs++;} lbessard@131: | '[' error ']' lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid initial values list defined in array initialization."); yyerrok;} lbessard@131: | '[' array_initial_elements_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "']' missing at the end of array initialization."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* helper symbol for array_initialization */ etisserant@0: array_initial_elements_list: etisserant@0: array_initial_elements mario@68: {$$ = new array_initial_elements_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | array_initial_elements_list ',' array_initial_elements etisserant@0: {$$ = $1; $$->add_element($3);} msousa@547: /* ERROR_CHECK_BEGIN */ msousa@547: /* The following error checking rules have been commented out. Why? Was it a typo? msousa@547: * Lets keep them commented out for now... msousa@547: */ msousa@547: /* lbessard@131: | array_initial_elements_list ',' error lbessard@134: {$$ = $1; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no array initial value in array initial values list.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid array initial value in array initial values list."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } msousa@547: */ lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: array_initial_elements: etisserant@0: array_initial_element etisserant@0: | integer '(' ')' laurent@377: {$$ = new array_initial_elements_c($1, NULL, locloc(@$));} etisserant@0: | integer '(' array_initial_element ')' mario@68: {$$ = new array_initial_elements_c($1, $3, locloc(@$));} lbessard@136: /* ERROR_CHECK_BEGIN */ lbessard@131: | integer '(' error ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid array initial value in array initial values list."); yyerrok;} lbessard@131: | integer '(' array_initial_element error lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of array initial value in array initial values list."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ 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 */ mjsousa@954: /* PRE_PARSING or SINGLE_PHASE_PARSING */ mjsousa@954: /* The following rules will be run either by: mjsousa@954: * - the pre_parsing phase of two phase parsing (when preparsing command line option is chosen). mjsousa@954: * - the standard single phase parser (when preparsing command line option is not chosen). mjsousa@954: */ mjsousa@952: identifier ':' structure_specification {library_element_symtable.insert($1, prev_declared_structure_type_name_token);} mjsousa@954: {if (!get_preparse_state()) $$ = new structure_type_declaration_c($1, $3, locloc(@$));} mjsousa@954: /* POST_PARSING */ mjsousa@954: /* These rules will be run after the preparser phase of two phase parsing has finished (only gets to execute if preparsing command line option is chosen). */ mjsousa@952: | prev_declared_structure_type_name ':' structure_specification mjsousa@954: {$$ = new structure_type_declaration_c(new identifier_c(((token_c *)$1)->value, locloc(@1)), $3, locloc(@$));} // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | identifier structure_specification lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in structure type declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new initialized_structure_c($1, NULL, locloc(@$));} etisserant@0: | prev_declared_structure_type_name ASSIGN structure_initialization mario@68: {$$ = new initialized_structure_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | prev_declared_structure_type_name structure_initialization lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in structure specification with initialization."); yynerrs++;} lbessard@136: | prev_declared_structure_type_name ASSIGN error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined in structure specification with initialization.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid value in structure specification with initialization."); yyclearin;} lbessard@136: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: structure_declaration: etisserant@0: STRUCT structure_element_declaration_list END_STRUCT etisserant@0: {$$ = $2;} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | STRUCT END_STRUCT lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no structure element declared in structure type declaration."); yynerrs++;} lbessard@131: | STRUCT error structure_element_declaration_list END_STRUCT lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'STRUCT' in structure type declaration."); yyerrok;} lbessard@136: | STRUCT structure_element_declaration_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed structure type declaration."); yyerrok;} lbessard@131: | STRUCT error END_STRUCT lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in structure type declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for structure_declaration */ etisserant@0: structure_element_declaration_list: etisserant@0: structure_element_declaration ';' mario@68: {$$ = new structure_element_declaration_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | structure_element_declaration_list structure_element_declaration ';' etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@134: | error ';' lbessard@136: {$$ = new structure_element_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid structure element declaration."); yyerrok;} lbessard@131: | structure_element_declaration error lbessard@136: {$$ = new structure_element_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of structure element declaration."); yyerrok;} lbessard@131: | structure_element_declaration_list structure_element_declaration error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of structure element declaration."); yyerrok;} lbessard@133: | structure_element_declaration_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid structure element declaration."); yyerrok;} lbessard@131: | structure_element_declaration_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after structure element declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: structure_element_declaration: etisserant@0: structure_element_name ':' simple_spec_init msousa@1044: {$$ = new structure_element_declaration_c($1, $3, locloc(@$)); $$->token = $1->token;} etisserant@0: | structure_element_name ':' subrange_spec_init msousa@1044: {$$ = new structure_element_declaration_c($1, $3, locloc(@$)); $$->token = $1->token;} etisserant@0: | structure_element_name ':' enumerated_spec_init msousa@1044: {$$ = new structure_element_declaration_c($1, $3, locloc(@$)); $$->token = $1->token;} etisserant@0: | structure_element_name ':' array_spec_init msousa@1044: {$$ = new structure_element_declaration_c($1, $3, locloc(@$)); $$->token = $1->token;} etisserant@0: | structure_element_name ':' initialized_structure msousa@1044: {$$ = new structure_element_declaration_c($1, $3, locloc(@$)); $$->token = $1->token;} mjsousa@932: | structure_element_name ':' ref_spec_init /* non standard extension: Allow use of struct elements storing REF_TO datatypes (either using REF_TO or a previosuly declared ref type) */ mjsousa@932: { $$ = new structure_element_declaration_c($1, $3, locloc(@$)); mjsousa@932: if (!allow_ref_to_in_derived_datatypes) { mjsousa@932: print_err_msg(locf(@$), locl(@$), "REF_TO and reference datatypes may not be used in a STRUCT element (use -R option to activate support for this non-standard syntax)."); mjsousa@932: yynerrs++; mjsousa@932: } mjsousa@932: } lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | structure_element_name simple_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and simple specification."); yynerrs++;} lbessard@131: | structure_element_name subrange_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and subrange specification."); yynerrs++;} lbessard@131: | structure_element_name enumerated_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and enumerated specification."); yynerrs++;} lbessard@131: | structure_element_name array_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and array specification."); yynerrs++;} lbessard@131: | structure_element_name initialized_structure lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and structure specification."); yynerrs++;} lbessard@131: | structure_element_name ':' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in structure element declaration.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid specification in structure element declaration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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;} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | '(' error ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid structure element initialization list in structure initialization."); yyerrok;} lbessard@131: | '(' structure_element_initialization_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "expecting ')' at the end of structure element initialization list in structure initialization."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for structure_initialization */ etisserant@0: structure_element_initialization_list: etisserant@0: structure_element_initialization mario@68: {$$ = new structure_element_initialization_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | structure_element_initialization_list ',' structure_element_initialization etisserant@0: {$$ = $1; $$->add_element($3);} msousa@547: /* ERROR_CHECK_BEGIN */ msousa@547: /* The following error checking rules have been commented out. Why? Was it a typo? msousa@547: * Lets keep them commented out for now... msousa@547: */ msousa@547: /* lbessard@131: | structure_element_initialization_list structure_element_initialization lbessard@136: {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in structure element initialization list in structure initialization."); yynerrs++;} lbessard@131: | structure_element_initialization_list ',' error lbessard@134: {$$ = $1; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no structure element initialization defined in structure initialization.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid structure element initialization in structure initialization."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } msousa@547: */ lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: structure_element_initialization: etisserant@0: structure_element_name ASSIGN constant mario@68: {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} etisserant@0: | structure_element_name ASSIGN enumerated_value mario@68: {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} etisserant@0: | structure_element_name ASSIGN array_initialization mario@68: {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} etisserant@0: | structure_element_name ASSIGN structure_initialization mario@68: {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | structure_element_name constant lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in structure element initialization."); yynerrs++;} lbessard@136: | structure_element_name enumerated_value lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in enumerated structure element initialization."); yynerrs++;} lbessard@136: | structure_element_name array_initialization lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in array structure element initialization."); yynerrs++;} lbessard@136: | structure_element_name structure_initialization lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in structured structure element initialization."); yynerrs++;} lbessard@136: | structure_element_name ASSIGN error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in structured structure element initialization.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid initial value in structured structure element initialization."); yyclearin;} lbessard@136: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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 */ mjsousa@954: /* PRE_PARSING or SINGLE_PHASE_PARSING */ mjsousa@954: /* The following rules will be run either by: mjsousa@954: * - the pre_parsing phase of two phase parsing (when preparsing command line option is chosen). mjsousa@954: * - the standard single phase parser (when preparsing command line option is not chosen). mjsousa@954: */ mjsousa@952: identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init {library_element_symtable.insert($1, prev_declared_string_type_name_token);} mjsousa@954: {if (!get_preparse_state()) $$ = new string_type_declaration_c($1, $3, $4, $5, locloc(@$));} mjsousa@954: /* POST_PARSING */ mjsousa@954: /* These rules will be run after the preparser phase of two phase parsing has finished (only gets to execute if preparsing command line option is chosen). */ mjsousa@952: | prev_declared_string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init mjsousa@954: {$$ = new string_type_declaration_c(new identifier_c(((token_c *)$1)->value, locloc(@1)), $3, $4, $5, locloc(@$));} // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! 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: mjsousa@876: /* Taken fron IEC 61131-3 v3 mjsousa@876: * // Table 14 - Reference operations mjsousa@876: * Ref_Type_Decl : Ref_Type_Name ':' Ref_Spec_Init ; mjsousa@876: * Ref_Spec_Init : Ref_Spec ( ':=' Ref_Value )? ; mjsousa@876: * Ref_Spec : 'REF_TO' Non_Gen_Type_Name ; mjsousa@876: * Ref_Type_Name : Identifier ; mjsousa@876: * Ref_Name : Identifier ; mjsousa@876: * Ref_Value : Ref_Addr | 'NULL' ; mjsousa@876: * Ref_Addr : 'REF' '(' (Symbolic_Variable | FB_Name | Class_Instance_Name ) ')' ; mjsousa@876: * Ref_Assign : Ref_Name ':=' (Ref_Name | Ref_Deref | Ref_Value ) ; mjsousa@876: * Ref_Deref : 'DREF' '(' Ref_Name ')' ; mjsousa@876: */ mjsousa@876: mjsousa@876: /* NOTE: in IEC 61131-3 v3, the formal syntax definition does not define non_generic_type_name to include FB type names. mjsousa@876: * However, in section "6.3.4.10 References", example 4 includes a REF_TO a FB type! mjsousa@876: * We have therefore explicitly added the "REF_TO function_block_type_name" to this rule! mjsousa@923: * NOTE: the REF_TO ANY is a non-standard extension to the standard. This is basically equivalent to a (void *) mjsousa@876: */ mjsousa@932: ref_spec_non_recursive: /* helper symbol, used to remove a reduce/reduce conflict in a non-standard syntax I (Mario) have added!! */ mjsousa@876: REF_TO non_generic_type_name mjsousa@876: {$$ = new ref_spec_c($2, locloc(@$));} mjsousa@876: | REF_TO function_block_type_name mjsousa@876: {$$ = new ref_spec_c($2, locloc(@$));} mjsousa@923: | REF_TO ANY mjsousa@924: {$$ = new ref_spec_c(new generic_type_any_c(locloc(@2)), locloc(@$)); mjsousa@924: if (!allow_ref_to_any) { mjsousa@924: print_err_msg(locf(@$), locl(@$), "REF_TO ANY datatypes are not allowed (use -R option to activate support for this non-standard syntax)."); mjsousa@924: yynerrs++; mjsousa@924: } mjsousa@924: } mjsousa@932: ; mjsousa@932: mjsousa@932: ref_spec: /* defined in IEC 61131-3 v3 */ mjsousa@932: ref_spec_non_recursive mjsousa@932: | prev_declared_ref_type_name mjsousa@932: ; mjsousa@932: mjsousa@932: mjsousa@932: /* The IEC 61131-3 v3 standard actually only defines the following syntax: mjsousa@932: * mjsousa@932: * Ref_Type_Decl: Ref_Type_Name ':' Ref_Spec_Init; mjsousa@932: * Ref_Spec_Init: Ref_Spec ( ':=' Ref_Value )?; mjsousa@932: * Ref_Spec : 'REF_TO' + Data_Type_Access; mjsousa@932: * mjsousa@932: * Note that the above syntax it is not possible to define a REF_TO datatype as mjsousa@932: * an alias to an already previously declared REF_TO datatype. mjsousa@932: * mjsousa@932: * I (Mario) believe that this is probably a bug in the IEC 61131-3 syntax, and I have therefore mjsousa@932: * changed that standard definition to... mjsousa@932: * mjsousa@932: * Ref_Type_Decl: Ref_Type_Name ':' Ref_Spec_Init; mjsousa@932: * Ref_Spec_Init: Ref_Spec ( ':=' Ref_Value )?; mjsousa@932: * Ref_Spec : ('REF_TO' + Data_Type_Access) | Ref_Type_Name; mjsousa@932: * mjsousa@876: * For example: mjsousa@876: * TYPE mjsousa@932: * ref1_t: REF_TO INT; mjsousa@932: * ref2_t: ref1_t; <-- without the above changes, this would not be allowed!! mjsousa@876: * END_TYPE mjsousa@876: * mjsousa@932: * This change also makes it possible to declare variables using a previously declared REF_TO datatype mjsousa@876: * For example: mjsousa@932: * VAR refvar: ref1_t; END_VAR mjsousa@932: * mjsousa@932: * This change also makes it possible to declare arrays containing a previously declared ref type. mjsousa@932: * For example: mjsousa@932: * VAR refvar: ARRAY [1..3] OF ref1_t; END_VAR <--- becomes OK mjsousa@932: * VAR refvar: ARRAY [1..3] OF REF_TO INT; END_VAR <--- still not OK. (Only becomes OK with other non-standard rules in another location of this file!) mjsousa@932: * mjsousa@932: * Interestingly, this change does NOT make it possible to declare structure elements of a previously declared ref type. mjsousa@932: * For example: mjsousa@932: * TYPE struct_t: STRUCT elem1: ref1_t; END_STRUCT; END_TYPE; <--- still not OK. (Only becomes OK with other non-standard rules in another location of this file!) mjsousa@932: * TYPE struct_t: STRUCT elem1: REF_TO INT; END_STRUCT; END_TYPE; <--- still not OK. (Only becomes OK with other non-standard rules in another location of this file!) mjsousa@932: */ mjsousa@932: mjsousa@876: mjsousa@876: mjsousa@876: ref_spec_init: /* defined in IEC 61131-3 v3 */ mjsousa@909: ref_spec mjsousa@909: {$$ = new ref_spec_init_c($1, NULL, locloc(@$));} mjsousa@909: /* For the moment, we do not support initialising reference data types... mjsousa@909: | ref_spec ASSIGN ... mjsousa@909: {$$ = new ref_spec_init_c($1, $3, locloc(@$));} mjsousa@909: */ mjsousa@876: ; mjsousa@876: mjsousa@876: ref_type_decl: /* defined in IEC 61131-3 v3 */ mjsousa@954: /* PRE_PARSING or SINGLE_PHASE_PARSING */ mjsousa@954: /* The following rules will be run either by: mjsousa@954: * - the pre_parsing phase of two phase parsing (when preparsing command line option is chosen). mjsousa@954: * - the standard single phase parser (when preparsing command line option is not chosen). mjsousa@954: */ mjsousa@952: identifier ':' ref_spec_init {library_element_symtable.insert($1, prev_declared_ref_type_name_token);} mjsousa@954: {if (!get_preparse_state()) $$ = new ref_type_decl_c($1, $3, locloc(@$));} mjsousa@954: /* POST_PARSING */ mjsousa@954: /* These rules will be run after the preparser phase of two phase parsing has finished (only gets to execute if preparsing command line option is chosen). */ mjsousa@952: | prev_declared_ref_type_name ':' ref_spec_init mjsousa@954: {$$ = new ref_type_decl_c(new identifier_c(((token_c *)$1)->value, locloc(@1)), $3, locloc(@$));} // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! mjsousa@954: ; mjsousa@876: mjsousa@876: etisserant@0: mjsousa@932: mjsousa@932: mjsousa@932: etisserant@0: /*********************/ etisserant@0: /* B 1.4 - Variables */ etisserant@0: /*********************/ ccb@202: /* NOTE: The standard is erroneous in it's definition of 'variable' because: ccb@202: * - The standard considers 'ENO' as a keyword... msousa@315: * - ...=> which means that it may never be parsed as an 'identifier'... msousa@315: * - ...=> and therefore may never be used as the name of a variable inside an expression. ccb@202: * - However, a function/FB must be able to assign the ENO parameter ccb@202: * it's value, doing it in an assignment statement, and therefore using the 'ENO' ccb@202: * character sequence as an identifier! msousa@315: * The obvious solution is to also allow the ENO keyword to be ccb@202: * used as the name of a variable. Note that this variable may be used ccb@202: * even though it is not explicitly declared as a function/FB variable, ccb@202: * as the standard requires us to define it implicitly in this case! msousa@315: * There are three ways of achieving this: msousa@315: * (i) simply not define EN and ENO as keywords in flex (lexical analyser) msousa@315: * and let them be considered 'identifiers'. Aditionally, add some code msousa@315: * so that if they are not explicitly declared, we add them automatically to msousa@315: * the declaration of each Functions and FB, where they would then be parsed msousa@315: * as a previously_declared_variable. msousa@315: * This approach has the advantage the EN and ENO would automatically be valid msousa@315: * in every location where it needs to be valid, namely in the explicit declaration msousa@315: * of these same variables, or when they are used within expressions. msousa@315: * However, this approach has the drawback that msousa@315: * EN and ENO could then also be used anywhere a standard identifier is allowed, msousa@315: * including in the naming of Functions, FBs, Programs, Configurations, Resources, msousa@315: * SFC Actions, SFC Steps, etc... msousa@315: * This would mean that we would then have to add a lexical analysis check msousa@315: * within the bison code (syntax analyser) to all the above constructs to make sure msousa@315: * that the identifier being used is not EN or ENO. msousa@315: * (ii) The other approach is to define EN and ENO as keywords / tokens in flex msousa@315: * (lexical analyser) and then change the syntax in bison to acomodate msousa@315: * these tokens wherever they could correctly appear. msousa@315: * This has the drawback that we need to do some changes to the synax defintion. msousa@315: * (iii) Yet a another option is to mix the above two methods. msousa@315: * Define EN and ENO as tokens in flex, but change (only) the syntax for msousa@315: * variable declaration to allow these tokens to also be used in declaring variables. msousa@315: * From this point onwards these tokens are then considered a previously_declared_variable, msousa@315: * since flex will first check for this before even checking for tokens. msousa@315: * msousa@315: * I (Mario) cuurretnly (2011) believe the cleanest method of achieving this goal msousa@315: * is to use option (iii) msousa@315: * However, considering that: msousa@315: * - I have already previously implemented option (ii); msousa@315: * - option (iii) requires that flex parse the previously_declared_variable msousa@315: * before parsing any token. We already support this (remeber that this is msousa@315: * used mainly to allow some IL operators as well as PRIORITY, etc. tokens msousa@315: * to be used as identifiers, since the standard does not define them as keywords), msousa@315: * but this part of the code in flex is often commented out as usually people do not expect msousa@315: * us to follow the standard in the strict sense, but rather consider those msousa@315: * tokens as keywords; msousa@315: * considering the above, we currently carry on using option (ii). ccb@202: */ etisserant@0: variable: etisserant@0: symbolic_variable lbessard@175: | prev_declared_direct_variable ccb@202: | eno_identifier msousa@1053: {$$ = new symbolic_variable_c($1, locloc(@$)); $$->token = $1->token;} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: symbolic_variable: mario@68: /* NOTE: To be entirely correct, variable_name must be replacemed by etisserant@0: * prev_declared_variable_name | prev_declared_fb_name | prev_declared_global_var_name etisserant@0: */ mario@78: prev_declared_fb_name msousa@1053: {$$ = new symbolic_variable_c($1, locloc(@$)); $$->token = $1->token;} etisserant@0: | prev_declared_global_var_name msousa@1053: {$$ = new symbolic_variable_c($1, locloc(@$)); $$->token = $1->token;} mario@13: | prev_declared_variable_name msousa@1053: {$$ = new symbolic_variable_c($1, locloc(@$)); $$->token = $1->token;} etisserant@0: | multi_element_variable mario@78: /* mario@78: | identifier msousa@1053: {$$ = new symbolic_variable_c($1, locloc(@$)); $$->token = $1->token;} mario@78: */ mjsousa@933: | symbolic_variable '^' mjsousa@933: /* Dereferencing operator defined in IEC 61131-3 v3. However, implemented here differently then how it is defined in the standard! See following note for explanation! */ mjsousa@936: {$$ = new deref_operator_c($1, locloc(@$)); mjsousa@934: if (!allow_ref_dereferencing) { mjsousa@934: print_err_msg(locf(@$), locl(@$), "Derefencing REF_TO datatypes with '^' is not allowed (use -r option to activate support for this IEC 61131-3 v3 feature)."); mjsousa@934: yynerrs++; mjsousa@934: } mjsousa@934: } mjsousa@933: ; mjsousa@933: /* mjsousa@933: * NOTE: The syntax defined in the v3 standard for the dereferencing operator '^' seems to me to be un-intentionally mjsousa@933: * limited. For example mjsousa@933: * ref_to_bool_var := REF( array_of_bool [1] ); <--- Allowed! mjsousa@933: * ref_to_bool_var := REF( ref_to_array_of_bool^[1] ); <--- Allowed! mjsousa@933: * bool_var := array_of_ref_to_bool[1]^; <--- NOT Allowed! mjsousa@933: * ref_to_array_of_bool^[1] := FALSE; <--- Allowed! mjsousa@933: * I consider this a bug in the v3 standard!! mjsousa@933: * I have therefore opted to implement this by simply adding a rule to symbolic_variable mjsousa@933: * symbolic_variable: mjsousa@933: * ... mjsousa@933: * | symbolic_variable '^' mjsousa@933: * This simple rule should be able to cover all the needed dereferencing syntax! mjsousa@933: * I have also added a dereferencing expression for the DREF() operator. mjsousa@933: * Since both of them do the exact same operation, they will both be translated to the exact same mjsousa@933: * entry type in the abstract syntax tree (an deref_expression_c) mjsousa@933: */ 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 msousa@1053: {$$ = new symbolic_variable_c($1, locloc(@$)); $$->token = $1->token;} 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: /********************************************/ lbessard@175: prev_declared_direct_variable: prev_declared_direct_variable_token {$$ = new direct_variable_c($1, locloc(@$));}; 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 ']' mario@68: {$$ = new array_variable_c($1, $3, locloc(@$));} 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 ']' mario@68: {$$ = new array_variable_c($1, $3, locloc(@$));} 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 mario@68: {$$ = new subscript_list_c(locloc(@$)); $$->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 mario@68: {$$ = new structured_variable_c($1, $3, locloc(@$));} laurent@382: | record_variable '.' il_simple_operator_clash3 msousa@469: {$$ = new structured_variable_c($1, il_operator_c_2_identifier_c($3), locloc(@$));} 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 mario@68: {$$ = new structured_variable_c($1, $3, locloc(@$));} laurent@382: | any_record_variable '.' il_simple_operator_clash3 laurent@382: {$$ = new structured_variable_c($1, $3, locloc(@$));} 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: msousa@315: field_selector: msousa@315: any_identifier msousa@315: | eno_identifier msousa@315: ; 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 ccb@202: {$$ = new input_declarations_c(NULL, $2, new explicit_definition_c(), locloc(@$));} etisserant@0: | VAR_INPUT RETAIN input_declaration_list END_VAR ccb@202: {$$ = new input_declarations_c(new retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} etisserant@0: | VAR_INPUT NON_RETAIN input_declaration_list END_VAR ccb@202: {$$ = new input_declarations_c(new non_retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} mario@95: /* ERROR_CHECK_BEGIN */ lbessard@131: | VAR_INPUT END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in input variable(s) declaration."); yynerrs++;} lbessard@131: | VAR_INPUT RETAIN END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive input variable(s) declaration."); yynerrs++;} lbessard@131: | VAR_INPUT NON_RETAIN END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in non-retentive input variable(s) declaration."); yynerrs++;} lbessard@131: | VAR_INPUT error input_declaration_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_INPUT' in input variable(s) declaration."); yyerrok;} lbessard@131: | VAR_INPUT RETAIN error input_declaration_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive input variable(s) declaration."); yyerrok;} lbessard@131: | VAR_INPUT NON_RETAIN error input_declaration_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive input variable(s) declaration."); yyerrok;} lbessard@136: | VAR_INPUT input_declaration_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed input variable(s) declaration."); yyerrok;} lbessard@136: | VAR_INPUT RETAIN input_declaration_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive input variable(s) declaration."); yyerrok;} lbessard@136: | VAR_INPUT NON_RETAIN input_declaration_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed non-retentive input variable(s) declaration."); yyerrok;} mario@95: | VAR_INPUT error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in input variable(s) declaration."); yyerrok;} lbessard@131: | VAR_INPUT RETAIN error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in retentive input variable(s) declaration."); yyerrok;} lbessard@131: | VAR_INPUT NON_RETAIN error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in non-retentive input variable(s) declaration."); yyerrok;} mario@95: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for input_declarations */ etisserant@0: input_declaration_list: etisserant@0: input_declaration ';' mario@68: {$$ = new input_declaration_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | input_declaration_list input_declaration ';' etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@134: | error ';' lbessard@136: {$$ = new input_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid input variable(s) declaration."); yyerrok;} lbessard@131: | input_declaration error lbessard@136: {$$ = new input_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of input variable(s) declaration."); yyerrok;} lbessard@131: | input_declaration_list input_declaration error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of input variable(s) declaration."); yyerrok;} lbessard@133: | input_declaration_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid input variable(s) declaration."); yyerrok;} lbessard@131: | input_declaration_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after input variable(s) declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: ccb@202: /* NOTE: The formal definition of 'input_declaration' as defined in the standard is erroneous, ccb@202: * as it does not allow a user defined 'EN' input parameter. However, ccb@202: * The semantic description of the languages clearly states that this is allowed. ccb@202: * We have added the 'en_param_declaration' clause to cover for this. ccb@202: */ etisserant@0: input_declaration: etisserant@0: var_init_decl etisserant@0: | edge_declaration lbessard@146: | en_param_declaration etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: edge_declaration: etisserant@0: var1_list ':' BOOL R_EDGE mario@68: {$$ = new edge_declaration_c(new raising_edge_option_c(locloc(@3)), $1, locloc(@$));} etisserant@0: | var1_list ':' BOOL F_EDGE mario@68: {$$ = new edge_declaration_c(new falling_edge_option_c(locloc(@3)), $1, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | var1_list BOOL R_EDGE lbessard@146: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in edge declaration."); yynerrs++;} lbessard@131: | var1_list BOOL F_EDGE lbessard@146: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in edge declaration."); yynerrs++;} lbessard@131: | var1_list ':' BOOL R_EDGE F_EDGE ccb@202: {$$ = NULL; print_err_msg(locl(@5), locf(@5), "'R_EDGE' and 'F_EDGE' can't be present at the same time in edge declaration."); yynerrs++;} ccb@202: | var1_list ':' BOOL F_EDGE R_EDGE ccb@202: {$$ = NULL; print_err_msg(locl(@5), locf(@5), "'R_EDGE' and 'F_EDGE' can't be present at the same time in edge declaration."); yynerrs++;} lbessard@131: | var1_list ':' R_EDGE lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in edge declaration."); yynerrs++;} lbessard@131: | var1_list ':' F_EDGE lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in edge declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: ccb@202: ccb@202: /* NOTE: The formal definition of the standard is erroneous, as it simply does not ccb@202: * consider the EN and ENO keywords! ccb@202: * The semantic description of the languages clearly states that these may be ccb@202: * used in several ways. One of them is to declare an EN input parameter. ccb@202: * We have added the 'en_param_declaration' clause to cover for this. msousa@315: * msousa@315: * Please read the comment above the definition of 'variable' in section B1.4 for details. ccb@202: */ lbessard@146: en_param_declaration: ccb@202: en_identifier ':' BOOL ASSIGN boolean_literal msousa@805: {$$ = new en_param_declaration_c($1, new simple_spec_init_c(new bool_type_name_c(locloc(@3)), $5, locf(@3), locl(@5)), new explicit_definition_c(), locloc(@$));} ccb@202: | en_identifier ':' BOOL ASSIGN integer msousa@805: {$$ = new en_param_declaration_c($1, new simple_spec_init_c(new bool_type_name_c(locloc(@3)), $5, locf(@3), locl(@5)), new explicit_definition_c(), locloc(@$));} ccb@202: /* ERROR_CHECK_BEGIN */ ccb@202: | en_identifier BOOL ASSIGN boolean_literal lbessard@146: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in EN declaration."); yynerrs++;} ccb@202: | en_identifier BOOL ASSIGN integer lbessard@146: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in EN declaration."); yynerrs++;} ccb@202: | en_identifier ':' ASSIGN boolean_literal lbessard@146: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in EN declaration."); yynerrs++;} ccb@202: | en_identifier ':' ASSIGN integer lbessard@146: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in EN declaration."); yynerrs++;} ccb@202: | en_identifier ':' BOOL ASSIGN error lbessard@146: {$$ = NULL; lbessard@146: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in EN declaration.");} lbessard@146: else {print_err_msg(locf(@3), locl(@3), "invalid specification in EN declaration."); yyclearin;} lbessard@146: yyerrok; lbessard@146: } lbessard@146: /* ERROR_CHECK_END */ lbessard@146: ; 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 mario@68: {$$ = new var1_init_decl_c($1, $3, locloc(@$));} etisserant@0: | var1_list ':' subrange_spec_init mario@68: {$$ = new var1_init_decl_c($1, $3, locloc(@$));} etisserant@0: | var1_list ':' enumerated_spec_init mario@68: {$$ = new var1_init_decl_c($1, $3, locloc(@$));} mjsousa@876: | var1_list ':' ref_spec_init /* defined in IEC 61131-3 v3 (REF_TO ...)*/ mjsousa@876: {$$ = new var1_init_decl_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | var1_list simple_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and simple specification."); yynerrs++;} lbessard@131: | var1_list subrange_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and subrange specification."); yynerrs++;} lbessard@131: | var1_list enumerated_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and enumerated specification."); yynerrs++;} lbessard@131: | var1_list ':' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in variable declaration.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid specification in variable declaration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: msousa@350: /* NOTE: msousa@350: * The syntax msousa@350: * variable_name DOTDOT msousa@350: * is an extension to the standard!!! msousa@350: * msousa@350: * In order to be able to handle extensible standard functions msousa@350: * (i.e. standard functions that may have a variable number of msousa@350: * input parameters, such as AND(word#33, word#44, word#55, word#66), msousa@350: * we have extended the acceptable syntax to allow var_name '..' msousa@350: * in an input variable declaration. msousa@350: * msousa@350: * This allows us to parse the declaration of standard msousa@350: * extensible functions and load their interface definition msousa@350: * into the abstract syntax tree just like we do to other msousa@350: * user defined functions. msousa@350: * This has the advantage that we can later do semantic msousa@350: * checking of calls to functions (be it a standard or user defined msousa@350: * function) in (almost) exactly the same way. msousa@350: * msousa@350: * Of course, we have a flag that disables this syntax when parsing user msousa@350: * written code, so we only allow this extra syntax while parsing the msousa@350: * 'header' file that declares all the standard IEC 61131-3 functions. msousa@350: */ etisserant@0: var1_list: etisserant@0: variable_name mario@68: {$$ = new var1_list_c(locloc(@$)); $$->add_element($1); etisserant@0: variable_name_symtable.insert($1, prev_declared_variable_name_token); etisserant@0: } msousa@350: | variable_name integer DOTDOT msousa@350: {$$ = new var1_list_c(locloc(@$)); $$->add_element(new extensible_input_parameter_c($1, $2, locloc(@$))); msousa@350: variable_name_symtable.insert($1, prev_declared_variable_name_token); msousa@350: if (!allow_extensible_function_parameters) print_err_msg(locf(@1), locl(@2), "invalid syntax in variable name declaration."); msousa@350: } 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: } msousa@350: | var1_list ',' variable_name integer DOTDOT msousa@350: {$$ = $1; $$->add_element(new extensible_input_parameter_c($3, $4, locloc(@$))); msousa@350: variable_name_symtable.insert($3, prev_declared_variable_name_token); msousa@350: if (!allow_extensible_function_parameters) print_err_msg(locf(@1), locl(@2), "invalid syntax in variable name declaration."); msousa@350: } lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | var1_list variable_name lbessard@136: {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in variable list."); yynerrs++;} lbessard@131: | var1_list ',' error lbessard@134: {$$ = $1; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no variable name defined in variable declaration.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid variable name in variable declaration."); yyclearin;} lbessard@134: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: array_var_init_decl: etisserant@0: var1_list ':' array_spec_init mario@68: {$$ = new array_var_init_decl_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | var1_list array_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and array specification."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: structured_var_init_decl: etisserant@0: var1_list ':' initialized_structure mario@68: {$$ = new structured_var_init_decl_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | var1_list initialized_structure lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and structured specification."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ 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 msousa@810: {$$ = new fb_name_decl_c($1, new fb_spec_init_c($2, NULL,locloc(@2)), locloc(@$));} 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 msousa@810: {$$ = new fb_name_decl_c($1, new fb_spec_init_c($2, $4, locf(@2), locl(@4)), locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | fb_name_list_with_colon ASSIGN structure_initialization lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block type name defined in function block declaration with initialization."); yynerrs++;} lbessard@131: | fb_name_list_with_colon function_block_type_name structure_initialization lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':=' missing in function block declaration with initialization."); yynerrs++;} lbessard@131: | fb_name_list_with_colon function_block_type_name ASSIGN error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no initialization defined in function block declaration.");} lbessard@136: else {print_err_msg(locf(@4), locl(@4), "invalid initialization in function block declaration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new fb_name_list_c(locloc(@$)); 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: lbessard@146: VAR_OUTPUT var_output_init_decl_list END_VAR ccb@202: {$$ = new output_declarations_c(NULL, $2, new explicit_definition_c(), locloc(@$));} lbessard@146: | VAR_OUTPUT RETAIN var_output_init_decl_list END_VAR ccb@202: {$$ = new output_declarations_c(new retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} lbessard@146: | VAR_OUTPUT NON_RETAIN var_output_init_decl_list END_VAR ccb@202: {$$ = new output_declarations_c(new non_retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} mario@96: /* ERROR_CHECK_BEGIN */ lbessard@131: | VAR_OUTPUT END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in output variable(s) declaration."); yynerrs++;} lbessard@131: | VAR_OUTPUT RETAIN END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive output variable(s) declaration."); yynerrs++;} lbessard@131: | VAR_OUTPUT NON_RETAIN END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in non-retentive output variable(s) declaration."); yynerrs++;} lbessard@146: | VAR_OUTPUT error var_output_init_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_OUPUT' in output variable(s) declaration."); yyerrok;} lbessard@146: | VAR_OUTPUT RETAIN error var_output_init_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive output variable(s) declaration."); yyerrok;} lbessard@146: | VAR_OUTPUT NON_RETAIN error var_output_init_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive output variable(s) declaration."); yyerrok;} lbessard@146: | VAR_OUTPUT var_output_init_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed output variable(s) declaration."); yyerrok;} lbessard@146: | VAR_OUTPUT RETAIN var_output_init_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive output variable(s) declaration."); yyerrok;} lbessard@146: | VAR_OUTPUT NON_RETAIN var_output_init_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed non-retentive output variable(s) declaration."); yyerrok;} mario@96: | VAR_OUTPUT error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in output variable(s) declaration."); yyerrok;} lbessard@131: | VAR_OUTPUT RETAIN error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in retentive output variable(s) declaration."); yyerrok;} lbessard@131: | VAR_OUTPUT NON_RETAIN error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in non-retentive output variable(s) declaration."); yyerrok;} mario@96: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: ccb@202: ccb@202: /* NOTE: The formal definition of 'var_output_init_decl' as defined in the standard is erroneous, ccb@202: * as it does not allow a user defined 'ENO' output parameter. However, ccb@202: * The semantic description of the languages clearly states that this is allowed. ccb@202: * We have added the 'eno_param_declaration' clause to cover for this. msousa@315: * msousa@315: * Please read the comment above the definition of 'variable' in section B1.4 for details. ccb@202: */ lbessard@146: var_output_init_decl: lbessard@146: var_init_decl lbessard@146: | eno_param_declaration lbessard@146: ; lbessard@146: lbessard@146: var_output_init_decl_list: lbessard@146: var_output_init_decl ';' lbessard@146: {$$ = new var_init_decl_list_c(locloc(@$)); $$->add_element($1);} lbessard@146: | var_output_init_decl_list var_output_init_decl ';' lbessard@146: {$$ = $1; $$->add_element($2);} lbessard@146: /* ERROR_CHECK_BEGIN */ lbessard@146: | var_output_init_decl_list var_output_init_decl error lbessard@146: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of variable(s) declaration."); yyerrok;} lbessard@146: | var_output_init_decl_list error ';' lbessard@146: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid variable(s) declaration."); yyerrok;} lbessard@146: /* ERROR_CHECK_END */ lbessard@146: ; lbessard@146: ccb@202: ccb@202: /* NOTE: The formal definition of the standard is erroneous, as it simply does not ccb@202: * consider the EN and ENO keywords! ccb@202: * The semantic description of the languages clearly states that these may be ccb@202: * used in several ways. One of them is to declare an ENO output parameter. ccb@202: * We have added the 'eno_param_declaration' clause to cover for this. msousa@315: * msousa@315: * Please read the comment above the definition of 'variable' in section B1.4 for details. ccb@202: */ lbessard@146: eno_param_declaration: ccb@202: eno_identifier ':' BOOL ccb@202: /* NOTE We do _NOT_ include this variable in the previously_declared_variable symbol table! ccb@202: * Please read the comment above the definition of 'variable' for the reason for this. ccb@202: */ ccb@202: {$$ = new eno_param_declaration_c($1, new bool_type_name_c(locloc(@$)), new explicit_definition_c(), locloc(@$));} ccb@202: /* ERROR_CHECK_BEGIN */ laurent@207: | eno_identifier BOOL ccb@202: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in ENO declaration."); yynerrs++;} laurent@207: | eno_identifier ':' error lbessard@146: {$$ = NULL; lbessard@146: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in ENO declaration.");} lbessard@146: else {print_err_msg(locf(@3), locl(@3), "invalid specification in ENO declaration."); yyclearin;} lbessard@146: yyerrok; lbessard@146: } lbessard@146: /* ERROR_CHECK_END */ lbessard@146: ; etisserant@0: etisserant@0: etisserant@0: input_output_declarations: etisserant@0: VAR_IN_OUT var_declaration_list END_VAR mario@68: {$$ = new input_output_declarations_c($2, locloc(@$));} mario@96: /* ERROR_CHECK_BEGIN */ lbessard@131: | VAR_IN_OUT END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in in_out variable(s) declaration."); yynerrs++;} lbessard@136: | VAR_IN_OUT error var_declaration_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_IN_OUT' in in_out variable(s) declaration."); yyerrok;} lbessard@136: | VAR_IN_OUT var_declaration_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed in_out variable(s) declaration."); yyerrok;} mario@96: | VAR_IN_OUT error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in in_out variable(s) declaration."); yyerrok;} mario@96: /* ERROR_CHECK_END */ 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 ';' mario@68: {$$ = new var_declaration_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | var_declaration_list var_declaration ';' etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@134: | error ';' lbessard@136: {$$ = new var_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid variable(s) declaration."); yyerrok;} lbessard@131: | var_declaration error lbessard@136: {$$ = new var_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of variable(s) declaration."); yyerrok;} lbessard@131: | var_declaration_list var_declaration error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of variable(s) declaration."); yyerrok;} lbessard@133: | var_declaration_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid variable(s) declaration."); yyerrok;} lbessard@131: | var_declaration_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after variable(s) declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ 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: lbessard@134: var1_list ':' simple_specification mario@68: {$$ = new var1_init_decl_c($1, $3, locloc(@$));} lbessard@134: | var1_list ':' subrange_specification mario@68: {$$ = new var1_init_decl_c($1, $3, locloc(@$));} lbessard@134: | var1_list ':' enumerated_specification mario@68: {$$ = new var1_init_decl_c($1, $3, locloc(@$));} mjsousa@876: | var1_list ':' ref_spec /* defined in IEC 61131-3 v3 (REF_TO ...)*/ mjsousa@876: {$$ = new var1_init_decl_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | var1_list simple_specification lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and simple specification."); yynerrs++;} lbessard@131: | var1_list subrange_specification lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and subrange specification."); yynerrs++;} lbessard@131: | var1_list enumerated_specification lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and enumerated specification."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: array_var_declaration: etisserant@0: var1_list ':' array_specification mario@68: {$$ = new array_var_declaration_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | var1_list array_specification lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and array specification."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: structured_var_declaration: etisserant@0: var1_list ':' prev_declared_structure_type_name mario@68: {$$ = new structured_var_declaration_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | var1_list prev_declared_structure_type_name lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and structured specification."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: var_declarations: etisserant@0: VAR var_init_decl_list END_VAR mario@68: {$$ = new var_declarations_c(NULL, $2, locloc(@$));} etisserant@0: | VAR CONSTANT var_init_decl_list END_VAR mario@68: {$$ = new var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | VAR END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in variable(s) declaration."); yynerrs++;} lbessard@131: | VAR CONSTANT END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in constant variable(s) declaration."); yynerrs++;} lbessard@131: | VAR error var_init_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@3), "unexpected token after 'VAR' in variable(s) declaration."); yyerrok;} lbessard@131: | VAR CONSTANT error var_init_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant variable(s) declaration."); yyerrok;} lbessard@136: | VAR var_init_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed variable(s) declaration."); yyerrok;} lbessard@136: | VAR CONSTANT var_init_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant variable(s) declaration."); yyerrok;} lbessard@131: | VAR error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in variable(s) declaration."); yyerrok;} lbessard@131: | VAR CONSTANT error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant variable(s) declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: retentive_var_declarations: etisserant@0: VAR RETAIN var_init_decl_list END_VAR mario@68: {$$ = new retentive_var_declarations_c($3, locloc(@$));} mario@96: /* ERROR_CHECK_BEGIN */ lbessard@131: | VAR RETAIN END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive variable(s) declaration."); yynerrs++;} lbessard@131: | VAR RETAIN error var_init_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive variable(s) declaration."); yyerrok;} lbessard@136: | VAR RETAIN var_init_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive variable(s) declaration."); yyerrok;} mario@96: | VAR RETAIN error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in retentive variable(s) declaration."); yyerrok;} mario@96: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: located_var_declarations: lbessard@131: VAR located_var_decl_list END_VAR mario@68: {$$ = new located_var_declarations_c(NULL, $2, locloc(@$));} etisserant@0: | VAR CONSTANT located_var_decl_list END_VAR mario@68: {$$ = new located_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} etisserant@0: | VAR RETAIN located_var_decl_list END_VAR mario@68: {$$ = new located_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));} etisserant@0: | VAR NON_RETAIN located_var_decl_list END_VAR mario@68: {$$ = new located_var_declarations_c(new non_retain_option_c(locloc(@2)), $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | VAR NON_RETAIN END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in non-retentive located variable(s) declaration."); yynerrs++;} lbessard@131: | VAR error located_var_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR' in located variable(s) declaration."); yyerrok;} lbessard@131: | VAR CONSTANT error located_var_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant located variable(s) declaration."); yyerrok;} lbessard@131: | VAR RETAIN error located_var_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive located variable(s) declaration."); yyerrok;} lbessard@131: | VAR NON_RETAIN error located_var_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive located variable(s) declaration."); yyerrok;} lbessard@136: | VAR located_var_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed located variable(s) declaration."); yyerrok;} lbessard@136: | VAR CONSTANT located_var_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant located variable(s) declaration."); yyerrok;} lbessard@136: | VAR RETAIN located_var_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive located variable(s) declaration."); yyerrok;} lbessard@136: | VAR NON_RETAIN located_var_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed non-retentive located variable(s) declaration."); yyerrok;} lbessard@131: | VAR NON_RETAIN error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in non retentive variable(s) declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ 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 ';' mario@68: {$$ = new located_var_decl_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | located_var_decl_list located_var_decl ';' etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@134: | error ';' lbessard@136: {$$ = new located_var_decl_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid located variable declaration."); yyerrok;} lbessard@131: | located_var_decl error lbessard@136: {$$ = new located_var_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of located variable declaration."); yyerrok;} lbessard@131: | located_var_decl_list located_var_decl error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of located variable declaration."); yyerrok;} lbessard@133: | located_var_decl_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid located variable declaration."); yyerrok;} lbessard@131: | located_var_decl_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after located variable declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: located_var_decl: etisserant@0: variable_name location ':' located_var_spec_init mario@68: {$$ = new located_var_decl_c($1, $2, $4, locloc(@$)); etisserant@0: variable_name_symtable.insert($1, prev_declared_variable_name_token); etisserant@0: } etisserant@0: | location ':' located_var_spec_init mario@68: {$$ = new located_var_decl_c(NULL, $1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | variable_name location located_var_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between located variable location and specification."); yynerrs++;} lbessard@131: | location located_var_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between located variable location and specification."); yynerrs++;} lbessard@131: | variable_name location ':' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in located variable declaration.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid specification in located variable declaration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | location ':' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in located variable declaration.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid specification in located variable declaration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: external_var_declarations: etisserant@0: VAR_EXTERNAL external_declaration_list END_VAR mario@68: {$$ = new external_var_declarations_c(NULL, $2, locloc(@$));} etisserant@0: | VAR_EXTERNAL CONSTANT external_declaration_list END_VAR mario@68: {$$ = new external_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} mario@96: /* ERROR_CHECK_BEGIN */ lbessard@131: | VAR_EXTERNAL END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in external variable(s) declaration."); yynerrs++;} lbessard@131: | VAR_EXTERNAL CONSTANT END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in constant external variable(s) declaration."); yynerrs++;} lbessard@131: | VAR_EXTERNAL error external_declaration_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_EXTERNAL' in external variable(s) declaration."); yyerrok;} lbessard@131: | VAR_EXTERNAL CONSTANT error external_declaration_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant external variable(s) declaration."); yyerrok;} lbessard@136: | VAR_EXTERNAL external_declaration_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed external variable(s) declaration."); yyerrok;} lbessard@136: | VAR_EXTERNAL CONSTANT external_declaration_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant external variable(s) declaration."); yyerrok;} mario@96: | VAR_EXTERNAL error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in external variable(s) declaration."); yyerrok;} lbessard@131: | VAR_EXTERNAL CONSTANT error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant external variable(s) declaration."); yyerrok;} mario@96: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for external_var_declarations */ etisserant@0: external_declaration_list: etisserant@0: external_declaration ';' mario@68: {$$ = new external_declaration_list_c(locloc(@$)); $$->add_element($1);} lbessard@131: | external_declaration_list external_declaration ';' etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@134: | error ';' lbessard@136: {$$ = new external_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid external variable declaration."); yyerrok;} lbessard@131: | external_declaration error lbessard@136: {$$ = new external_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of external variable declaration."); yyerrok;} lbessard@131: | external_declaration_list external_declaration error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of external variable declaration."); yyerrok;} lbessard@133: | external_declaration_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid external variable declaration."); yyerrok;} lbessard@131: | external_declaration_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after external variable declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: mjsousa@963: mjsousa@963: /* Warning: When handling VAR_EXTERNAL declarations, the constant folding algorithm may (depending on the command line parameters) mjsousa@963: * set the symbol_c->const_value annotations on both the external_var_name as well as on its VAR_EXTERNAL datatype specification symbol. mjsousa@963: * Setting the const_value on the datatype specification symbol of a VAR_EXTERNAL declaration is only possible if the declaration of mjsousa@963: * several external variables in a list is not allowed (as each variable could have a potentially distinct initial value). mjsousa@963: * VAR_EXTERNAL mjsousa@963: * a, b, c, d: INT; (* incorrect syntax! *) mjsousa@963: * END_VAR mjsousa@963: * mjsousa@963: * If anybody considers extending this standard syntax to allow the above syntax (several variables in a list), then be sure to go mjsousa@963: * and fix the constant folding algorithm (more precisely, the constant_folding_c::handle_var_extern_global_pair() function. mjsousa@963: */ etisserant@0: external_declaration: etisserant@0: global_var_name ':' simple_specification mario@68: {$$ = new external_declaration_c($1, $3, locloc(@$)); etisserant@0: variable_name_symtable.insert($1, prev_declared_variable_name_token); etisserant@0: } etisserant@0: | global_var_name ':' subrange_specification mario@68: {$$ = new external_declaration_c($1, $3, locloc(@$)); etisserant@0: variable_name_symtable.insert($1, prev_declared_variable_name_token); etisserant@0: } etisserant@0: | global_var_name ':' enumerated_specification mario@68: {$$ = new external_declaration_c($1, $3, locloc(@$)); etisserant@0: variable_name_symtable.insert($1, prev_declared_variable_name_token); etisserant@0: } etisserant@0: | global_var_name ':' array_specification mario@68: {$$ = new external_declaration_c($1, $3, locloc(@$)); etisserant@0: variable_name_symtable.insert($1, prev_declared_variable_name_token); etisserant@0: } etisserant@0: | global_var_name ':' prev_declared_structure_type_name mario@68: {$$ = new external_declaration_c($1, $3, locloc(@$)); etisserant@0: variable_name_symtable.insert($1, prev_declared_variable_name_token); etisserant@0: } etisserant@0: | global_var_name ':' function_block_type_name msousa@810: {$$ = new external_declaration_c($1, new fb_spec_init_c($3, NULL, locloc(@3)), locloc(@$)); etisserant@0: variable_name_symtable.insert($1, prev_declared_fb_name_token); etisserant@0: } mjsousa@876: | global_var_name ':' ref_spec /* defined in IEC 61131-3 v3 (REF_TO ...)*/ mjsousa@891: {$$ = new external_declaration_c($1, $3, locloc(@$)); mjsousa@876: variable_name_symtable.insert($1, prev_declared_fb_name_token); mjsousa@876: } lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | global_var_name simple_specification lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and simple specification."); yynerrs++;} lbessard@131: | global_var_name subrange_specification lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and subrange specification."); yynerrs++;} lbessard@131: | global_var_name enumerated_specification lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and enumerated specification."); yynerrs++;} lbessard@131: | global_var_name array_specification lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and array specification."); yynerrs++;} lbessard@131: | global_var_name prev_declared_structure_type_name lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and structured specification."); yynerrs++;} lbessard@131: | global_var_name function_block_type_name lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and function block type specification."); yynerrs++;} lbessard@131: | global_var_name ':' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in external variable declaration.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid specification in external variable declaration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new global_var_declarations_c(NULL, $2, locloc(@$));} etisserant@0: | VAR_GLOBAL CONSTANT global_var_decl_list END_VAR mario@68: {$$ = new global_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} etisserant@0: | VAR_GLOBAL RETAIN global_var_decl_list END_VAR mario@68: {$$ = new global_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));} mario@96: /* ERROR_CHECK_BEGIN */ lbessard@131: | VAR_GLOBAL END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in global variable(s) declaration."); yynerrs++;} lbessard@131: | VAR_GLOBAL CONSTANT END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in constant global variable(s) declaration."); yynerrs++;} lbessard@131: | VAR_GLOBAL RETAIN END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive global variable(s) declaration."); yynerrs++;} lbessard@131: | VAR_GLOBAL error global_var_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_GLOBAL' in global variable(s) declaration."); yyerrok;} lbessard@131: | VAR_GLOBAL CONSTANT error global_var_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant global variable(s) declaration."); yyerrok;} lbessard@131: | VAR_GLOBAL RETAIN error global_var_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive global variable(s) declaration."); yyerrok;} lbessard@136: | VAR_GLOBAL global_var_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed global variable(s) declaration."); yyerrok;} lbessard@136: | VAR_GLOBAL CONSTANT global_var_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant global variable(s) declaration."); yyerrok;} lbessard@136: | VAR_GLOBAL RETAIN global_var_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive global variable(s) declaration."); yyerrok;} mario@96: | VAR_GLOBAL error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in global variable(s) declaration."); yyerrok;} lbessard@131: | VAR_GLOBAL CONSTANT error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant global variable(s) declaration."); yyerrok;} lbessard@131: | VAR_GLOBAL RETAIN error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant global variable(s) declaration."); yyerrok;} mario@96: /* ERROR_CHECK_END */ 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 ';' mario@68: {$$ = new global_var_decl_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | global_var_decl_list global_var_decl ';' etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@134: | error ';' lbessard@136: {$$ = new global_var_decl_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid global variable(s) declaration."); yyerrok;} lbessard@131: | global_var_decl error lbessard@136: {$$ = new global_var_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of global variable(s) declaration."); yyerrok;} lbessard@131: | global_var_decl_list global_var_decl error lbessard@136: {$$ = $1; print_err_msg(locl(@1), locf(@2), "';' missing at end of global variable(s) declaration."); yyerrok;} lbessard@133: | global_var_decl_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid global variable(s) declaration."); yyerrok;} lbessard@131: | global_var_decl_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after global variable(s) declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: global_var_decl: lbessard@131: /* NOTE : This possibility defined in standard has no sense and generate a conflict (disabled) etisserant@0: global_var_spec ':' mario@68: {$$ = new global_var_decl_c($1, NULL, locloc(@$));} lbessard@131: */ lbessard@131: global_var_spec ':' located_var_spec_init mario@68: {$$ = new global_var_decl_c($1, $3, locloc(@$));} etisserant@0: | global_var_spec ':' function_block_type_name msousa@810: {$$ = new global_var_decl_c($1, new fb_spec_init_c($3, NULL, locloc(@3)), locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | global_var_list located_var_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between global variable list and type specification."); yynerrs++;} lbessard@131: | global_var_name location located_var_spec_init lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between global variable specification and type specification."); yynerrs++;} lbessard@131: | global_var_spec function_block_type_name lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between global variable specification and function block type specification."); yynerrs++;} lbessard@131: | global_var_spec ':' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in global variable declaration.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid specification in global variable declaration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: global_var_spec: etisserant@0: global_var_list {$$ = $1;} etisserant@0: | location mario@68: {$$ = new global_var_spec_c(NULL, $1, locloc(@$));} etisserant@0: | global_var_name location mario@68: {$$ = new global_var_spec_c($1, $2, locloc(@$)); etisserant@0: variable_name_symtable.insert($1, prev_declared_global_var_name_token); 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 mjsousa@876: | ref_spec_init /* defined in IEC 61131-3 v3 (REF_TO ...) */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: location: lbessard@175: AT direct_variable_token lbessard@175: {$$ = new location_c(new direct_variable_c($2, locloc(@$)), locloc(@$)); lbessard@175: direct_variable_symtable.insert($2, prev_declared_direct_variable_token); lbessard@175: } lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | AT error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no location defined in location declaration.");} lbessard@136: else {print_err_msg(locf(@2), locl(@2), "invalid location in global location declaration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: global_var_list: etisserant@0: global_var_name mario@68: {$$ = new global_var_list_c(locloc(@$)); $$->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: } lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | global_var_list global_var_name lbessard@136: {$$ = new global_var_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "',' missing in global variable list."); yynerrs++;} lbessard@131: | global_var_list ',' error lbessard@134: {$$ = $1; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no variable name defined in global variable declaration.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid variable name in global variable declaration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new single_byte_string_var_declaration_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | var1_list single_byte_string_spec lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and string type specification."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ 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 ']' msousa@350: {$$ = new single_byte_string_spec_c(new single_byte_limited_len_string_spec_c(new string_type_name_c(locloc(@1)), $3, locloc(@$)), NULL, locloc(@$));} etisserant@0: /* etisserant@0: | STRING ASSIGN single_byte_character_string msousa@350: {$$ = new single_byte_string_spec_c($1, NULL, $3, locloc(@$));} etisserant@0: */ etisserant@0: | STRING '[' integer ']' ASSIGN single_byte_character_string msousa@350: {$$ = new single_byte_string_spec_c(new single_byte_limited_len_string_spec_c(new string_type_name_c(locloc(@1)), $3, locloc(@$)), $6, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | STRING '[' error ']' lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited string type specification."); yyerrok;} lbessard@131: | STRING '[' error ']' ASSIGN single_byte_character_string lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited string type specification."); yyerrok;} lbessard@131: | STRING '[' ']' lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited string type specification."); yynerrs++;} lbessard@131: | STRING '[' ']' ASSIGN single_byte_character_string lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited string type specification."); yynerrs++;} lbessard@131: | STRING '[' integer error lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "expecting ']' after length definition for limited string type specification."); yyerrok;} lbessard@131: | STRING '[' integer ']' single_byte_character_string lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':=' missing before limited string type initialization."); yynerrs++;} lbessard@131: | STRING '[' integer ']' ASSIGN error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@5), locf(@6), "no initial value defined in limited string type initialization.");} lbessard@136: else {print_err_msg(locf(@6), locl(@6), "invalid initial value in limited string type initialization."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: double_byte_string_var_declaration: etisserant@0: var1_list ':' double_byte_string_spec mario@68: {$$ = new double_byte_string_var_declaration_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | var1_list double_byte_string_spec lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and double byte string type specification."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: double_byte_string_spec: etisserant@0: /* WSTRING msousa@350: {$$ = new double_byte_string_spec_c($1, NULL, NULL, locloc(@$));} etisserant@0: */ etisserant@0: WSTRING '[' integer ']' msousa@350: {$$ = new double_byte_string_spec_c(new double_byte_limited_len_string_spec_c(new wstring_type_name_c(locloc(@1)), $3, locloc(@$)), NULL, locloc(@$));} msousa@350: etisserant@0: /* etisserant@0: | WSTRING ASSIGN double_byte_character_string msousa@350: {$$ = new double_byte_string_spec_c($1, NULL, $3, locloc(@$));} etisserant@0: */ etisserant@0: | WSTRING '[' integer ']' ASSIGN double_byte_character_string msousa@350: {$$ = new double_byte_string_spec_c(new double_byte_limited_len_string_spec_c(new wstring_type_name_c(locloc(@1)), $3, locloc(@$)), $6, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | WSTRING '[' error ']' lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited double byte string type specification."); yyerrok;} lbessard@131: | WSTRING '[' error ']' ASSIGN single_byte_character_string lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited double byte string type specification."); yyerrok;} lbessard@131: | WSTRING '[' ']' lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited double byte string type specification."); yynerrs++;} lbessard@131: | WSTRING '[' ']' ASSIGN single_byte_character_string lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited double byte string type specification."); yynerrs++;} lbessard@131: | WSTRING '[' integer error lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "expecting ']' after length definition for limited double byte string type specification."); yyerrok;} lbessard@131: | WSTRING '[' integer ']' single_byte_character_string lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':=' missing before limited double byte string type initialization."); yynerrs++;} lbessard@131: | WSTRING '[' integer ']' ASSIGN error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@5), locf(@6), "no initial value defined double byte in limited string type initialization.");} lbessard@136: else {print_err_msg(locf(@6), locl(@6), "invalid initial value in limited double byte string type initialization."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: incompl_located_var_declarations: etisserant@0: VAR incompl_located_var_decl_list END_VAR mario@68: {$$ = new incompl_located_var_declarations_c(NULL, $2, locloc(@$));} etisserant@0: | VAR RETAIN incompl_located_var_decl_list END_VAR mario@68: {$$ = new incompl_located_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));} etisserant@0: | VAR NON_RETAIN incompl_located_var_decl_list END_VAR mario@68: {$$ = new incompl_located_var_declarations_c(new non_retain_option_c(locloc(@2)), $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@136: | VAR incompl_located_var_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed incomplete located variable(s) declaration."); yyerrok;} lbessard@136: | VAR RETAIN incompl_located_var_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed incomplete retentive located variable(s) declaration."); yyerrok;} lbessard@136: | VAR NON_RETAIN incompl_located_var_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed incomplete non-retentive located variable(s) declaration."); yyerrok;} lbessard@131: | VAR error incompl_located_var_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR' in incomplete located variable(s) declaration."); yyerrok;} lbessard@131: | VAR RETAIN error incompl_located_var_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive located variable(s) declaration."); yyerrok;} lbessard@131: | VAR NON_RETAIN error incompl_located_var_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive located variable(s) declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ 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 ';' mario@68: {$$ = new incompl_located_var_decl_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | incompl_located_var_decl_list incompl_located_var_decl ';' etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | incompl_located_var_decl error lbessard@136: {$$ = new incompl_located_var_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of incomplete located variable declaration."); yyerrok;} lbessard@131: | incompl_located_var_decl_list incompl_located_var_decl error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of incomplete located variable declaration."); yyerrok;} lbessard@133: | incompl_located_var_decl_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid incomplete located variable declaration."); yyerrok;} lbessard@131: | incompl_located_var_decl_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after incomplete located variable declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: incompl_located_var_decl: etisserant@0: variable_name incompl_location ':' var_spec mario@68: {$$ = new incompl_located_var_decl_c($1, $2, $4, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@134: | variable_name incompl_location var_spec lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between incomplete located variable and type specification."); yynerrs++; lbessard@134: } lbessard@131: | variable_name incompl_location ':' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in incomplete located variable declaration.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid specification in incomplete located variable declaration."); yyclearin;} lbessard@134: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: incompl_location: etisserant@0: AT incompl_location_token mario@68: {$$ = new incompl_location_c($2, locloc(@$));} 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: string_spec: etisserant@0: /* STRING msousa@350: {$$ = new single_byte_limited_len_string_spec_c($1, NULL, locloc(@$));} etisserant@0: */ etisserant@0: STRING '[' integer ']' msousa@350: {$$ = new single_byte_limited_len_string_spec_c(new string_type_name_c(locloc(@1)), $3, locloc(@$));} etisserant@0: /* etisserant@0: | WSTRING msousa@350: {$$ = new double_byte_limited_len_string_spec_c($1, NULL, locloc(@$));} etisserant@0: */ etisserant@0: | WSTRING '[' integer ']' msousa@350: {$$ = new double_byte_limited_len_string_spec_c(new wstring_type_name_c(locloc(@1)), $3, locloc(@$));} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /* intermediate helper symbol for: etisserant@0: * - non_retentive_var_decls etisserant@0: * - var_declarations etisserant@0: */ etisserant@0: var_init_decl_list: etisserant@0: var_init_decl ';' mario@68: {$$ = new var_init_decl_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | var_init_decl_list var_init_decl ';' etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | var_init_decl_list var_init_decl error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of variable(s) declaration."); yyerrok;} lbessard@133: | var_init_decl_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid variable(s) declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /***********************/ etisserant@0: /* B 1.5.1 - Functions */ etisserant@0: /***********************/ mario@68: /* mario@68: function_name: mario@68: prev_declared_derived_function_name mario@68: | standard_function_name mario@68: ; mario@68: */ mario@68: 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: /* 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: * mario@78: * 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: mjsousa@958: /* standard_function_name_no_clashes is only used in function invocations, so we use the poutype_identifier_c class! */ etisserant@0: standard_function_name_no_clashes: etisserant@0: standard_function_name_token mjsousa@958: {$$ = new poutype_identifier_c($1, locloc(@$));} 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: mjsousa@958: /* standard_function_name_NOT_clashes is only used in function invocations, so we use the poutype_identifier_c class! */ etisserant@0: standard_function_name_NOT_clashes: etisserant@0: NOT mjsousa@958: {$$ = new poutype_identifier_c(strdup("NOT"), locloc(@$));} 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: mjsousa@958: /* standard_function_name_expression_clashes is only used in function invocations, so we use the poutype_identifier_c class! */ etisserant@0: standard_function_name_expression_clashes: mjsousa@958: AND {$$ = new poutype_identifier_c(strdup("AND"), locloc(@$));} mjsousa@958: | OR {$$ = new poutype_identifier_c(strdup("OR"), locloc(@$));} mjsousa@958: | XOR {$$ = new poutype_identifier_c(strdup("XOR"), locloc(@$));} mjsousa@958: | ADD {$$ = new poutype_identifier_c(strdup("ADD"), locloc(@$));} mjsousa@958: | SUB {$$ = new poutype_identifier_c(strdup("SUB"), locloc(@$));} mjsousa@958: | MUL {$$ = new poutype_identifier_c(strdup("MUL"), locloc(@$));} mjsousa@958: | DIV {$$ = new poutype_identifier_c(strdup("DIV"), locloc(@$));} mjsousa@958: | MOD {$$ = new poutype_identifier_c(strdup("MOD"), locloc(@$));} mjsousa@958: | GT {$$ = new poutype_identifier_c(strdup("GT"), locloc(@$));} mjsousa@958: | GE {$$ = new poutype_identifier_c(strdup("GE"), locloc(@$));} mjsousa@958: | EQ {$$ = new poutype_identifier_c(strdup("EQ"), locloc(@$));} mjsousa@958: | LT {$$ = new poutype_identifier_c(strdup("LT"), locloc(@$));} mjsousa@958: | LE {$$ = new poutype_identifier_c(strdup("LE"), locloc(@$));} mjsousa@958: | NE {$$ = new poutype_identifier_c(strdup("NE"), locloc(@$));} mario@91: /* mjsousa@958: AND_operator {$$ = il_operator_c_2_poutype_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! mjsousa@958: //| AND2_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} mjsousa@958: | OR_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} mjsousa@958: | XOR_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} mjsousa@958: | ADD_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} mjsousa@958: | SUB_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} mjsousa@958: | MUL_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} mjsousa@958: | DIV_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} mjsousa@958: | MOD_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} mjsousa@958: | GT_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} mjsousa@958: | GE_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} mjsousa@958: | EQ_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} mjsousa@958: | LT_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} mjsousa@958: | LE_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} mjsousa@958: | NE_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} mario@91: */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: derived_function_name: mjsousa@952: identifier /* will never occur during normal parsing, only needed for preparsing to change it to a prev_declared_derived_function_name! */ etisserant@0: | prev_declared_derived_function_name mjsousa@958: {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$)); // transform the poutype_identifier_c into an identifier_c mjsousa@952: if (get_preparse_state() && !allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} etisserant@0: } msousa@350: | AND msousa@350: {$$ = new identifier_c("AND", locloc(@$)); mjsousa@952: if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} msousa@350: } msousa@350: | OR msousa@350: {$$ = new identifier_c("OR", locloc(@$)); mjsousa@952: if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} msousa@350: } msousa@350: | XOR msousa@350: {$$ = new identifier_c("XOR", locloc(@$)); mjsousa@952: if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} msousa@350: } msousa@350: | NOT msousa@350: {$$ = new identifier_c("NOT", locloc(@$)); mjsousa@952: if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} msousa@350: } msousa@350: | MOD msousa@350: {$$ = new identifier_c("MOD", locloc(@$)); mjsousa@952: if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} msousa@350: } 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 */ mjsousa@952: /* PRE_PARSING: The rules expected to be applied by the preparser. */ mjsousa@952: FUNCTION derived_function_name END_FUNCTION /* rule that is only expected to be used during preparse state => MUST print an error if used outside preparse() state!! */ mjsousa@952: {$$ = NULL; mjsousa@952: if (get_preparse_state()) {library_element_symtable.insert($2, prev_declared_derived_function_name_token);} mjsousa@952: else {print_err_msg(locl(@1), locf(@3), "FUNCTION with no variable declarations and no body."); yynerrs++;} mjsousa@952: } mjsousa@958: /* POST_PARSING and STANDARD_PARSING: The rules expected to be applied after the preparser has finished. */ mjsousa@952: | function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION mario@68: {$$ = new function_declaration_c($1, $3, $4, $5, locloc(@$)); mjsousa@1012: if (!runtime_options.disable_implicit_en_eno) add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ etisserant@0: variable_name_symtable.pop(); lbessard@175: direct_variable_symtable.pop(); mjsousa@955: library_element_symtable.insert($1, prev_declared_derived_function_name_token); 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 mario@68: {$$ = new function_declaration_c($1, $3, $4, $5, locloc(@$)); mjsousa@1012: if (!runtime_options.disable_implicit_en_eno) add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ etisserant@0: variable_name_symtable.pop(); lbessard@175: direct_variable_symtable.pop(); mjsousa@955: library_element_symtable.insert($1, prev_declared_derived_function_name_token); etisserant@0: } mjsousa@1014: /* | FUNCTION derived_function_name ':' VOID io_OR_function_var_declarations_list function_body END_FUNCTION */ mjsousa@1014: | function_name_declaration ':' VOID io_OR_function_var_declarations_list function_body END_FUNCTION mjsousa@1016: {$$ = new function_declaration_c($1, new void_type_name_c(locloc(@3)), $4, $5, locloc(@$)); mjsousa@1014: if (!runtime_options.disable_implicit_en_eno) add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ mjsousa@1014: variable_name_symtable.pop(); mjsousa@1014: direct_variable_symtable.pop(); mjsousa@1014: library_element_symtable.insert($1, prev_declared_derived_function_name_token); mjsousa@1014: } mario@68: /* ERROR_CHECK_BEGIN */ lbessard@131: | function_name_declaration elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after function name in function declaration."); yynerrs++;} lbessard@131: | function_name_declaration derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after function name in function declaration."); yynerrs++;} lbessard@131: | function_name_declaration ':' io_OR_function_var_declarations_list function_body END_FUNCTION lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no return type defined in function declaration."); yynerrs++;} lbessard@131: | function_name_declaration ':' error io_OR_function_var_declarations_list function_body END_FUNCTION lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid return type defined in function declaration."); yyerrok;} lbessard@131: | function_name_declaration ':' elementary_type_name function_body END_FUNCTION lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared in function declaration."); yynerrs++;} lbessard@131: | function_name_declaration ':' derived_type_name function_body END_FUNCTION lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared in function declaration."); yynerrs++;} lbessard@131: | function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list END_FUNCTION lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no body defined in function declaration."); yynerrs++;} lbessard@131: | function_name_declaration ':' derived_type_name io_OR_function_var_declarations_list END_FUNCTION lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no body defined in function declaration."); yynerrs++;} lbessard@131: | function_name_declaration ':' elementary_type_name END_FUNCTION lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared and body defined in function declaration."); yynerrs++;} lbessard@131: | function_name_declaration ':' derived_type_name END_FUNCTION lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared and body defined in function declaration."); yynerrs++;} lbessard@136: | function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list function_body END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locf(@3), "unclosed function declaration."); yynerrs++;} lbessard@136: | function_name_declaration ':' derived_type_name io_OR_function_var_declarations_list function_body END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed function declaration."); yynerrs++;} lbessard@131: | function_name_declaration error END_FUNCTION lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in function declaration."); yyerrok;} mario@68: /* ERROR_CHECK_END */ mario@68: ; mario@68: mario@68: 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: mjsousa@952: /* FUNCTION derived_function_name */ 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: } lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | FUNCTION error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no function name defined in function declaration.");} lbessard@136: else {print_err_msg(locf(@2), locl(@2), "invalid function name in function declaration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /* intermediate helper symbol for function_declaration */ etisserant@0: io_OR_function_var_declarations_list: lbessard@131: io_var_declarations lbessard@131: {$$ = new var_declarations_list_c(locloc(@1));$$->add_element($1);} lbessard@131: | function_var_decls lbessard@131: {$$ = new var_declarations_list_c(locloc(@1));$$->add_element($1);} 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);} lbessard@134: /* ERROR_CHECK_BEGIN */ lbessard@134: | io_OR_function_var_declarations_list retentive_var_declarations lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected retentive variable(s) declaration in function declaration."); yynerrs++;} lbessard@134: | io_OR_function_var_declarations_list located_var_declarations lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected located variable(s) declaration in function declaration."); yynerrs++;} lbessard@134: | io_OR_function_var_declarations_list external_var_declarations lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected external variable(s) declaration in function declaration."); yynerrs++;} lbessard@134: | io_OR_function_var_declarations_list global_var_declarations lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected global variable(s) declaration in function declaration."); yynerrs++;} lbessard@134: | io_OR_function_var_declarations_list incompl_located_var_declarations lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected incomplete located variable(s) declaration in function declaration."); yynerrs++;} lbessard@134: | io_OR_function_var_declarations_list temp_var_decls lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected temporary located variable(s) declaration in function declaration."); yynerrs++;} lbessard@134: | io_OR_function_var_declarations_list non_retentive_var_decls lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected non-retentive variable(s) declaration in function declaration."); yynerrs++;} lbessard@134: /*| io_OR_function_var_declarations_list access_declarations lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected access variable(s) declaration in function declaration."); yynerrs++;}*/ lbessard@134: | io_OR_function_var_declarations_list instance_specific_initializations lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected instance specific initialization(s) in function declaration."); yynerrs++;} lbessard@134: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new function_var_decls_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} etisserant@0: | VAR var2_init_decl_list END_VAR mario@68: {$$ = new function_var_decls_c(NULL, $2, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@136: | VAR error var2_init_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR' in function variable(s) declaration."); yyerrok;} lbessard@136: | VAR CONSTANT error var2_init_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant function variable(s) declaration."); yyerrok;} lbessard@136: | VAR var2_init_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed function variable(s) declaration."); yyerrok;} lbessard@136: | VAR CONSTANT var2_init_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant function variable(s) declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: /* intermediate helper symbol for function_var_decls */ etisserant@0: var2_init_decl_list: etisserant@0: var2_init_decl ';' mario@68: {$$ = new var2_init_decl_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | var2_init_decl_list var2_init_decl ';' etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | var2_init_decl error lbessard@136: {$$ = new var2_init_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of function variable(s) declaration."); yyerrok;} lbessard@131: | var2_init_decl_list var2_init_decl error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of function variable(s) declaration."); yyerrok;} lbessard@133: | var2_init_decl_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid function variable(s) declaration."); yyerrok;} lbessard@131: | var2_init_decl_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after function variable(s) declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: function_body: mjsousa@1016: start_ST_body_token statement_list {$$ = $2;} mjsousa@1016: | start_IL_body_token instruction_list {$$ = $2;} 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: mario@68: standard_function_block_name: standard_function_block_name_token {$$ = new identifier_c($1, locloc(@$));}; etisserant@0: etisserant@0: derived_function_block_name: identifier; etisserant@0: etisserant@0: etisserant@0: function_block_declaration: mjsousa@955: /* PRE_PARSING: The rules expected to be applied by the preparser. Will only run if pre-parsing command line option is ON. */ mjsousa@952: FUNCTION_BLOCK derived_function_block_name END_FUNCTION_BLOCK /* rule that is only expected to be used during preparse state => MUST print an error if used outside preparse() state!! */ mjsousa@952: {$$ = NULL; mjsousa@952: if (get_preparse_state()) {library_element_symtable.insert($2, prev_declared_derived_function_block_name_token);} mjsousa@952: else {print_err_msg(locl(@1), locf(@3), "FUNCTION_BLOCK with no variable declarations and no body."); yynerrs++;} mjsousa@952: } mjsousa@955: /* POST_PARSING: The rules expected to be applied after the preparser runs. Will only run if pre-parsing command line option is ON. */ mjsousa@952: | FUNCTION_BLOCK prev_declared_derived_function_block_name io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK mario@68: {$$ = new function_block_declaration_c($2, $3, $4, locloc(@$)); mjsousa@1012: if (!runtime_options.disable_implicit_en_eno) add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ mjsousa@955: /* Clear the variable_name_symtable. Since we have finished parsing the function block, mjsousa@955: * the variable names are now out of scope, so are no longer valid! mjsousa@955: */ mjsousa@955: variable_name_symtable.pop(); mjsousa@955: direct_variable_symtable.pop(); mjsousa@955: } mjsousa@955: /* STANDARD_PARSING: The rules expected to be applied in single-phase parsing. Will only run if pre-parsing command line option is OFF. */ mjsousa@955: | FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK mjsousa@955: {$$ = new function_block_declaration_c($2, $3, $4, locloc(@$)); etisserant@0: library_element_symtable.insert($2, prev_declared_derived_function_block_name_token); mjsousa@1012: if (!runtime_options.disable_implicit_en_eno) add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ mjsousa@955: /* Clear the variable_name_symtable. Since we have finished parsing the function block, mjsousa@955: * the variable names are now out of scope, so are no longer valid! etisserant@0: */ etisserant@0: variable_name_symtable.pop(); lbessard@175: direct_variable_symtable.pop(); etisserant@0: } mario@68: /* ERROR_CHECK_BEGIN */ lbessard@131: | FUNCTION_BLOCK io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in function block declaration."); yynerrs++;} lbessard@131: | FUNCTION_BLOCK error io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name in function block declaration."); yyerrok;} lbessard@131: | FUNCTION_BLOCK derived_function_block_name function_block_body END_FUNCTION_BLOCK lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared in function declaration."); yynerrs++;} lbessard@131: | FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list END_FUNCTION_BLOCK lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no body defined in function block declaration."); yynerrs++;} mjsousa@952: /* Rule already covered by the rule to handle the preparse state! lbessard@131: | FUNCTION_BLOCK derived_function_block_name END_FUNCTION_BLOCK lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared and body defined in function block declaration."); yynerrs++;} mjsousa@952: */ lbessard@136: | FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_OF_INPUT mjsousa@1016: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "expecting END_FUNCTION_BLOCK before end of file."); yynerrs++;} mario@68: | FUNCTION_BLOCK error END_FUNCTION_BLOCK lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in function block declaration."); yyerrok;} mario@68: /* ERROR_CHECK_END */ 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: lbessard@131: io_var_declarations lbessard@131: {$$ = new var_declarations_list_c(locloc(@$));$$->add_element($1);} lbessard@131: | other_var_declarations lbessard@131: {$$ = new var_declarations_list_c(locloc(@$));$$->add_element($1);} 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);} lbessard@134: /* ERROR_CHECK_BEGIN */ lbessard@134: | io_OR_other_var_declarations_list located_var_declarations lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected located variable(s) declaration in function block declaration."); yynerrs++;} lbessard@134: | io_OR_other_var_declarations_list global_var_declarations lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected global variable(s) declaration in function block declaration."); yynerrs++;} lbessard@134: /*| io_OR_other_var_declarations_list access_declarations lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected access variable(s) declaration in function block declaration."); yynerrs++;}*/ lbessard@134: | io_OR_other_var_declarations_list instance_specific_initializations lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected instance specific initialization(s) in function block declaration."); yynerrs++;} lbessard@134: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new temp_var_decls_c($2, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | VAR_TEMP END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in temporary variable(s) declaration."); yynerrs++;} lbessard@136: | VAR_TEMP temp_var_decls_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "unclosed temporary variable(s) declaration."); yyerrok;} lbessard@131: | VAR_TEMP error temp_var_decls_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_TEMP' in function variable(s) declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ 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 ';' mario@68: {$$ = new temp_var_decls_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | temp_var_decls_list temp_var_decl ';' etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@134: | error ';' lbessard@136: {$$ = new temp_var_decls_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid temporary variable(s) declaration."); yyerrok;} lbessard@131: | temp_var_decl error lbessard@136: {$$ = new temp_var_decls_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of temporary variable(s) declaration."); yyerrok;} lbessard@131: | temp_var_decls_list temp_var_decl error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of temporary variable(s) declaration."); yyerrok;} lbessard@133: | temp_var_decls_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid temporary variable(s) declaration."); yyerrok;} lbessard@131: | temp_var_decls_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after temporary variable(s) declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: non_retentive_var_decls: etisserant@0: VAR NON_RETAIN var_init_decl_list END_VAR mario@68: {$$ = new non_retentive_var_decls_c($3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@136: | VAR NON_RETAIN var_init_decl_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unclosed non-retentive temporary variable(s) declaration."); yyerrok;} lbessard@131: | VAR NON_RETAIN error var_init_decl_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive temporary variable(s) declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: function_block_body: mjsousa@1016: /* NOTE: start_ST_body_token is a dummy token generated by flex when it determines it is starting to parse a POU body in ST mjsousa@1016: * start_IL_body_token is a dummy token generated by flex when it determines it is starting to parse a POU body in IL mjsousa@1016: * These tokens help remove a reduce/reduce conflict in bison, between a formal function invocation in IL, and a mjsousa@1016: * function invocation used as a statement (a non-standard extension added to matiec) mjsousa@1016: * e.g: FUNCTION_BLOCK foo mjsousa@1016: * VAR ... END_VAR mjsousa@1016: * func_returning_void(in1 := 3 mjsousa@1016: * ); --> only the presence or absence of ';' will determine whether this is a IL or ST mjsousa@1016: * function invocation. (In standard ST this would be ilegal, in matiec we allow it mjsousa@1016: * when activated by a command line option) mjsousa@1016: * END_FUNCTION mjsousa@1016: */ mjsousa@1016: start_ST_body_token statement_list {$$ = $2;} mjsousa@1016: | start_IL_body_token instruction_list {$$ = $2;} mjsousa@1016: | 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: mjsousa@955: /* PRE_PARSING: The rules expected to be applied by the preparser. Will only run if pre-parsing command line option is ON. */ mjsousa@952: PROGRAM program_type_name END_PROGRAM /* rule that is only expected to be used during preparse state => MUST print an error if used outside preparse() state!! */ mjsousa@952: {$$ = NULL; mjsousa@952: if (get_preparse_state()) {library_element_symtable.insert($2, prev_declared_program_type_name_token);} mjsousa@952: else {print_err_msg(locl(@1), locf(@3), "PROGRAM with no variable declarations and no body."); yynerrs++;} mjsousa@952: } mjsousa@955: /* POST_PARSING: The rules expected to be applied after the preparser runs. Will only run if pre-parsing command line option is ON. */ mjsousa@952: | PROGRAM prev_declared_program_type_name program_var_declarations_list function_block_body END_PROGRAM mario@68: {$$ = new program_declaration_c($2, $3, $4, locloc(@$)); mjsousa@955: /* Clear the variable_name_symtable. Since we have finished parsing the program declaration, mjsousa@955: * the variable names are now out of scope, so are no longer valid! mjsousa@955: */ mjsousa@955: variable_name_symtable.pop(); mjsousa@955: direct_variable_symtable.pop(); mjsousa@955: } mjsousa@955: /* STANDARD_PARSING: The rules expected to be applied in single-phase parsing. Will only run if pre-parsing command line option is OFF. */ mjsousa@955: | PROGRAM program_type_name {library_element_symtable.insert($2, prev_declared_program_type_name_token);} program_var_declarations_list function_block_body END_PROGRAM mjsousa@955: {$$ = new program_declaration_c($2, $4, $5, locloc(@$)); mjsousa@955: /* Clear the variable_name_symtable. Since we have finished parsing the program declaration, mjsousa@955: * the variable names are now out of scope, so are no longer valid! etisserant@0: */ etisserant@0: variable_name_symtable.pop(); lbessard@175: direct_variable_symtable.pop(); etisserant@0: } mario@68: /* ERROR_CHECK_BEGIN */ lbessard@131: | PROGRAM program_var_declarations_list function_block_body END_PROGRAM lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no program name defined in program declaration.");} lbessard@131: | PROGRAM error program_var_declarations_list function_block_body END_PROGRAM lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid program name in program declaration."); yyerrok;} mjsousa@952: | PROGRAM prev_declared_program_type_name function_block_body END_PROGRAM lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared in program declaration."); yynerrs++;} mjsousa@952: | PROGRAM prev_declared_program_type_name program_var_declarations_list END_PROGRAM lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no body defined in program declaration."); yynerrs++;} mjsousa@952: /* Rule already covered by the rule to handle the preparse state! mjsousa@952: | PROGRAM prev_declared_program_type_name END_PROGRAM lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared and body defined in program declaration."); yynerrs++;} mjsousa@952: */ mjsousa@952: | PROGRAM prev_declared_program_type_name program_var_declarations_list function_block_body END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed program declaration."); yynerrs++;} mario@68: | PROGRAM error END_PROGRAM lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in program declaration."); yyerrok;} mario@68: /* ERROR_CHECK_END */ 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: lbessard@131: io_var_declarations lbessard@131: {$$ = new var_declarations_list_c(locloc(@$)); $$->add_element($1);} lbessard@131: | other_var_declarations lbessard@131: {$$ = new var_declarations_list_c(locloc(@$)); $$->add_element($1);} lbessard@131: | located_var_declarations lbessard@131: {$$ = new var_declarations_list_c(locloc(@$)); $$->add_element($1);} 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: */ lbessard@134: /* ERROR_CHECK_BEGIN */ lbessard@134: | program_var_declarations_list global_var_declarations lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected global variable(s) declaration in function block declaration."); yynerrs++;} lbessard@134: /*| program_var_declarations_list access_declarations lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected access variable(s) declaration in function block declaration."); yynerrs++;}*/ lbessard@134: | program_var_declarations_list instance_specific_initializations lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected instance specific initialization(s) in function block declaration."); yynerrs++; lbessard@134: } lbessard@134: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new sequential_function_chart_c(locloc(@$)); $$->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 mario@68: {$$ = new sfc_network_c(locloc(@$)); $$->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);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | sfc_network error lbessard@136: {$$ = $1; print_err_msg(locl(@1), locf(@2), "unexpected token after SFC network in sequencial function chart."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: initial_step: etisserant@0: INITIAL_STEP step_name ':' action_association_list END_STEP mario@13: // INITIAL_STEP identifier ':' action_association_list END_STEP msousa@616: {$$ = new initial_step_c($2, $4, locloc(@$)); msousa@616: variable_name_symtable.insert($2, prev_declared_variable_name_token); // A step name may later be used as a structured variable!! msousa@616: } lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | INITIAL_STEP ':' action_association_list END_STEP lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "no step name defined in initial step declaration."); yynerrs++;} lbessard@131: | INITIAL_STEP error ':' action_association_list END_STEP lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid step name defined in initial step declaration."); yyerrok;} lbessard@131: | INITIAL_STEP step_name action_association_list END_STEP lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':' missing after step name in initial step declaration."); yynerrs++;} lbessard@131: | INITIAL_STEP step_name ':' error END_STEP lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid action association list in initial step declaration."); yyerrok;} lbessard@136: | INITIAL_STEP step_name ':' action_association_list END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed initial step declaration."); yynerrs++;} lbessard@131: | INITIAL_STEP error END_STEP lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in initial step declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: step: etisserant@0: STEP step_name ':' action_association_list END_STEP mario@13: // STEP identifier ':' action_association_list END_STEP msousa@616: {$$ = new step_c($2, $4, locloc(@$)); msousa@616: variable_name_symtable.insert($2, prev_declared_variable_name_token); // A step name may later be used as a structured variable!! msousa@616: } lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | STEP ':' action_association_list END_STEP lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no step name defined in step declaration."); yynerrs++;} lbessard@131: | STEP error ':' action_association_list END_STEP lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid step name defined in step declaration."); yyerrok;} lbessard@131: | STEP step_name action_association_list END_STEP lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':' missing after step name in step declaration."); yynerrs++;} lbessard@131: | STEP step_name ':' error END_STEP lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid action association list in step declaration."); yyerrok;} lbessard@136: | STEP step_name ':' action_association_list END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@3), "invalid action association list in step declaration."); yynerrs++;} lbessard@131: | STEP error END_STEP lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in step declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ 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 */ mario@68: {$$ = new action_association_list_c(locloc(@$));} etisserant@0: | action_association_list action_association ';' etisserant@1: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | action_association_list action_association error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of action association declaration."); yyerrok;} lbessard@131: | action_association_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after action association declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@1: ; etisserant@1: etisserant@0: mario@13: // step_name: identifier; mario@13: step_name: any_identifier; etisserant@0: etisserant@0: action_association: msousa@295: action_name '(' {cmd_goto_sfc_qualifier_state();} action_qualifier {cmd_pop_state();} indicator_name_list ')' mario@68: {$$ = new action_association_c($1, $4, $6, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@136: /*| action_name '(' error ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid qualifier defined in action association."); yyerrok;}*/ lbessard@131: /* ERROR_CHECK_END */ etisserant@1: ; etisserant@1: etisserant@1: /* helper symbol for action_association */ etisserant@0: indicator_name_list: etisserant@1: /* empty */ mario@68: {$$ = new indicator_name_list_c(locloc(@$));} etisserant@0: | indicator_name_list ',' indicator_name etisserant@1: {$$ = $1; $$->add_element($3);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | indicator_name_list indicator_name lbessard@136: {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing at end of action association declaration."); yynerrs++;} lbessard@131: | indicator_name_list ',' error lbessard@134: {$$ = $1; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no indicator defined in indicator list.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid indicator in indicator list."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: mario@13: // action_name: identifier; mario@13: action_name: any_identifier; etisserant@0: etisserant@0: action_qualifier: etisserant@1: /* empty */ etisserant@1: {$$ = NULL;} etisserant@1: | qualifier mario@68: {$$ = new action_qualifier_c($1, NULL, locloc(@$));} etisserant@0: | timed_qualifier ',' action_time mario@68: {$$ = new action_qualifier_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | timed_qualifier action_time lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "',' missing between timed qualifier and action time in action qualifier."); yynerrs++;} lbessard@131: | timed_qualifier ',' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no action time defined in action qualifier.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid action time in action qualifier."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@1: ; etisserant@1: etisserant@1: qualifier: mario@94: N {$$ = new qualifier_c(strdup("N"), locloc(@$));} mario@68: | R {$$ = new qualifier_c(strdup("R"), locloc(@$));} mario@68: | S {$$ = new qualifier_c(strdup("S"), locloc(@$));} mario@68: | P {$$ = new qualifier_c(strdup("P"), locloc(@$));} Laurent@627: | P0 {$$ = new qualifier_c(strdup("P0"), locloc(@$));} Laurent@627: | P1 {$$ = new qualifier_c(strdup("P1"), locloc(@$));} etisserant@0: ; etisserant@0: etisserant@0: timed_qualifier: mario@94: L {$$ = new timed_qualifier_c(strdup("L"), locloc(@$));} mario@68: | D {$$ = new timed_qualifier_c(strdup("D"), locloc(@$));} mario@68: | SD {$$ = new timed_qualifier_c(strdup("SD"), locloc(@$));} mario@68: | DS {$$ = new timed_qualifier_c(strdup("DS"), locloc(@$));} mario@68: | SL {$$ = new timed_qualifier_c(strdup("SL"), locloc(@$));} etisserant@0: ; etisserant@0: msousa@616: /* NOTE: A step_name may be used as a structured vaqriable, in order to access the status bit (e.g. Step1.X) msousa@616: * or the time it has been active (e.g. Step1.T). msousa@616: * In order to allow the step name to be used as a variable inside ST expressions (only ST expressions ??) msousa@616: * when defining transitions, we need to add the step_name to the list of previously declared variables. msousa@616: * This allows the step name to be used as a variable inside all transition expressions, as the user msousa@616: * can clearly define the transition _after_ the step itself has been defined/declared, so the msousa@616: * 'variable' is previously 'declared'. msousa@616: * msousa@616: * However, when defining/declaring a step, a variable name can also be used to define a timed msousa@616: * action association. In this case, we may have a circular reference: msousa@616: * e.g. msousa@616: * ... msousa@616: * STEP step1: msousa@616: * action1 (D,t#100ms); msousa@616: * end_step msousa@616: * msousa@616: * STEP step2: msousa@616: * action1 (D,step3.T); <---- forward reference to step3.T !!!!!! msousa@616: * end_step msousa@616: * msousa@616: * STEP step3: msousa@616: * action1 (D,step2.T); <---- back reference to step2.T msousa@616: * end_step msousa@616: * msousa@616: * msousa@616: * There is no way the user can always use the step3.T variable only after it has msousa@616: * been 'declared'. So adding the steps to the list of previously declared variables msousa@616: * when the steps are declared is not a solution to the above situation. msousa@616: * msousa@616: * Fortunately, the standard does not allow ST expressions in the above syntax msousa@616: * (i.e. when defining the delay of a timed actions), but only either a msousa@616: * Time literal, or a variable. msousa@616: * This is why we change the definition of action_time from msousa@616: * action_time: msousa@616: * duration msousa@616: * | variable msousa@616: * ; msousa@616: * msousa@616: * to: msousa@616: * action_time: msousa@616: * duration msousa@616: * | any_symbolic_variable msousa@616: * ; msousa@616: * msousa@616: * NOTE that this same problem does not occur with the 'indicator_name': it does not msousa@616: * make sense to set/indicate a step1.X variable, as these variables are read-only! msousa@616: */ msousa@616: etisserant@0: action_time: etisserant@0: duration msousa@616: //| variable msousa@616: | any_symbolic_variable lbessard@10: ; lbessard@10: lbessard@10: indicator_name: variable; etisserant@0: mario@13: // transition_name: identifier; mario@13: transition_name: any_identifier; mario@13: etisserant@0: etisserant@0: steps: etisserant@0: step_name mario@68: {$$ = new steps_c($1, NULL, locloc(@$));} etisserant@0: | '(' step_name_list ')' mario@68: {$$ = new steps_c(NULL, $2, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | '(' step_name_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "expecting ')' at the end of step list in transition declaration."); yyerrok;} lbessard@131: | '(' error ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid step list in transition declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@1: ; etisserant@0: etisserant@0: step_name_list: etisserant@0: step_name ',' step_name mario@68: {$$ = new step_name_list_c(locloc(@$)); $$->add_element($1); $$->add_element($3);} etisserant@0: | step_name_list ',' step_name etisserant@1: {$$ = $1; $$->add_element($3);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | step_name_list step_name lbessard@136: {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in step list."); yynerrs++;} lbessard@131: | step_name_list ',' error lbessard@134: {$$ = $1; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no step name defined in step list.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid step name in step list."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@1: ; etisserant@0: mario@13: mario@85: /* NOTE: flex will automatically pop() out of body_state to previous state. mario@94: * We do not need to give a command from bison to return to previous flex state, mario@94: * after forcing flex to go to body_state. mario@85: */ mario@85: transition: lbessard@131: TRANSITION transition_priority mario@85: FROM steps TO steps mario@85: {cmd_goto_body_state();} transition_condition mario@85: END_TRANSITION lbessard@131: {$$ = new transition_c(NULL, $2, $4, $6, $8, locloc(@$));} mario@85: //| TRANSITION identifier FROM steps TO steps ... lbessard@131: | TRANSITION transition_name transition_priority mario@85: FROM steps TO steps mario@85: {cmd_goto_body_state();} transition_condition mario@85: END_TRANSITION lbessard@131: {$$ = new transition_c($2, $3, $5, $7, $9, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | TRANSITION error transition_priority FROM steps TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid transition name defined in transition declaration."); yyerrok;} lbessard@131: | TRANSITION transition_name error FROM steps TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid transition priority defined in transition declaration."); yyerrok;} lbessard@131: | TRANSITION transition_priority FROM TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no origin step(s) defined in transition declaration."); yynerrs++;} lbessard@131: | TRANSITION transition_name transition_priority FROM TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no origin step(s) defined in transition declaration."); yynerrs++;} lbessard@131: | TRANSITION transition_priority FROM error TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid origin step(s) defined in transition declaration."); yyerrok;} lbessard@131: | TRANSITION transition_name transition_priority FROM error TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locf(@5), locl(@5), "invalid origin step(s) defined in transition declaration."); yyerrok;} lbessard@131: | TRANSITION transition_priority FROM steps steps {cmd_goto_body_state();} transition_condition END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "'TO' missing between origin step(s) and destination step(s) in transition declaration."); yynerrs++;} lbessard@131: | TRANSITION transition_name transition_priority FROM steps steps {cmd_goto_body_state();} transition_condition END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locl(@5), locf(@6), "'TO' missing between origin step(s) and destination step(s) in transition declaration."); yynerrs++;} lbessard@131: | TRANSITION transition_priority FROM steps TO {cmd_goto_body_state();} transition_condition END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locl(@5), locf(@7), "no destination step(s) defined in transition declaration."); yynerrs++;} lbessard@131: | TRANSITION transition_name transition_priority FROM steps TO {cmd_goto_body_state();} transition_condition END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locl(@6), locf(@8), "no destination step(s) defined in transition declaration."); yynerrs++;} lbessard@131: | TRANSITION transition_priority FROM steps TO error {cmd_goto_body_state();} transition_condition END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid destination step(s) defined in transition declaration."); yyerrok;} lbessard@131: | TRANSITION transition_name transition_priority FROM steps TO error {cmd_goto_body_state();} transition_condition END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locf(@7), locl(@7), "invalid destination step(s) defined in transition declaration."); yyerrok;} lbessard@131: | TRANSITION transition_priority {cmd_goto_body_state();} transition_condition END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@4), "no origin and destination step(s) defined in transition declaration."); yynerrs++;} lbessard@131: | TRANSITION transition_name transition_priority {cmd_goto_body_state();} transition_condition END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@5), "no origin and destination step(s) defined in transition declaration."); yynerrs++;} lbessard@136: /*| TRANSITION transition_priority FROM steps TO steps {cmd_goto_body_state();} transition_condition error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@6), "unclosed transition declaration."); yyerrok;} lbessard@136: | TRANSITION transition_name transition_priority FROM steps TO steps {cmd_goto_body_state();} transition_condition error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@7), "unclosed transition declaration."); yyerrok;}*/ lbessard@131: | TRANSITION error END_TRANSITION lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in transition declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ lbessard@131: ; lbessard@131: lbessard@131: transition_priority: lbessard@131: /* empty */ lbessard@131: {$$ = NULL;} lbessard@131: | '(' {cmd_goto_sfc_priority_state();} PRIORITY {cmd_pop_state();} ASSIGN integer ')' lbessard@131: {$$ = $6;} msousa@547: /* ERROR_CHECK_BEGIN */ msousa@547: /* The following error checking rules have been intentionally commented out. */ msousa@547: /* lbessard@134: | '(' ASSIGN integer ')' lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'PRIORITY' missing between '(' and ':=' in transition declaration with priority."); yynerrs++;} lbessard@134: | '(' error ASSIGN integer ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "expecting 'PRIORITY' between '(' and ':=' in transition declaration with priority."); yyerrok;} msousa@547: */ msousa@547: /* ERROR_CHECK_END */ lbessard@131: ; mario@85: mario@85: mario@85: transition_condition: andrej@1031: start_IL_body_token ':' eol_list simple_instr_list andrej@1031: {$$ = new transition_condition_c($4, NULL, locloc(@$));} mario@85: | ASSIGN expression ';' mario@88: {$$ = new transition_condition_c(NULL, $2, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ andrej@1031: | start_IL_body_token eol_list simple_instr_list mjsousa@1032: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':' missing before IL condition in transition declaration."); yynerrs++;} andrej@1031: | start_IL_body_token ':' eol_list error lbessard@131: {$$ = NULL; mjsousa@1032: if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no instructions defined in IL condition of transition declaration.");} mjsousa@1032: else {print_err_msg(locf(@4), locl(@4), "invalid instructions in IL condition of transition declaration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | ASSIGN ';' lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no expression defined in ST condition of transition declaration."); yynerrs++;} lbessard@131: | ASSIGN error ';' lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid expression defined in ST condition of transition declaration."); yyerrok;} lbessard@131: | ASSIGN expression error lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "expecting ';' after expression defined in ST condition of transition declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ lbessard@10: ; lbessard@3: mario@68: etisserant@0: etisserant@0: action: mario@85: // ACTION identifier ':' ... lbessard@151: ACTION action_name {cmd_goto_body_state();} action_body END_ACTION lbessard@151: {$$ = new action_c($2, $4, locloc(@$));} lbessard@151: /* ERROR_CHECK_BEGIN */ lbessard@151: | ACTION {cmd_goto_body_state();} action_body END_ACTION lbessard@151: {$$ = NULL; print_err_msg(locl(@1), locf(@3), "no action name defined in action declaration."); yynerrs++;} lbessard@151: | ACTION error {cmd_goto_body_state();} action_body END_ACTION lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid action name defined in action declaration."); yyerrok;} lbessard@131: | ACTION action_name {cmd_goto_body_state();} function_block_body END_ACTION lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@4), "':' missing after action name in action declaration."); yynerrs++;} lbessard@151: /*| ACTION action_name {cmd_goto_body_state();} action_body END_OF_INPUT lbessard@151: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed action declaration."); yyerrok;}*/ lbessard@131: | ACTION error END_ACTION lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in action declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@1: ; etisserant@1: lbessard@151: action_body: lbessard@151: ':' function_block_body lbessard@151: {$$ = $2;} lbessard@151: /* ERROR_CHECK_BEGIN */ lbessard@151: | ':' error lbessard@151: {$$ = NULL; lbessard@151: if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no body defined in action declaration.");} lbessard@151: else {print_err_msg(locf(@2), locl(@2), "invalid body defined in action declaration."); yyclearin;} lbessard@151: yyerrok; lbessard@151: } lbessard@151: /* ERROR_CHECK_END */ lbessard@151: ; lbessard@151: 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 lbessard@131: * prev_declared_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: */ mjsousa@952: prev_declared_global_var_name: prev_declared_global_var_name_token {$$ = new identifier_c($1, locloc(@$));}; mjsousa@952: prev_declared_resource_name: prev_declared_resource_name_token {$$ = new identifier_c($1, locloc(@$));}; mjsousa@952: prev_declared_program_name: prev_declared_program_name_token {$$ = new identifier_c($1, locloc(@$));}; mjsousa@952: prev_declared_configuration_name: prev_declared_configuration_name_token {$$ = new identifier_c($1, locloc(@$));}; mjsousa@952: // prev_declared_task_name: prev_declared_task_name_token {$$ = new identifier_c($1, locloc(@$));}; 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: mjsousa@955: /* PRE_PARSING: The rules expected to be applied by the preparser. Will only run if pre-parsing command line option is ON. */ mjsousa@952: CONFIGURATION configuration_name END_CONFIGURATION /* rule that is only expected to be used during preparse state */ mjsousa@952: {$$ = NULL; mjsousa@952: if (get_preparse_state()) {library_element_symtable.insert($2, prev_declared_configuration_name_token);} mjsousa@952: else {print_err_msg(locl(@1), locf(@3), "no resource(s) nor program(s) defined in configuration declaration."); yynerrs++;} mjsousa@952: } mjsousa@955: /* POST_PARSING: The rules expected to be applied after the preparser runs. Will only run if pre-parsing command line option is ON. */ mjsousa@952: | CONFIGURATION prev_declared_configuration_name mjsousa@862: global_var_declarations_list etisserant@0: single_resource_declaration lbessard@175: {variable_name_symtable.pop(); lbessard@175: direct_variable_symtable.pop();} etisserant@0: optional_access_declarations etisserant@0: optional_instance_specific_initializations etisserant@0: END_CONFIGURATION mario@68: {$$ = new configuration_declaration_c($2, $3, $4, $6, $7, locloc(@$)); etisserant@0: variable_name_symtable.pop(); lbessard@175: direct_variable_symtable.pop(); etisserant@0: } mjsousa@952: | CONFIGURATION prev_declared_configuration_name mjsousa@862: global_var_declarations_list etisserant@0: resource_declaration_list etisserant@0: optional_access_declarations etisserant@0: optional_instance_specific_initializations etisserant@0: END_CONFIGURATION mario@68: {$$ = new configuration_declaration_c($2, $3, $4, $5, $6, locloc(@$)); etisserant@0: variable_name_symtable.pop(); lbessard@175: direct_variable_symtable.pop(); mario@85: } mjsousa@955: /* STANDARD_PARSING: The rules expected to be applied in single-phase parsing. Will only run if pre-parsing command line option is OFF. */ mjsousa@955: | CONFIGURATION configuration_name mjsousa@955: global_var_declarations_list mjsousa@955: single_resource_declaration mjsousa@955: {variable_name_symtable.pop(); mjsousa@955: direct_variable_symtable.pop();} mjsousa@955: optional_access_declarations mjsousa@955: optional_instance_specific_initializations mjsousa@955: END_CONFIGURATION mjsousa@955: {$$ = new configuration_declaration_c($2, $3, $4, $6, $7, locloc(@$)); mjsousa@955: variable_name_symtable.pop(); mjsousa@955: direct_variable_symtable.pop(); mjsousa@955: library_element_symtable.insert($2, prev_declared_configuration_name_token); mjsousa@955: } etisserant@0: | CONFIGURATION configuration_name mjsousa@862: global_var_declarations_list etisserant@0: resource_declaration_list etisserant@0: optional_access_declarations etisserant@0: optional_instance_specific_initializations etisserant@0: END_CONFIGURATION mario@68: {$$ = new configuration_declaration_c($2, $3, $4, $5, $6, locloc(@$)); etisserant@0: variable_name_symtable.pop(); lbessard@175: direct_variable_symtable.pop(); mjsousa@955: library_element_symtable.insert($2, prev_declared_configuration_name_token); mario@85: } mario@68: /* ERROR_CHECK_BEGIN */ lbessard@131: | CONFIGURATION mjsousa@862: global_var_declarations_list lbessard@131: single_resource_declaration lbessard@175: {variable_name_symtable.pop(); lbessard@175: direct_variable_symtable.pop();} lbessard@131: optional_access_declarations lbessard@131: optional_instance_specific_initializations lbessard@131: END_CONFIGURATION lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no configuration name defined in configuration declaration."); yynerrs++;} lbessard@131: | CONFIGURATION mjsousa@862: global_var_declarations_list lbessard@131: resource_declaration_list lbessard@131: optional_access_declarations lbessard@131: optional_instance_specific_initializations lbessard@131: END_CONFIGURATION lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no configuration name defined in configuration declaration."); yynerrs++;} lbessard@131: | CONFIGURATION error mjsousa@862: global_var_declarations_list lbessard@131: single_resource_declaration lbessard@175: {variable_name_symtable.pop(); lbessard@175: direct_variable_symtable.pop();} lbessard@131: optional_access_declarations lbessard@131: optional_instance_specific_initializations lbessard@131: END_CONFIGURATION lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid configuration name defined in configuration declaration."); yyerrok;} lbessard@131: | CONFIGURATION error mjsousa@862: global_var_declarations_list lbessard@131: resource_declaration_list lbessard@131: optional_access_declarations lbessard@131: optional_instance_specific_initializations lbessard@131: END_CONFIGURATION lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid configuration name defined in configuration declaration."); yyerrok;} mjsousa@952: /* Rule already covered by the rule to handle the preparse state! lbessard@131: | CONFIGURATION configuration_name mjsousa@862: global_var_declarations_list lbessard@131: optional_access_declarations lbessard@131: optional_instance_specific_initializations lbessard@131: END_CONFIGURATION lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no resource(s) defined in configuration declaration."); yynerrs++;} mjsousa@952: */ lbessard@131: | CONFIGURATION configuration_name mjsousa@862: global_var_declarations_list lbessard@131: error lbessard@131: optional_access_declarations lbessard@131: optional_instance_specific_initializations lbessard@131: END_CONFIGURATION lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid resource(s) defined in configuration declaration."); yyerrok;} lbessard@136: /*| CONFIGURATION configuration_name mjsousa@862: global_var_declarations_list lbessard@136: single_resource_declaration lbessard@175: {variable_name_symtable.pop(); lbessard@175: direct_variable_symtable.pop();} lbessard@136: optional_access_declarations lbessard@136: optional_instance_specific_initializations lbessard@136: END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed configuration declaration."); yyerrok;}*/ lbessard@136: | CONFIGURATION configuration_name mjsousa@862: global_var_declarations_list lbessard@136: resource_declaration_list lbessard@136: optional_access_declarations lbessard@136: optional_instance_specific_initializations lbessard@136: END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed configuration declaration."); yyerrok;} etisserant@0: | CONFIGURATION error END_CONFIGURATION lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in configuration declaration."); yyerrok;} mario@68: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: // helper symbol for etisserant@0: // - configuration_declaration etisserant@0: // - resource_declaration etisserant@0: // mjsousa@862: /* NOTE: The IEC 61131-3 v2 standard defines this list as being: [global_var_declarations] mjsousa@862: * e.g.: mjsousa@862: * 'CONFIGURATION' configuration_name [global_var_declarations] ... mjsousa@862: * mjsousa@862: * However, this means that a single VAR_GLOBAL ... END_VAR construct is allowed mjsousa@862: * in each CONFIGURATION or RESOURCE declaration. If the user wishes to have global mjsousa@862: * variables with distinct properties (e.g. some with RETAIN, others with CONSTANT, mjsousa@862: * and yet other variables with none of these qualifiers), the syntax defined in the mjsousa@862: * standard does not allow this. mjsousa@862: * Amazingly, IEC 61131-3 v3 also does not seem to allow it either!! mjsousa@862: * Since this is most likely a bug in the standard, we are changing the syntax slightly mjsousa@862: * to become: mjsousa@862: * 'CONFIGURATION' configuration_name {global_var_declarations} ... mjsousa@862: * mjsousa@862: * Remember that: mjsousa@862: * {S}, closure, meaning zero or more concatenations of S. mjsousa@862: * [S], option, meaning zero or one occurrence of S. mjsousa@862: */ mjsousa@862: global_var_declarations_list: etisserant@0: // empty mjsousa@862: {$$ = new global_var_declarations_list_c(locloc(@$));} mjsousa@862: | global_var_declarations_list global_var_declarations mjsousa@862: {$$ = $1; $$->add_element($2);} mjsousa@862: ; 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 mario@68: {$$ = new resource_declaration_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | resource_declaration_list resource_declaration etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | resource_declaration_list error lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected token after resource declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: resource_declaration: msousa@811: RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} resource_name {variable_name_symtable.insert($3, prev_declared_resource_name_token);} ON resource_type_name mjsousa@862: global_var_declarations_list etisserant@0: single_resource_declaration etisserant@0: END_RESOURCE msousa@811: {$$ = new resource_declaration_c($3, $6, $7, $8, locloc(@$)); mario@13: variable_name_symtable.pop(); lbessard@175: direct_variable_symtable.pop(); etisserant@0: variable_name_symtable.insert($3, prev_declared_resource_name_token); etisserant@0: } lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@175: | RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} ON resource_type_name mjsousa@862: global_var_declarations_list lbessard@131: single_resource_declaration lbessard@131: END_RESOURCE lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@3), "no resource name defined in resource declaration."); yynerrs++;} lbessard@175: /*| RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} resource_name ON resource_type_name mjsousa@862: global_var_declarations_list lbessard@136: single_resource_declaration lbessard@136: END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@5), "unclosed resource declaration."); yyerrok;}*/ lbessard@131: | RESOURCE error END_RESOURCE lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in resource declaration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: single_resource_declaration: etisserant@0: task_configuration_list program_configuration_list mario@68: {$$ = new single_resource_declaration_c($1, $2, locloc(@$));} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: // helper symbol for single_resource_declaration // etisserant@0: task_configuration_list: etisserant@0: // empty mario@68: {$$ = new task_configuration_list_c(locloc(@$));} etisserant@0: | task_configuration_list task_configuration ';' etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | task_configuration_list task_configuration error lbessard@136: {$$ = $1; print_err_msg(locl(@1), locf(@2), "';' missing at the end of task configuration in resource declaration."); yyerrok;} lbessard@131: | task_configuration_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after task configuration in resource declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: // helper symbol for single_resource_declaration // etisserant@0: program_configuration_list: etisserant@0: program_configuration ';' mario@68: {$$ = new program_configuration_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | program_configuration_list program_configuration ';' etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | program_configuration error lbessard@136: {$$ = new program_configuration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at the end of program configuration in resource declaration."); yyerrok;} lbessard@131: | program_configuration_list program_configuration error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of program configuration in resource declaration."); yyerrok;} lbessard@133: | program_configuration_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid program configuration in resource declaration."); yyerrok;} lbessard@131: | program_configuration_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after program configuration in resource declaration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ 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;} lbessard@131: // ERROR_CHECK_BEGIN // lbessard@131: | VAR_ACCESS END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in access variable(s) declaration."); yynerrs++;} lbessard@131: | VAR_ACCESS error access_declaration_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_ACCESS' in access variable(s) declaration."); yyerrok;} lbessard@136: | VAR_ACCESS access_declaration_list error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed access variable(s) declaration."); yyerrok;} lbessard@131: | VAR_ACCESS error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in access variable(s) declaration."); yyerrok;} lbessard@131: // ERROR_CHECK_END // 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 ';' lbessard@131: // ERROR_CHECK_BEGIN // lbessard@134: | error ';' lbessard@134: {$$ = // create a new list //; lbessard@136: print_err_msg(locf(@1), locl(@1), "invalid access variable declaration."); yyerrok;} lbessard@131: | access_declaration error lbessard@134: {$$ = // create a new list //; lbessard@136: print_err_msg(locl(@1), locf(@2), "';' missing at the end of access variable declaration."); yyerrok;} lbessard@131: | access_declaration_list access_declaration error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of access variable declaration."); yyerrok;} lbessard@133: | access_declaration_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid access variable declaration."); yyerrok;} lbessard@131: | access_declaration_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after access variable declaration."); yynerrs++;} lbessard@131: // ERROR_CHECK_END // 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: lbessard@175: prev_declared_direct_variable lbessard@175: | prev_declared_resource_name '.' prev_declared_direct_variable etisserant@0: | any_fb_name_list symbolic_variable lbessard@131: | prev_declared_resource_name '.' any_fb_name_list symbolic_variable lbessard@131: | prev_declared_program_name '.' any_fb_name_list symbolic_variable lbessard@131: | prev_declared_resource_name '.' prev_declared_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 mario@68: {$$ = new any_fb_name_list_c(locloc(@$));} 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 mario@68: {$$ = new global_var_reference_c(NULL, $1, NULL, locloc(@$));} etisserant@0: | prev_declared_global_var_name '.' structure_element_name mario@68: {$$ = new global_var_reference_c(NULL, $1, $3, locloc(@$));} etisserant@0: | prev_declared_resource_name '.' prev_declared_global_var_name mario@68: {$$ = new global_var_reference_c($1, $3, NULL, locloc(@$));} etisserant@0: | prev_declared_resource_name '.' prev_declared_global_var_name '.' structure_element_name mario@68: {$$ = new global_var_reference_c($1, $3, $5, locloc(@$));} 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 mario@68: {$$ = new program_output_reference_c($1, $3, locloc(@$));} 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 mario@68: {$$ = new task_configuration_c($2, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | TASK task_initialization lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no task name defined in task declaration."); yynerrs++;} lbessard@131: | TASK error task_initialization lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid task name defined in task declaration."); yyerrok;} lbessard@131: | TASK task_name error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no task initialization defined in task declaration.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid task initialization in task declaration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: mario@75: /* NOTE: The specification does not 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: mario@74: etisserant@0: task_initialization: etisserant@0: // '(' [SINGLE ASSIGN data_source ','] [INTERVAL ASSIGN data_source ','] PRIORITY ASSIGN integer ')' // mario@75: '(' {cmd_goto_task_init_state();} task_initialization_single task_initialization_interval task_initialization_priority ')' mario@75: {$$ = new task_initialization_c($3, $4, $5, locloc(@$));} mario@74: ; mario@74: mario@74: mario@74: task_initialization_single: mario@74: // [SINGLE ASSIGN data_source ','] mario@74: /* empty */ mario@74: {$$ = NULL;} mario@75: | SINGLE ASSIGN {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} mario@75: {$$ = $4;} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | SINGLE {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@3), "':=' missing after 'SINGLE' in task initialization."); yynerrs++;} lbessard@131: | SINGLE ASSIGN {cmd_pop_state();} ',' {cmd_goto_task_init_state();} lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@4), "no data source defined in 'SINGLE' statement of task initialization."); yynerrs++;} lbessard@131: | SINGLE ASSIGN {cmd_pop_state();} error ',' {cmd_goto_task_init_state();} lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid data source defined in 'SINGLE' statement of task initialization."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ mario@74: ; mario@74: mario@74: mario@74: task_initialization_interval: mario@74: // [INTERVAL ASSIGN data_source ','] mario@74: /* empty */ mario@74: {$$ = NULL;} mario@75: | INTERVAL ASSIGN {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} mario@75: {$$ = $4;} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | INTERVAL {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@3), "':=' missing after 'INTERVAL' in task initialization.");} lbessard@131: | INTERVAL ASSIGN {cmd_pop_state();} ',' {cmd_goto_task_init_state();} lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@4), "no data source defined in 'INTERVAL' statement of task initialization."); yynerrs++;} lbessard@131: | INTERVAL ASSIGN {cmd_pop_state();} error ',' {cmd_goto_task_init_state();} lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid data source defined in 'INTERVAL' statement of task initialization."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ mario@75: ; mario@75: mario@74: mario@74: mario@74: task_initialization_priority: mario@74: // PRIORITY ASSIGN integer mario@75: PRIORITY ASSIGN {cmd_pop_state();} integer mario@75: {$$ = $4;} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | PRIORITY {cmd_pop_state();} integer lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@3), "':=' missing after 'PRIORITY' in task initialization."); yynerrs++;} lbessard@131: | PRIORITY ASSIGN {cmd_pop_state();} error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@4), "no priority number defined in 'PRIORITY' statement of task initialization.");} lbessard@136: else {print_err_msg(locf(@4), locl(@4), "invalid priority number in 'PRIORITY' statement of task initialization."); yyclearin;} lbessard@134: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ mario@75: ; mario@75: mario@74: etisserant@0: etisserant@0: data_source: etisserant@0: constant etisserant@0: | global_var_reference etisserant@0: | program_output_reference lbessard@175: | prev_declared_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 mario@68: {$$ = new program_configuration_c(NULL, $2, $3, $5, $6, locloc(@$)); 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 mario@68: {$$ = new program_configuration_c(new retain_option_c(locloc(@2)), $3, $4, $6, $7, locloc(@$)); 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 mario@68: {$$ = new program_configuration_c(new non_retain_option_c(locloc(@2)), $3, $4, $6, $7, locloc(@$)); etisserant@0: variable_name_symtable.insert($3, prev_declared_program_name_token); etisserant@0: } lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | PROGRAM program_name optional_task_name ':' identifier optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locf(@5), locl(@5), "invalid program type name after ':' in program configuration."); yynerrs++;} lbessard@131: | PROGRAM RETAIN program_name optional_task_name ':' identifier optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid program type name after ':' in program configuration."); yynerrs++;} lbessard@131: | PROGRAM NON_RETAIN program_name optional_task_name ':' identifier optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid program type name after ':' in program configuration."); yynerrs++;} lbessard@131: | PROGRAM error program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'PROGRAM' in program configuration."); yyerrok;} lbessard@131: | PROGRAM RETAIN error program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive program configuration."); yyerrok;} lbessard@131: | PROGRAM NON_RETAIN error program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive program configuration."); yyerrok;} lbessard@131: | PROGRAM optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no program name defined in program configuration."); yynerrs++;} lbessard@131: | PROGRAM RETAIN optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no program name defined in retentive program configuration."); yynerrs++;} lbessard@131: | PROGRAM NON_RETAIN optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no program name defined in non-retentive program configuration."); yynerrs++;} lbessard@131: | PROGRAM error optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid program name defined in program configuration."); yyerrok;} lbessard@131: | PROGRAM RETAIN error optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid program name defined in retentive program configuration."); yyerrok;} lbessard@131: | PROGRAM NON_RETAIN error optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid program name defined in non-retentive program configuration."); yyerrok;} lbessard@131: | PROGRAM program_name optional_task_name prev_declared_program_type_name optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "':' missing after program name or optional task name in program configuration."); yynerrs++;} lbessard@131: | PROGRAM RETAIN program_name optional_task_name prev_declared_program_type_name optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':' missing after program name or optional task name in retentive program configuration."); yynerrs++;} lbessard@131: | PROGRAM NON_RETAIN program_name optional_task_name prev_declared_program_type_name optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':' missing after program name or optional task name in non-retentive program configuration."); yynerrs++;} lbessard@131: | PROGRAM program_name optional_task_name ':' optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no program type defined in program configuration."); yynerrs++;} lbessard@131: | PROGRAM RETAIN program_name optional_task_name ':' optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locl(@5), locf(@6), "no program type defined in retentive program configuration."); yynerrs++;} lbessard@131: | PROGRAM NON_RETAIN program_name optional_task_name ':' optional_prog_conf_elements lbessard@136: {$$ = NULL; print_err_msg(locl(@5), locf(@6), "no program type defined in non-retentive program configuration."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ 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;} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | WITH error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no task name defined in optional task name of program configuration.");} lbessard@136: else {print_err_msg(locf(@2), locl(@2), "invalid task name in optional task name of program configuration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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;} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | '(' error ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid program configuration elements in program configuration."); yyerrok;} lbessard@131: | '(' prog_conf_elements error lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of program configuration elements in program configuration."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: prog_conf_elements: etisserant@0: prog_conf_element mario@68: {$$ = new prog_conf_elements_c(locloc(@$)); $$->add_element($1);} etisserant@0: | prog_conf_elements ',' prog_conf_element etisserant@0: {$$ = $1; $$->add_element($3);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | prog_conf_elements prog_conf_element lbessard@136: {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in program configuration elements list."); yynerrs++;} lbessard@131: | prog_conf_elements ',' error lbessard@136: {$$ = $1; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for program configuration element in program configuration list.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid value for program configuration element in program configuration list."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new fb_task_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | any_identifier WITH error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no task name defined in function block configuration.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid task name in function block configuration."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new prog_cnxn_assign_c($1, $3, locloc(@$));} etisserant@0: | any_symbolic_variable SENDTO data_sink mario@68: {$$ = new prog_cnxn_sendto_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | any_symbolic_variable constant lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing between parameter and value in program configuration element."); yynerrs++;} lbessard@131: | any_symbolic_variable enumerated_value lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing between parameter and value in program configuration element."); yynerrs++;} lbessard@131: | any_symbolic_variable data_sink lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' or '=>' missing between parameter and variable in program configuration element."); yynerrs++;} lbessard@131: | any_symbolic_variable ASSIGN error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value or variable defined in program configuration assignment element.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid value or variable in program configuration assignment element."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | any_symbolic_variable SENDTO error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no variable defined in program configuration sendto element.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid variable in program configuration sendto element."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: prog_data_source: etisserant@0: constant etisserant@0: | enumerated_value etisserant@0: | global_var_reference lbessard@175: | prev_declared_direct_variable etisserant@0: ; etisserant@0: etisserant@0: data_sink: etisserant@0: global_var_reference lbessard@175: | prev_declared_direct_variable etisserant@0: ; etisserant@0: etisserant@0: instance_specific_initializations: etisserant@0: VAR_CONFIG instance_specific_init_list END_VAR mario@68: {$$ = new instance_specific_initializations_c($2, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | VAR_CONFIG END_VAR lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in configuration variable(s) initialization."); yynerrs++;} lbessard@131: | VAR_CONFIG error instance_specific_init_list END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_CONFIG' in configuration variable(s) initialization."); yyerrok;} lbessard@136: | VAR_CONFIG instance_specific_init_list error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed configuration variable(s) initialization."); yyerrok;} lbessard@131: | VAR_CONFIG error END_VAR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in configuration variable(s) initialization."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: // helper symbol for instance_specific_initializations // etisserant@0: instance_specific_init_list: etisserant@0: instance_specific_init ';' mario@68: {$$ = new instance_specific_init_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | instance_specific_init_list instance_specific_init ';' etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@134: | error ';' lbessard@136: {$$ = new instance_specific_init_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid configuration variable initialization."); yyerrok;} lbessard@131: | instance_specific_init error lbessard@136: {$$ = new instance_specific_init_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at the end of configuration variable initialization."); yyerrok;} lbessard@131: | instance_specific_init_list instance_specific_init error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of configuration variable initialization."); yyerrok;} lbessard@133: | instance_specific_init_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid configuration variable initialization."); yyerrok;} lbessard@131: | instance_specific_init_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after configuration variable initialization."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new instance_specific_init_c($1, $3, $5, $6, NULL, $8, locloc(@$));} etisserant@0: | prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier location ':' located_var_spec_init mario@68: {$$ = new instance_specific_init_c($1, $3, $5, $6, $7, $9, locloc(@$));} etisserant@0: | prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier ':' fb_initialization mario@68: {$5->add_element($6); $$ = new instance_specific_init_c($1, $3, $5, NULL, NULL, $8, locloc(@$));} 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 mario@68: {$$ = new fb_initialization_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | function_block_type_name structure_initialization lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing between function block name and initialization in function block initialization."); yynerrs++;} lbessard@136: | function_block_type_name ASSIGN error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in function block initialization.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid initial value in function block initialization."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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: mario@94: etisserant@0: etisserant@0: instruction_list: etisserant@0: il_instruction mario@68: {$$ = new instruction_list_c(locloc(@$)); $$->add_element($1);} msousa@267: | any_pragma eol_list msousa@520: {$$ = new instruction_list_c(locloc(@1)); $$->add_element($1);} /* locloc(@1) is not a bug! We ignore trailing EOLs when determining symbol location! */ etisserant@0: | instruction_list il_instruction etisserant@0: {$$ = $1; $$->add_element($2);} msousa@267: | instruction_list any_pragma etisserant@0: {$$ = $1; $$->add_element($2);} mario@68: ; mario@68: mario@68: mario@68: mario@68: il_instruction: mario@68: il_incomplete_instruction eol_list msousa@520: {$$ = new il_instruction_c(NULL, $1, locloc(@1));} /* locloc(@1) is not a bug! We ignore trailing EOLs when determining symbol location! */ mario@68: | label ':' il_incomplete_instruction eol_list msousa@520: {$$ = new il_instruction_c($1, $3, locf(@1), locl(@3));} /* locf(@1), locl(@3) is not a bug! We ignore trailing EOLs when determining symbol location! */ msousa@311: | label ':' eol_list msousa@520: {$$ = new il_instruction_c($1, NULL, locf(@1), locl(@2));} /* locf(@1), locl(@2) is not a bug! We ignore trailing EOLs when determining symbol location! */ mario@68: /* ERROR_CHECK_BEGIN */ mario@68: | error eol_list lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid IL instruction."); yyerrok;} lbessard@131: | il_incomplete_instruction error lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing at the end of IL instruction."); yyerrok;} lbessard@131: | error ':' il_incomplete_instruction eol_list lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid label in IL instruction."); yyerrok;} lbessard@131: | label il_incomplete_instruction eol_list lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after label in IL instruction."); yynerrs++;} mario@68: | label ':' error eol_list lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid IL instruction."); yyerrok;} lbessard@131: | label ':' il_incomplete_instruction error lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "EOL missing at the end of IL instruction."); yyerrok;} mario@68: /* ERROR_CHECK_END */ 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: mario@94: // (il_simple_operator [il_operand]) | (function_name [il_operand_list]) etisserant@0: il_simple_operator mario@68: {$$ = new il_simple_operation_c($1, NULL, locloc(@$));} mario@93: /* mario@93: * Note: Bison is getting confused with the following rule, mario@94: * i.e. it is finding conflicts where there seemingly are really none. mario@93: * The rule was therefore replaced by the equivalent following mario@93: * two rules. mario@93: */ mario@93: /* mario@93: | il_simple_operator il_operand mario@93: {$$ = new il_simple_operation_c($1, $2, locloc(@$));} mario@93: */ etisserant@0: | il_simple_operator_noclash il_operand mario@68: {$$ = new il_simple_operation_c($1, $2, locloc(@$));} mario@91: | il_simple_operator_clash il_operand mario@91: {$$ = new il_simple_operation_c($1, $2, locloc(@$));} 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 mario@89: * function call. mario@89: * mario@89: * I (Mario) have chosen to reduce it to an operator. mario@68: * In order to do this, we must remove from the syntax that defines mario@68: * function calls all the functions whose names clash with the IL operators. mario@68: * 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 mjsousa@958: {$$ = new il_function_call_c($1, NULL, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c etisserant@0: /* NOTE: the line etisserant@0: * | il_simple_operator il_operand mario@68: * already contains the 'NOT', 'MOD', etc. operators, followed by a single il_operand. mario@68: * However, this same code (MOD x) may also be reduced to a function call to the MOD mario@68: * function. This means that (MOD, AND,...) could be interpret as a function name mario@68: * or as an IL operator! This would lead us to a reduce/reduce conflict! mario@68: * mario@89: * I (Mario) have chosen to reduce it to an operand, rather than a function call. mario@68: * In order to do this, we must remove from the syntax that defines mario@68: * function calls all the functions whose names clash with the IL operators. 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 mario@68: * the function 'NOT', 'MOD', etc... being called with more than one il_operand, mario@68: * in which case it is always a function call, and not an IL instruction. 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 mjsousa@958: {$$ = new il_function_call_c($1, $2, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c mario@91: | il_simple_operator_clash il_operand_list2 mjsousa@958: {$$ = new il_function_call_c(il_operator_c_2_poutype_identifier_c($1), $2, locloc(@$));} mario@93: ; mario@93: mario@91: etisserant@0: etisserant@0: il_expression: mario@94: // il_expr_operator '(' [il_operand] EOL {EOL} [simple_instr_list] ')' msousa@690: /* IMPORTANT NOTE: msousa@690: * When the exists, and to make it easier to handle the as a general case (i.e. without C++ code handling this as a special case), msousa@690: * we will create an equivalent LD IL instruction, and prepend it into the . msousa@690: * The remainder of the compiler may from now on assume that the code being compiled does not contain any IL code like msousa@690: * LD 1 msousa@690: * ADD ( 2 msousa@690: * SUB 3 msousa@690: * ) msousa@690: * msousa@690: * but instead, the equivalent code msousa@690: * LD 1 msousa@690: * ADD ( msousa@690: * LD 2 msousa@690: * SUB 3 msousa@690: * ) msousa@690: * msousa@690: * Note, however, that in the first case, we still store in the il_expression_c a pointer to the (the literal '2' in the above example), in case msousa@690: * somewhere further on in the compiler we really want to handle it as a special case. To handle it as a special case, it should be easy to simply delete the first msousa@690: * artificial entry in with il_expression->simple_instr_list->remove_element(0) !! msousa@690: */ mario@94: /* mario@94: * Note: Bison is getting confused with the use of il_expr_operator, mario@94: * i.e. it is finding conflicts where there seemingly are really none. mario@94: * il_expr_operator was therefore replaced by the equivalent mario@94: * il_expr_operator_noclash | il_expr_operator_clash. mario@94: */ etisserant@0: il_expr_operator_noclash '(' eol_list ')' mario@68: {$$ = new il_expression_c($1, NULL, NULL, locloc(@$));} etisserant@0: | il_expr_operator_noclash '(' il_operand eol_list ')' msousa@690: { simple_instr_list_c *tmp_simple_instr_list = new simple_instr_list_c(locloc(@3)); msousa@690: tmp_simple_instr_list ->insert_element(new il_simple_instruction_c(new il_simple_operation_c(new LD_operator_c(locloc(@3)), $3, locloc(@3)), locloc(@3)), 0); msousa@690: $$ = new il_expression_c($1, $3, tmp_simple_instr_list, locloc(@$)); msousa@690: } etisserant@0: | il_expr_operator_noclash '(' eol_list simple_instr_list ')' mario@68: {$$ = new il_expression_c($1, NULL, $4, locloc(@$));} etisserant@0: | il_expr_operator_noclash '(' il_operand eol_list simple_instr_list ')' msousa@690: { simple_instr_list_c *tmp_simple_instr_list = dynamic_cast $5; msousa@690: tmp_simple_instr_list ->insert_element(new il_simple_instruction_c(new il_simple_operation_c(new LD_operator_c(locloc(@3)), $3, locloc(@3)), locloc(@3)), 0); msousa@690: $$ = new il_expression_c($1, $3, $5, locloc(@$)); msousa@690: } etisserant@0: | il_expr_operator_clash '(' eol_list ')' mario@68: {$$ = new il_expression_c($1, NULL, NULL, locloc(@$));} etisserant@0: | il_expr_operator_clash '(' il_operand eol_list ')' msousa@690: { simple_instr_list_c *tmp_simple_instr_list = new simple_instr_list_c(locloc(@3)); msousa@690: tmp_simple_instr_list ->insert_element(new il_simple_instruction_c(new il_simple_operation_c(new LD_operator_c(locloc(@3)), $3, locloc(@3)), locloc(@3)), 0); msousa@690: $$ = new il_expression_c($1, $3, tmp_simple_instr_list, locloc(@$)); msousa@690: } etisserant@0: | il_expr_operator_clash '(' il_operand eol_list simple_instr_list ')' msousa@690: { simple_instr_list_c *tmp_simple_instr_list = dynamic_cast $5; msousa@690: tmp_simple_instr_list ->insert_element(new il_simple_instruction_c(new il_simple_operation_c(new LD_operator_c(locloc(@3)), $3, locloc(@3)), locloc(@3)), 0); msousa@690: $$ = new il_expression_c($1, $3, $5, locloc(@$)); msousa@690: } etisserant@0: | il_expr_operator_clash_eol_list simple_instr_list ')' mario@68: {$$ = new il_expression_c($1, NULL, $2, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | il_expr_operator_noclash '(' eol_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of IL expression."); yyerrok;} lbessard@131: | il_expr_operator_noclash '(' il_operand eol_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL expression."); yyerrok;} lbessard@131: | il_expr_operator_noclash '(' eol_list simple_instr_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL expression."); yyerrok;} lbessard@131: | il_expr_operator_noclash '(' il_operand eol_list simple_instr_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@5), locf(@6), "')' missing at the end of IL expression."); yyerrok;} lbessard@131: | il_expr_operator_clash '(' il_operand eol_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL expression."); yyerrok;} lbessard@131: | il_expr_operator_clash '(' il_operand eol_list simple_instr_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@5), locf(@6), "')' missing at the end of IL expression."); yyerrok;} lbessard@131: | il_expr_operator_clash_eol_list simple_instr_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of IL expression."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_jump_operation: etisserant@0: il_jump_operator label mario@68: {$$ = new il_jump_operation_c($1, $2, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | il_jump_operator error lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid label defined in IL jump operation."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_fb_call: mario@94: // il_call_operator fb_name ['(' (EOL {EOL} [il_param_list]) | [il_operand_list] ')'] etisserant@0: il_call_operator prev_declared_fb_name mario@68: {$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));} etisserant@0: | il_call_operator prev_declared_fb_name '(' ')' mario@68: {$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));} etisserant@0: | il_call_operator prev_declared_fb_name '(' eol_list ')' mario@68: {$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));} etisserant@0: | il_call_operator prev_declared_fb_name '(' il_operand_list ')' mario@68: {$$ = new il_fb_call_c($1, $2, $4, NULL, locloc(@$));} etisserant@0: | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')' mario@68: {$$ = new il_fb_call_c($1, $2, NULL, $5, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | il_call_operator error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call.");} lbessard@136: else {print_err_msg(locf(@2), locl(@2), "invalid function block name in IL function block call."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | il_call_operator '(' ')' lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} lbessard@131: | il_call_operator '(' eol_list ')' lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} lbessard@131: | il_call_operator '(' il_operand_list ')' lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} lbessard@131: | il_call_operator '(' eol_list il_param_list ')' lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} lbessard@131: | il_call_operator error '(' ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} lbessard@131: | il_call_operator error '(' eol_list ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} lbessard@131: | il_call_operator error '(' il_operand_list ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} lbessard@131: | il_call_operator error '(' eol_list il_param_list ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} lbessard@131: | il_call_operator prev_declared_fb_name ')' lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'(' missing after function block name defined in IL function block call."); yynerrs++;} lbessard@131: | il_call_operator prev_declared_fb_name il_operand_list ')' lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'(' missing after function block name defined in IL function block call."); yynerrs++;} lbessard@131: | il_call_operator prev_declared_fb_name '(' error lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of IL function block call."); yyerrok;} lbessard@131: | il_call_operator prev_declared_fb_name '(' eol_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL function block call."); yyerrok;} lbessard@131: | il_call_operator prev_declared_fb_name '(' il_operand_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL function block call."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ 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: mario@94: // function_name '(' EOL {EOL} [il_param_list] ')' 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! mario@68: * (AND MOD OR XOR ADD DIV EQ GT GE LT LE MUL NE SUB) etisserant@0: */ etisserant@0: function_name_no_clashes '(' eol_list ')' mjsousa@958: {$$ = new il_formal_funct_call_c($1, NULL, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c etisserant@0: | function_name_simpleop_clashes '(' eol_list ')' mjsousa@958: {$$ = new il_formal_funct_call_c($1, NULL, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c etisserant@0: /* | function_name '(' eol_list il_param_list ')' */ mario@68: /* For the above syntax, we no longer have two ways of interpreting the mario@68: * same syntax. The above is always a function call! mario@68: * However, some of the functions that we may be calling mario@68: * may have the same name as an IL operator. This means that mario@68: * flex will be parsing them and handing them over to bison as mario@68: * IL operator tokens, and not as function name tokens. mario@68: * (when parsing ST, flex no longer recognizes IL operators, mario@68: * so will always return the correct function name, unless that mario@68: * name also coincides with an operator used in ST -> XOR, OR, MOD, AND, NOT) mario@68: * mario@68: * We must therefore interpret the IL operators as function names! mario@68: */ etisserant@0: | function_name_no_clashes '(' eol_list il_param_list ')' mjsousa@958: {$$ = new il_formal_funct_call_c($1, $4, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c etisserant@0: | function_name_simpleop_clashes '(' eol_list il_param_list ')' mjsousa@958: {$$ = new il_formal_funct_call_c($1, $4, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c mario@68: /* The following line should read: mario@68: * mario@68: * | function_name_expression_clashes '(' eol_list il_param_list ')' mario@68: * mario@68: * but 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 mjsousa@958: * at the end of this file... il_operator_c_2_poutype_identifier_c() etisserant@0: */ etisserant@0: | il_expr_operator_clash_eol_list il_param_list ')' mjsousa@958: {$$ = new il_formal_funct_call_c(il_operator_c_2_poutype_identifier_c($1), $2, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | function_name_no_clashes '(' eol_list error ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid parameter list defined in IL formal function call."); yyerrok;} lbessard@131: | function_name_simpleop_clashes '(' eol_list error ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid parameter list defined in IL formal function call."); yyerrok;} lbessard@131: | il_expr_operator_clash_eol_list error ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid parameter list defined in IL formal function call."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ 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;} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | il_expr_operator_clash '(' error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "EOL missing after '(' in IL instruction."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_operand: etisserant@0: variable mario@85: | enumerated_value etisserant@0: | constant etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_operand_list: etisserant@0: il_operand mario@68: {$$ = new il_operand_list_c(locloc(@$)); $$->add_element($1);} mario@91: | il_operand_list2 mario@91: ; mario@91: mario@91: mario@91: /* List with 2 or more il_operands */ mario@91: il_operand_list2: mario@91: il_operand ',' il_operand mario@91: {$$ = new il_operand_list_c(locloc(@$)); $$->add_element($1); $$->add_element($3);} mario@91: | il_operand_list2 ',' il_operand etisserant@0: {$$ = $1; $$->add_element($3);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | il_operand_list2 il_operand lbessard@136: {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in IL operand list."); yynerrs++;} lbessard@136: | il_operand ',' error lbessard@136: {$$ = new il_operand_list_c(locloc(@$)); lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no operand defined in IL operand list.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid operand name in IL operand list."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: simple_instr_list: etisserant@0: il_simple_instruction mario@68: {$$ = new simple_instr_list_c(locloc(@$)); $$->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 msousa@520: {$$ = new il_simple_instruction_c($1, locloc(@1));} /* locloc(@1) is not a bug! We ignore trailing EOLs when determining symbol location! */ etisserant@0: | il_expression eol_list msousa@520: {$$ = new il_simple_instruction_c($1, locloc(@1));} /* locloc(@1) is not a bug! We ignore trailing EOLs when determining symbol location! */ etisserant@0: | il_formal_funct_call eol_list msousa@520: {$$ = new il_simple_instruction_c($1, locloc(@1));} /* locloc(@1) is not a bug! We ignore trailing EOLs when determining symbol location! */ lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | il_expression error lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing after expression IL instruction."); yyerrok;} lbessard@131: | il_formal_funct_call error lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing after formal function call IL instruction."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new il_param_list_c(locloc(@$)); $$->add_element($1);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | il_param_instruction_list error lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid parameter assignment in parameter assignment list."); yyerrok;} lbessard@131: | il_param_last_instruction il_param_last_instruction lbessard@136: {$$ = new il_param_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "',' missing at the end of parameter assignment in parameter assignment list."); yynerrs++;} lbessard@131: | il_param_instruction_list il_param_last_instruction il_param_last_instruction lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "',' missing at the end of parameter assignment in parameter assignment list."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new il_param_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | il_param_instruction_list il_param_instruction etisserant@0: {$$ = $1; $$->add_element($2);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | il_param_last_instruction il_param_instruction lbessard@136: {$$ = new il_param_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "',' missing at the end of parameter assignment in parameter assignment list."); yynerrs++;} lbessard@131: | il_param_instruction_list il_param_last_instruction il_param_instruction lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "',' missing at the end of parameter assignment in parameter assignment list."); yynerrs++;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_param_instruction: msousa@257: il_param_assignment ',' eol_list etisserant@0: | il_param_out_assignment ',' eol_list lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | il_param_assignment ',' error lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "EOL missing at the end of parameter assignment in parameter assignment list."); yyerrok;} lbessard@131: | il_param_out_assignment ',' error lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "EOL missing at the end of parameter out assignment in parameter assignment list."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ 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 lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | il_param_assignment error lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing at the end of last parameter assignment in parameter assignment list."); yyerrok;} lbessard@131: | il_param_out_assignment error lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing at the end of last parameter out assignment in parameter assignment list."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ lbessard@131: etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_param_assignment: etisserant@0: il_assign_operator il_operand mario@68: {$$ = new il_param_assignment_c($1, $2, NULL, locloc(@$));} etisserant@0: | il_assign_operator '(' eol_list simple_instr_list ')' mario@68: {$$ = new il_param_assignment_c($1, NULL, $4, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | error il_operand lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid operator in parameter assignment."); yyerrok;} lbessard@131: | error '(' eol_list simple_instr_list ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid operator in parameter assignment."); yyerrok;} lbessard@131: | il_assign_operator error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no operand defined in parameter assignment.");} lbessard@136: else {print_err_msg(locf(@2), locl(@2), "invalid operand in parameter assignment."); yyclearin;} lbessard@134: yyerrok; lbessard@134: } lbessard@134: | il_assign_operator '(' eol_list ')' lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no instruction list defined in parameter assignment."); yynerrs++;} lbessard@134: | il_assign_operator '(' eol_list error ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid instruction list defined in parameter assignment."); yyerrok;} lbessard@131: | il_assign_operator '(' eol_list simple_instr_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of instruction list defined in parameter assignment."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: il_param_out_assignment: etisserant@0: il_assign_out_operator variable mario@68: {$$ = new il_param_out_assignment_c($1, $2, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | il_assign_out_operator error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no variable defined in IL operand list.");} lbessard@136: else {print_err_msg(locf(@2), locl(@2), "invalid variable in IL operand list."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /*******************/ etisserant@0: /* B 2.2 Operators */ etisserant@0: /*******************/ mario@68: sendto_identifier: sendto_identifier_token {$$ = new identifier_c($1, locloc(@$));}; 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: */ mario@68: LD_operator: LD {$$ = new LD_operator_c(locloc(@$));}; mario@68: LDN_operator: LDN {$$ = new LDN_operator_c(locloc(@$));}; mario@68: ST_operator: ST {$$ = new ST_operator_c(locloc(@$));}; mario@68: STN_operator: STN {$$ = new STN_operator_c(locloc(@$));}; mario@68: NOT_operator: NOT {$$ = new NOT_operator_c(locloc(@$));}; mario@68: S_operator: S {$$ = new S_operator_c(locloc(@$));}; mario@68: R_operator: R {$$ = new R_operator_c(locloc(@$));}; mario@68: S1_operator: S1 {$$ = new S1_operator_c(locloc(@$));}; mario@68: R1_operator: R1 {$$ = new R1_operator_c(locloc(@$));}; mario@68: CLK_operator: CLK {$$ = new CLK_operator_c(locloc(@$));}; mario@68: CU_operator: CU {$$ = new CU_operator_c(locloc(@$));}; mario@68: CD_operator: CD {$$ = new CD_operator_c(locloc(@$));}; mario@68: PV_operator: PV {$$ = new PV_operator_c(locloc(@$));}; mario@68: IN_operator: IN {$$ = new IN_operator_c(locloc(@$));}; mario@68: PT_operator: PT {$$ = new PT_operator_c(locloc(@$));}; mario@68: AND_operator: AND {$$ = new AND_operator_c(locloc(@$));}; mario@68: AND2_operator: AND2 {$$ = new AND_operator_c(locloc(@$));}; /* '&' in the source code! */ mario@68: OR_operator: OR {$$ = new OR_operator_c(locloc(@$));}; mario@68: XOR_operator: XOR {$$ = new XOR_operator_c(locloc(@$));}; mario@68: ANDN_operator: ANDN {$$ = new ANDN_operator_c(locloc(@$));}; mario@68: ANDN2_operator: ANDN2 {$$ = new ANDN_operator_c(locloc(@$));}; /* '&N' in the source code! */ mario@68: ORN_operator: ORN {$$ = new ORN_operator_c(locloc(@$));}; mario@68: XORN_operator: XORN {$$ = new XORN_operator_c(locloc(@$));}; mario@68: ADD_operator: ADD {$$ = new ADD_operator_c(locloc(@$));}; mario@68: SUB_operator: SUB {$$ = new SUB_operator_c(locloc(@$));}; mario@68: MUL_operator: MUL {$$ = new MUL_operator_c(locloc(@$));}; mario@68: DIV_operator: DIV {$$ = new DIV_operator_c(locloc(@$));}; mario@68: MOD_operator: MOD {$$ = new MOD_operator_c(locloc(@$));}; mario@68: GT_operator: GT {$$ = new GT_operator_c(locloc(@$));}; mario@68: GE_operator: GE {$$ = new GE_operator_c(locloc(@$));}; mario@68: EQ_operator: EQ {$$ = new EQ_operator_c(locloc(@$));}; mario@68: LT_operator: LT {$$ = new LT_operator_c(locloc(@$));}; mario@68: LE_operator: LE {$$ = new LE_operator_c(locloc(@$));}; mario@68: NE_operator: NE {$$ = new NE_operator_c(locloc(@$));}; mario@68: CAL_operator: CAL {$$ = new CAL_operator_c(locloc(@$));}; mario@68: CALC_operator: CALC {$$ = new CALC_operator_c(locloc(@$));}; mario@68: CALCN_operator: CALCN {$$ = new CALCN_operator_c(locloc(@$));}; mario@68: RET_operator: RET {$$ = new RET_operator_c(locloc(@$));}; mario@68: RETC_operator: RETC {$$ = new RETC_operator_c(locloc(@$));}; mario@68: RETCN_operator: RETCN {$$ = new RETCN_operator_c(locloc(@$));}; mario@68: JMP_operator: JMP {$$ = new JMP_operator_c(locloc(@$));}; mario@68: JMPC_operator: JMPC {$$ = new JMPC_operator_c(locloc(@$));}; mario@68: JMPCN_operator: JMPCN {$$ = new JMPCN_operator_c(locloc(@$));}; 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: laurent@382: LDN_operator etisserant@0: | ST_operator etisserant@0: | STN_operator laurent@382: | il_expr_operator_noclash laurent@382: ; laurent@382: laurent@382: laurent@382: il_simple_operator_clash: laurent@382: il_simple_operator_clash1 laurent@382: | il_simple_operator_clash2 laurent@382: | il_simple_operator_clash3 laurent@382: ; laurent@382: laurent@382: il_simple_operator_clash1: laurent@382: NOT_operator laurent@382: ; laurent@382: laurent@382: il_simple_operator_clash2: laurent@382: il_expr_operator_clash laurent@382: ; laurent@382: laurent@382: il_simple_operator_clash3: laurent@382: LD_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 laurent@382: ; 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 lbessard@143: {$$ = new il_assign_operator_c($1, locloc(@$));} ccb@202: | en_identifier ASSIGN lbessard@143: {$$ = new il_assign_operator_c($1, locloc(@$));} laurent@239: | S1_operator ASSIGN laurent@239: {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} laurent@239: | R1_operator ASSIGN laurent@239: {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} laurent@239: | CLK_operator ASSIGN laurent@239: {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} laurent@239: | CU_operator ASSIGN laurent@239: {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} laurent@239: | CD_operator ASSIGN laurent@239: {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} laurent@239: | PV_operator ASSIGN laurent@239: {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} laurent@239: | IN_operator ASSIGN laurent@239: {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} laurent@239: | PT_operator ASSIGN laurent@239: {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | error ASSIGN lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid parameter defined in parameter assignment."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new il_assign_out_operator_c(NULL, $1, locloc(@$));} msousa@257: /* The following is not required, as the sendto_identifier_token returned by flex will msousa@257: * also include the 'ENO' identifier. msousa@257: * The resulting abstract syntax tree is identical with or without this following rule, msousa@257: * as both the eno_identifier and the sendto_identifier are stored as msousa@257: * an identifier_c !! msousa@315: * msousa@315: * To understand why we must even explicitly consider the use of ENO here, msousa@315: * please read the comment above the definition of 'variable' in section B1.4 for details. msousa@257: */ msousa@257: /* ccb@202: | eno_identifier SENDTO lbessard@143: {$$ = new il_assign_out_operator_c(NULL, $1, locloc(@$));} msousa@257: */ etisserant@0: /*| NOT variable_name SENDTO */ etisserant@0: | NOT sendto_identifier SENDTO mario@68: {$$ = new il_assign_out_operator_c(new not_paramassign_c(locloc(@1)), $2, locloc(@$));} msousa@257: /* The following is not required, as the sendto_identifier_token returned by flex will msousa@257: * also include the 'ENO' identifier. msousa@257: * The resulting abstract syntax tree is identical with or without this following rule, msousa@257: * as both the eno_identifier and the sendto_identifier are stored as msousa@257: * an identifier_c !! msousa@257: * msousa@315: * To understand why we must even explicitly consider the use of ENO here, msousa@315: * please read the comment above the definition of 'variable' in section B1.4 for details. msousa@315: * msousa@257: * NOTE: Removing the following rule also removes a shift/reduce conflict from the parser. msousa@257: * This conflict is not really an error/ambiguity in the syntax, but rather msousa@257: * due to the fact that more than a single look-ahead token would be required msousa@257: * to correctly parse the syntax, something that bison does not support. msousa@257: * msousa@257: * The shift/reduce conflict arises because bison does not know whether msousa@257: * to parse the 'NOT ENO' in the following code msousa@257: * LD 1 msousa@257: * funct_name ( msousa@257: * NOT ENO => bool_var, msousa@257: * EN := TRUE msousa@257: * ) msousa@257: * as either a il_param_assignment (wrong!) or an il_param_out_assignment.(correct). msousa@257: * The '=>' delimiter (known as SEND_TO in this iec.y file) is a dead giveaway that msousa@257: * it should be parsed as an il_param_out_assignment, but still, bison gets confused! msousa@257: * Bison considers the possibility of reducing the 'NOT ENO' as an NOT_operator with msousa@257: * the 'ENO' operand msousa@257: * (NOT_operator -> il_simple_operator -> il_simple_operation -> il_simple_instruction -> msousa@257: * -> simple_instr_list -> il_param_assignment) msousa@257: * instead of reducing it to an il_param_out_operator. msousa@257: * ( il_param_out_operator -> il_param_out_assignment) msousa@257: * msousa@257: * Note that the shift/reduce conflict only manifests itself in the il_formal_funct_call, msousa@257: * where both the il_param_out_assignment and il_param_assignment are used! msousa@257: * msousa@257: * il_param_out_assignment --+--> il_param_instruction -> il_param_instruction_list --+ msousa@257: * | | msousa@257: * il_param_assignment --+ | msousa@257: * | msousa@257: * il_formal_funct_call <- il_param_list <-+ msousa@257: * msousa@257: */ msousa@257: /* ccb@202: | NOT eno_identifier SENDTO lbessard@143: {$$ = new il_assign_out_operator_c(new not_paramassign_c(locloc(@1)), $2, locloc(@$));} msousa@257: */ lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | error SENDTO lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid parameter defined in parameter out assignment."); yyerrok;} lbessard@134: | NOT SENDTO lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no parameter defined in parameter out assignment."); yynerrs++;} lbessard@134: | NOT error SENDTO lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid parameter defined in parameter out assignment."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ 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 mjsousa@933: | ref_expression /* an extension to the IEC 61131-3 v2 standard, based on the IEC 61131-3 v3 standard */ mjsousa@933: | deref_expression /* an extension to the IEC 61131-3 v2 standard, based on the IEC 61131-3 v3 standard */ etisserant@0: | expression OR xor_expression mario@68: {$$ = new or_expression_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | expression OR error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'OR' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'OR' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: mjsousa@873: /* REF(var_name) */ mjsousa@873: /* This is an extension to the IEC 61131-3 standard. It is actually defined in the IEC 61131-3 v3 standard */ mjsousa@873: /* The REF() operator returns the adrress of the variable. Basically, it returns a pointer to the variable */ mjsousa@873: ref_expression: mjsousa@873: REF '(' symbolic_variable ')' mjsousa@873: {$$ = new ref_expression_c($3, locloc(@$));} mjsousa@873: ; mjsousa@873: mjsousa@933: /* DREF(var_name) */ mjsousa@933: /* This is an extension to the IEC 61131-3 standard. It is actually defined in the IEC 61131-3 v3 standard */ mjsousa@933: /* The DREF() operator accesses the variable stored in the specified address. Basically, it dereferences a pointer to the variable */ mjsousa@933: deref_expression: mjsousa@933: DREF '(' symbolic_variable ')' mjsousa@933: {$$ = new deref_expression_c($3, locloc(@$));} mjsousa@933: ; mjsousa@933: etisserant@0: xor_expression: etisserant@0: and_expression etisserant@0: | xor_expression XOR and_expression mario@68: {$$ = new xor_expression_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | xor_expression XOR error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'XOR' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'XOR' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: and_expression: etisserant@0: comparison etisserant@0: | and_expression '&' comparison mario@68: {$$ = new and_expression_c($1, $3, locloc(@$));} etisserant@0: | and_expression AND comparison mario@68: {$$ = new and_expression_c($1, $3, locloc(@$));} 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 lbessard@136: * to remove the AND2 token... etisserant@0: */ etisserant@0: | and_expression AND2 comparison mario@68: {$$ = new and_expression_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | and_expression '&' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '&' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after '&' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | and_expression AND error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'AND' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'AND' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | and_expression AND2 error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '&' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after '&' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: comparison: etisserant@0: equ_expression etisserant@0: | comparison '=' equ_expression mario@68: {$$ = new equ_expression_c($1, $3, locloc(@$));} etisserant@0: | comparison OPER_NE equ_expression mario@68: {$$ = new notequ_expression_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | comparison '=' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '=' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after '=' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | comparison OPER_NE error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '<>' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after '<>' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: equ_expression: etisserant@0: add_expression etisserant@0: | equ_expression '<' add_expression mario@68: {$$ = new lt_expression_c($1, $3, locloc(@$));} etisserant@0: | equ_expression '>' add_expression mario@68: {$$ = new gt_expression_c($1, $3, locloc(@$));} etisserant@0: | equ_expression OPER_LE add_expression mario@68: {$$ = new le_expression_c($1, $3, locloc(@$));} etisserant@0: | equ_expression OPER_GE add_expression mario@68: {$$ = new ge_expression_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | equ_expression '<' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '<' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after '<' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | equ_expression '>' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '>' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after '>' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | equ_expression OPER_LE error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '<=' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after '<=' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | equ_expression OPER_GE error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '>=' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after '>=' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new add_expression_c($1, $3, locloc(@$));} etisserant@0: | add_expression '-' term mario@68: {$$ = new sub_expression_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | add_expression '+' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '+' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after '+' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | add_expression '-' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '-' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after '-' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new mul_expression_c($1, $3, locloc(@$));} etisserant@0: | term '/' power_expression mario@68: {$$ = new div_expression_c($1, $3, locloc(@$));} etisserant@0: | term MOD power_expression mario@68: {$$ = new mod_expression_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | term '*' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '*' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after '*' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | term '/' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '/' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after '/' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | term MOD error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'MOD' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'MOD' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new power_expression_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | power_expression OPER_EXP error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '**' in ST expression.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after '**' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: unary_expression: msousa@643: primary_expression msousa@643: | '-' non_int_or_real_primary_expression mario@68: {$$ = new neg_expression_c($2, locloc(@$));} etisserant@0: | NOT primary_expression mario@68: {$$ = new not_expression_c($2, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | '-' error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no expression defined after '-' in ST expression.");} lbessard@136: else {print_err_msg(locf(@2), locl(@2), "invalid expression after '-' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: | NOT error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no expression defined after 'NOT' in ST expression.");} lbessard@136: else {print_err_msg(locf(@2), locl(@2), "invalid expression after 'NOT' in ST expression."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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: * msousa@257: * To remove the conflict, we only allow constants without msousa@643: * integer or reals that are not preceded by a sign msousa@643: * (i.e. a '-' or '+' character) to be used in primary_expression msousa@257: * (i.e. as a parameter to the unary negation operator) msousa@643: * msousa@643: * e.g. '-42', '+54', '42', '54' are all allowed in primary expression msousa@643: * according to the standard. However, we will allow only '-42' and '+54' msousa@643: * to be used as an argument to the negation operator ('-'). msousa@643: */ msousa@643: /* NOTE: Notice that the standard considers the following syntax correct: msousa@643: * VAR intv: INT; END_VAR msousa@643: * intv := 42; <----- OK msousa@643: * intv := -42; <----- OK msousa@643: * intv := +42; <----- OK msousa@643: * intv := --42; <----- OK!! msousa@643: * intv := -+42; <----- OK!! msousa@643: * intv := -(--42); <----- OK!! msousa@643: * intv := -(-+42); <----- OK!! msousa@643: * intv :=-(-(--42)); <----- OK!! msousa@643: * intv :=-(-(-+42)); <----- OK!! msousa@643: * but does NOT allow the following syntax: msousa@643: * VAR intv: INT; END_VAR msousa@643: * intv := ---42; <----- ERROR!! msousa@643: * intv := --+42; <----- ERROR!! msousa@643: * intv := ----42; <----- ERROR!! msousa@643: * intv := ---+42; <----- ERROR!! msousa@643: * msousa@643: * Although strange, we follow the standard to the letter, and do exactly msousa@643: * as stated above!! etisserant@0: */ mario@13: /* NOTE: We use enumerated_value_without_identifier instead of enumerated_value mario@13: * in order to remove a reduce/reduce conflict between reducing an mario@13: * identifier to a variable or an enumerated_value. mario@78: * mario@78: * This change follows the IEC specification. The specification seems to mario@85: * imply (by introducing syntax that allows to unambiguosly reference an mario@85: * enumerated value - enum_type#enum_value) that in case the same identifier is used mario@78: * for a variable and an enumerated value, then the variable shall be mario@85: * considered. mario@13: */ msousa@643: non_int_or_real_primary_expression: msousa@643: non_int_or_real_constant mario@85: //| enumerated_value_without_identifier mario@85: | enumerated_value etisserant@0: | variable etisserant@0: | '(' expression ')' etisserant@0: {$$ = $2;} etisserant@0: | function_invocation lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | '(' expression error lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of expression in ST expression."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: msousa@257: primary_expression: msousa@257: constant msousa@257: //| enumerated_value_without_identifier laurent@328: | enumerated_value msousa@257: | variable msousa@257: | '(' expression ')' msousa@257: {$$ = $2;} msousa@257: | function_invocation msousa@257: /* ERROR_CHECK_BEGIN */ msousa@257: | '(' expression error msousa@257: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of expression in ST expression."); yyerrok;} msousa@257: /* ERROR_CHECK_END */ msousa@257: ; msousa@257: msousa@257: msousa@257: 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: mario@85: /* function_name '(' [param_assignment_list] ')' */ mario@85: function_name_no_NOT_clashes '(' param_assignment_formal_list ')' mjsousa@958: {$$ = new function_invocation_c($1, $3, NULL, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c mario@85: | function_name_no_NOT_clashes '(' param_assignment_nonformal_list ')' mjsousa@958: {$$ = new function_invocation_c($1, NULL, $3, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c mjsousa@1012: | function_name_no_NOT_clashes '(' ')' mjsousa@1012: {if (NULL == dynamic_cast($1)) ERROR; // $1 should be a poutype_identifier_c mjsousa@1012: if (runtime_options.allow_missing_var_in) mjsousa@1012: {$$ = new function_invocation_c($1, NULL, NULL, locloc(@$));} mjsousa@1012: else mjsousa@1012: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no parameter defined in function invocation of ST expression."); yynerrs++;} mjsousa@1012: } lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | function_name_no_NOT_clashes param_assignment_formal_list ')' lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function name in ST expression."); yynerrs++;} lbessard@131: | function_name_no_NOT_clashes '(' error ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid parameter(s) defined in function invocation of ST expression."); yyerrok;} lbessard@131: | function_name_no_NOT_clashes '(' param_assignment_formal_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of function invocation in ST expression."); yyerrok;} lbessard@131: | function_name_no_NOT_clashes '(' param_assignment_nonformal_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of function invocation in ST expression."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /********************/ etisserant@0: /* B 3.2 Statements */ etisserant@0: /********************/ etisserant@0: statement_list: mario@13: statement ';' mario@68: {$$ = new statement_list_c(locloc(@$)); $$->add_element($1);} msousa@267: | any_pragma mario@68: {$$ = new statement_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | statement_list statement ';' etisserant@0: {$$ = $1; $$->add_element($2);} msousa@267: | statement_list any_pragma etisserant@0: {$$ = $1; $$->add_element($2);} mario@68: /* ERROR_CHECK_BEGIN */ lbessard@133: | statement error lbessard@136: {$$ = new statement_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at the end of statement in ST statement."); yyerrok;} lbessard@133: | statement_list statement error lbessard@136: {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of statement in ST statement."); yyerrok;} etisserant@0: | statement_list error ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid statement in ST statement."); yyerrok;} lbessard@133: | statement_list ';' lbessard@136: {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after statement in ST statement."); yynerrs++;} mario@68: /* ERROR_CHECK_END */ 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 mjsousa@1019: | function_invocation mjsousa@1019: { /* This is a non-standard extension (calling a function outside an ST expression!) */ mjsousa@1019: /* Only allow this if command line option has been selected... */ mjsousa@1019: $$ = $1; mjsousa@1019: if (!runtime_options.allow_void_datatype) { mjsousa@1019: print_err_msg(locf(@1), locl(@1), "Function invocation in ST code is not allowed outside an expression. To allow this non-standard syntax, activate the apropriate command line option."); mjsousa@1019: yynerrs++; mjsousa@1019: } mjsousa@1019: } 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 mario@68: {$$ = new assignment_statement_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@136: | error ASSIGN expression lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid variable before ':=' in ST assignment statement."); yyerrok;} lbessard@131: | variable ASSIGN error lbessard@133: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after ':=' in ST assignment statement.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression after ':=' in ST assignment statement."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ 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: return_statement: mario@68: RETURN {$$ = new return_statement_c(locloc(@$));} etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: etisserant@0: fb_invocation: etisserant@0: prev_declared_fb_name '(' ')' ccb@202: {$$ = new fb_invocation_c($1, NULL, NULL, locloc(@$)); } mario@85: | prev_declared_fb_name '(' param_assignment_formal_list ')' ccb@202: {$$ = new fb_invocation_c($1, $3, NULL, locloc(@$));} mario@85: | prev_declared_fb_name '(' param_assignment_nonformal_list ')' ccb@202: {$$ = new fb_invocation_c($1, NULL, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | prev_declared_fb_name ')' lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function block name in ST statement."); yynerrs++;} lbessard@131: | prev_declared_fb_name param_assignment_formal_list ')' lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function block name in ST statement."); yynerrs++;} lbessard@131: | prev_declared_fb_name '(' error ')' lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid parameter list in function block invocation in ST statement."); yyerrok;} lbessard@131: | prev_declared_fb_name '(' error lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing after parameter list of function block invocation in ST statement."); yyerrok;} lbessard@131: | prev_declared_fb_name '(' param_assignment_formal_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing after parameter list of function block invocation in ST statement."); yyerrok;} lbessard@131: | prev_declared_fb_name '(' param_assignment_nonformal_list error lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing after parameter list of function block invocation in ST statement."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* helper symbol for etisserant@0: * - fb_invocation etisserant@0: * - function_invocation etisserant@0: */ mario@85: param_assignment_formal_list: mario@85: param_assignment_formal mario@68: {$$ = new param_assignment_list_c(locloc(@$)); $$->add_element($1);} mario@85: | param_assignment_formal_list ',' param_assignment_formal etisserant@0: {$$ = $1; $$->add_element($3);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | param_assignment_formal_list ',' error lbessard@134: {$$ = $1; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no parameter assignment defined in ST parameter assignment list.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid parameter assignment in ST parameter assignment list."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: mario@85: /* helper symbol for mario@85: * - fb_invocation mario@85: * - function_invocation mario@85: */ mario@85: param_assignment_nonformal_list: mario@85: param_assignment_nonformal mario@85: {$$ = new param_assignment_list_c(locloc(@$)); $$->add_element($1);} mario@85: | param_assignment_nonformal_list ',' param_assignment_nonformal mario@85: {$$ = $1; $$->add_element($3);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | param_assignment_nonformal_list ',' error lbessard@134: {$$ = $1; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no parameter assignment defined in ST parameter assignment list.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid parameter assignment in ST parameter assignment list."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ mario@85: ; mario@85: mario@85: mario@85: /* NOTE: According to the IEC 61131-3 standard, there are two possible mario@85: * syntaxes for calling function blocks within ST. mario@85: * The formal method has the form: mario@85: * fb ( invar := x, inoutvar := var1, outvar => var2); mario@85: * The non-formal method has the form: mario@85: * fb (x, var1, var2); mario@85: * In the text of IEC 61131-3 (where the semantics are defined), mario@85: * it is obvious that mixing the two syntaxes is considered incorrect. mario@85: * The following should therefore be incorrect: mario@85: * fb ( invar := x, var1, var2); mario@85: * However, according to the syntax definition, as defined in IEC 61131-3, mario@85: * mixing the formal and non-formal methods of invocation is allowed. mario@85: * We have two alternatives: mario@85: * (a) implement the syntax here in iec.y according to the standard, mario@85: * and leave it to the semantic analyser stage to find this error mario@85: * (b) or implement the syntax in iec.y correctly, not allowing mario@85: * the mixing of formal and non-formal invocation syntaxes. mario@85: * Considering that this is a syntax issue, and not semantic issue, mario@85: * I (Mario) have decided to go with alternative (a). mario@85: * In other words, in iec.y we do not follow the syntax as defined in mario@85: * Annex B of the IEC 61131-3 standard, but rather implement mario@85: * the syntax also taking into account the textual part of the standard too. mario@85: */ mario@85: /* etisserant@0: param_assignment: mario@85: variable_name ASSIGN expression mario@85: */ mario@85: param_assignment_nonformal: mario@85: expression mario@85: ; mario@85: mario@85: mario@85: param_assignment_formal: etisserant@0: any_identifier ASSIGN expression mario@68: {$$ = new input_variable_param_assignment_c($1, $3, locloc(@$));} ccb@202: | en_identifier ASSIGN expression lbessard@143: {$$ = new input_variable_param_assignment_c($1, $3, locloc(@$));} etisserant@0: /*| variable_name SENDTO variable */ etisserant@0: /*| any_identifier SENDTO variable */ etisserant@0: | sendto_identifier SENDTO variable lbessard@143: {$$ = new output_variable_param_assignment_c(NULL, $1, $3, locloc(@$));} msousa@257: /* The following is not required, as the sendto_identifier_token returned by flex will msousa@257: * also include the 'ENO' identifier. msousa@257: * The resulting abstract syntax tree is identical with or without this following rule, msousa@257: * as both the eno_identifier and the sendto_identifier are stored as msousa@257: * an identifier_c !! msousa@315: * msousa@315: * To understand why we must even explicitly consider the use of ENO here, msousa@315: * please read the comment above the definition of 'variable' in section B1.4 for details. msousa@257: */ msousa@257: /* ccb@202: | eno_identifier SENDTO variable lbessard@143: {$$ = new output_variable_param_assignment_c(NULL, $1, $3, locloc(@$));} msousa@257: */ mario@85: /*| NOT variable_name SENDTO variable */ etisserant@0: /*| NOT any_identifier SENDTO variable*/ etisserant@0: | NOT sendto_identifier SENDTO variable lbessard@143: {$$ = new output_variable_param_assignment_c(new not_paramassign_c(locloc(@$)), $2, $4, locloc(@$));} msousa@257: /* The following is not required, as the sendto_identifier_token returned by flex will msousa@257: * also include the 'ENO' identifier. msousa@257: * The resulting abstract syntax tree is identical with or without this following rule, msousa@257: * as both the eno_identifier and the sendto_identifier are stored as msousa@257: * an identifier_c !! msousa@315: * msousa@315: * To understand why we must even explicitly consider the use of ENO here, msousa@315: * please read the comment above the definition of 'variable' in section B1.4 for details. msousa@257: */ msousa@257: /* ccb@202: | NOT eno_identifier SENDTO variable lbessard@143: {$$ = new output_variable_param_assignment_c(new not_paramassign_c(locloc(@$)), $2, $4, locloc(@$));} msousa@257: */ lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | any_identifier ASSIGN error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter assignment.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter assignment."); yyclearin;} lbessard@136: yyerrok; lbessard@136: } ccb@202: | en_identifier ASSIGN error lbessard@143: {$$ = NULL; lbessard@143: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter assignment.");} lbessard@143: else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter assignment."); yyclearin;} lbessard@143: yyerrok; lbessard@143: } lbessard@131: | sendto_identifier SENDTO error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter out assignment.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter out assignment."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } msousa@257: /* ccb@202: | eno_identifier SENDTO error lbessard@143: {$$ = NULL; lbessard@143: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter out assignment.");} lbessard@143: else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter out assignment."); yyclearin;} lbessard@143: yyerrok; lbessard@143: } msousa@257: */ lbessard@131: | NOT SENDTO variable lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no parameter name defined in ST formal parameter out negated assignment."); yynerrs++;} lbessard@131: | NOT error SENDTO variable lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid parameter name defined in ST formal parameter out negated assignment."); yyerrok;} lbessard@131: | NOT sendto_identifier SENDTO error lbessard@131: {$$ = NULL; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no expression defined in ST formal parameter out negated assignment.");} lbessard@136: else {print_err_msg(locf(@4), locl(@4), "invalid expression in ST formal parameter out negated assignment."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } msousa@257: /* ccb@202: | NOT eno_identifier SENDTO error lbessard@143: {$$ = NULL; lbessard@143: if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no expression defined in ST formal parameter out negated assignment.");} lbessard@143: else {print_err_msg(locf(@4), locl(@4), "invalid expression in ST formal parameter out negated assignment."); yyclearin;} lbessard@143: yyerrok; lbessard@143: } msousa@257: */ lbessard@131: /* ERROR_CHECK_END */ 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 mario@68: {$$ = new if_statement_c($2, $4, $5, NULL, locloc(@$));} etisserant@0: | IF expression THEN statement_list elseif_statement_list ELSE statement_list END_IF mario@68: {$$ = new if_statement_c($2, $4, $5, $7, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | IF THEN statement_list elseif_statement_list END_IF lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'IF' statement."); yynerrs++;} lbessard@131: | IF THEN statement_list elseif_statement_list ELSE statement_list END_IF lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'IF' statement."); yynerrs++;} lbessard@131: | IF error THEN statement_list elseif_statement_list END_IF lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'IF' statement."); yyerrok;} lbessard@131: | IF error THEN statement_list elseif_statement_list ELSE statement_list END_IF lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'IF' statement."); yyerrok;} lbessard@131: | IF expression error statement_list elseif_statement_list END_IF lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'THEN' after test expression in ST 'IF' statement."); yyerrok;} lbessard@131: | IF expression error statement_list elseif_statement_list ELSE statement_list END_IF lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'THEN' after test expression in ST 'IF' statement."); yyerrok;} lbessard@131: | IF expression THEN elseif_statement_list END_IF lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no statement defined after 'THEN' in ST 'IF' statement."); yynerrs++;} lbessard@131: | IF expression THEN elseif_statement_list ELSE statement_list END_IF lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no statement defined after 'THEN' in ST 'IF' statement."); yynerrs++;} lbessard@131: | IF expression THEN statement_list elseif_statement_list ELSE END_IF lbessard@136: {$$ = NULL; print_err_msg(locl(@6), locf(@7), "no statement defined after 'ELSE' in ST 'IF' statement."); yynerrs++;} lbessard@131: | IF expression THEN statement_list elseif_statement_list ELSE error END_IF lbessard@136: {$$ = NULL; print_err_msg(locf(@7), locl(@7), "invalid statement defined after 'ELSE' in ST 'IF' statement."); yynerrs++; yyerrok;} lbessard@136: | IF expression error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed 'IF' statement in ST."); yyerrok;} lbessard@136: | IF expression THEN statement_list elseif_statement_list END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'IF' statement in ST."); yynerrs++;} lbessard@136: | IF expression THEN statement_list elseif_statement_list ELSE statement_list END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'IF' statement in ST."); yynerrs++;} lbessard@131: | IF error END_IF lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'IF' statement."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: /* helper symbol for if_statement */ etisserant@0: elseif_statement_list: etisserant@0: /* empty */ mario@68: {$$ = new elseif_statement_list_c(locloc(@$));} 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 mario@68: {$$ = new elseif_statement_c($2, $4, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | ELSIF THEN statement_list lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined for 'ELSEIF' statement in ST 'IF' statement."); yynerrs++;} lbessard@131: | ELSIF error THEN statement_list lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for 'ELSEIF' statement in ST 'IF' statement."); yyerrok;} lbessard@131: | ELSIF expression error statement_list lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'THEN' after test expression in 'ELSEIF' statement of ST 'IF' statement."); yyerrok;} lbessard@131: | ELSIF expression THEN error lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid statement list in 'ELSEIF' statement of ST 'IF' statement."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: case_statement: etisserant@0: CASE expression OF case_element_list END_CASE mario@68: {$$ = new case_statement_c($2, $4, NULL, locloc(@$));} etisserant@0: | CASE expression OF case_element_list ELSE statement_list END_CASE mario@68: {$$ = new case_statement_c($2, $4, $6, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | CASE OF case_element_list END_CASE lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'CASE' statement."); yynerrs++;} lbessard@131: | CASE OF case_element_list ELSE statement_list END_CASE lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'CASE' statement."); yynerrs++;} lbessard@131: | CASE error OF case_element_list END_CASE lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'CASE' statement."); yyerrok;} lbessard@131: | CASE error OF case_element_list ELSE statement_list END_CASE lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'CASE' statement."); yyerrok;} lbessard@131: | CASE expression error case_element_list END_CASE lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'OF' after test expression in ST 'CASE' statement."); yyerrok;} lbessard@131: | CASE expression error case_element_list ELSE statement_list END_CASE lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'OF' after test expression in ST 'CASE' statement."); yyerrok;} lbessard@131: | CASE expression OF END_CASE lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no case element(s) defined after 'OF' in ST 'CASE' statement."); yynerrs++;} lbessard@131: | CASE expression OF ELSE statement_list END_CASE lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no case element(s) defined after 'OF' in ST 'CASE' statement."); yynerrs++;} lbessard@131: | CASE expression OF error END_CASE lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid case element(s) defined after 'OF' in ST 'CASE' statement."); yyerrok;} lbessard@131: | CASE expression OF error ELSE statement_list END_CASE lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid case element(s) defined after 'OF' in ST 'CASE' statement."); yyerrok;} lbessard@131: | CASE expression OF case_element_list ELSE END_CASE lbessard@136: {$$ = NULL; print_err_msg(locl(@5), locf(@6), "no statement defined after 'ELSE' in ST 'CASE' statement."); yynerrs++;} lbessard@131: | CASE expression OF case_element_list ELSE error END_CASE lbessard@136: {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid statement defined after 'ELSE' in ST 'CASE' statement."); yyerrok;} lbessard@136: | CASE expression error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed 'CASE' statement in ST."); yyerrok;} lbessard@136: | CASE expression OF case_element_list END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'CASE' statement in ST."); yynerrs++;} lbessard@136: | CASE expression OF case_element_list ELSE statement_list END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'CASE' statement in ST."); yynerrs++;} lbessard@131: | CASE error END_CASE lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'CASE' statement."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: /* helper symbol for case_statement */ etisserant@0: case_element_list: etisserant@0: case_element mario@68: {$$ = new case_element_list_c(locloc(@$)); $$->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 mario@68: {$$ = new case_element_c($1, $3, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | case_list statement_list lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after case list in ST 'CASE' statement."); yynerrs++;} lbessard@131: | case_list ':' error lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid statement in case element of ST 'CASE' statement."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: case_list: etisserant@0: case_list_element mario@68: {$$ = new case_list_c(locloc(@$)); $$->add_element($1);} etisserant@0: | case_list ',' case_list_element etisserant@0: {$$ = $1; $$->add_element($3);} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | case_list ',' error lbessard@134: {$$ = $1; lbessard@136: if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no case defined in case list of ST parameter assignment list.");} lbessard@136: else {print_err_msg(locf(@3), locl(@3), "invalid case in case list of ST parameter assignment list."); yyclearin;} lbessard@131: yyerrok; lbessard@131: } lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: case_list_element: etisserant@0: signed_integer mario@78: | subrange etisserant@0: | enumerated_value 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 mario@68: {$$ = new for_statement_c($2, $4, $6, $8, $10, locloc(@$));} etisserant@0: | FOR control_variable ASSIGN expression TO expression DO statement_list END_FOR mario@68: {$$ = new for_statement_c($2, $4, $6, NULL, $8, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | FOR ASSIGN expression TO expression BY expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no control variable defined in ST 'FOR' statement."); yynerrs++;} lbessard@131: | FOR ASSIGN expression TO expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no control variable defined in ST 'FOR' statement."); yynerrs++;} lbessard@131: | FOR error ASSIGN expression TO expression BY expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid control variable defined for ST 'FOR' statement."); yyerrok;} lbessard@131: | FOR error ASSIGN expression TO expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid control variable defined for ST 'FOR' statement."); yyerrok;} lbessard@131: | FOR control_variable expression TO expression BY expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':=' missing between control variable and start expression in ST 'FOR' statement."); yynerrs++;} lbessard@131: | FOR control_variable expression TO expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':=' missing between control variable and start expression in ST 'FOR' statement."); yynerrs++;} lbessard@131: | FOR control_variable error expression TO expression BY expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting ':=' between control variable and start expression in ST 'FOR' statement."); yyerrok;} lbessard@131: | FOR control_variable error expression TO expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting ':=' between control variable and start expression in ST 'FOR' statement."); yyerrok;} lbessard@131: | FOR control_variable ASSIGN TO expression BY expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no start expression defined in ST 'FOR' statement."); yynerrs++;} lbessard@131: | FOR control_variable ASSIGN TO expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no start expression defined in ST 'FOR' statement."); yynerrs++;} lbessard@131: | FOR control_variable ASSIGN error TO expression BY expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid start expression defined in ST 'FOR' statement."); yyerrok;} lbessard@131: | FOR control_variable ASSIGN error TO expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid start expression in ST 'FOR' statement."); yyerrok;} lbessard@131: | FOR control_variable ASSIGN expression error expression BY expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locf(@5), locl(@5), "expecting 'TO' between start expression and end expression in ST 'FOR' statement."); yyerrok;} lbessard@131: | FOR control_variable ASSIGN expression error expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locf(@5), locl(@5), "expecting 'TO' between start expression and end expression in ST 'FOR' statement."); yyerrok;} lbessard@131: | FOR control_variable ASSIGN expression TO expression error expression DO statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locf(@7), locl(@7), "expecting 'BY' between end expression and step expression in ST 'FOR' statement."); yyerrok;} lbessard@131: | FOR control_variable ASSIGN expression TO expression BY expression error statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locf(@9), locl(@9), "expecting 'DO' after step expression in ST 'FOR' statement."); yyerrok;} lbessard@131: | FOR control_variable ASSIGN expression TO expression error statement_list END_FOR lbessard@136: {$$ = NULL; print_err_msg(locf(@7), locl(@7), "expecting 'DO' after end expression in ST 'FOR' statement."); yyerrok;} lbessard@131: | FOR control_variable ASSIGN expression TO expression BY expression DO END_FOR lbessard@136: {$$ = NULL; print_err_msg(locl(@9), locf(@10), "no statement(s) defined after 'DO' in ST 'FOR' statement."); yynerrs++;} lbessard@131: | FOR control_variable ASSIGN expression TO expression DO END_FOR lbessard@136: {$$ = NULL; print_err_msg(locl(@7), locf(@8), "no statement(s) defined after 'DO' in ST 'FOR' statement."); yynerrs++;} lbessard@131: | FOR control_variable ASSIGN expression TO expression BY expression DO error END_FOR lbessard@136: {$$ = NULL; print_err_msg(locf(@10), locl(@10), "invalid statement(s) defined after 'DO' in ST 'FOR' statement."); yyerrok;} lbessard@131: | FOR control_variable ASSIGN expression TO expression DO error END_FOR lbessard@136: {$$ = NULL; print_err_msg(locf(@8), locl(@8), "invalid statement(s) defined after 'DO' in ST 'FOR' statement."); yyerrok;} lbessard@136: | FOR control_variable error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yyerrok;} lbessard@136: | FOR control_variable ASSIGN expression error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yyerrok;} lbessard@136: | FOR control_variable ASSIGN expression TO expression DO statement_list END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yynerrs++;} lbessard@136: | FOR control_variable ASSIGN expression TO expression BY expression error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yyerrok;} lbessard@136: | FOR control_variable ASSIGN expression TO expression BY expression DO statement_list END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yynerrs++;} lbessard@134: | FOR error END_FOR lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'FOR' statement."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ 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 mario@79: * We must therefore change the syntax to read etisserant@0: * control_variable: prev_declared_variable_name; mario@13: * mario@79: * If we don't, then the correct use of any previosuly declared mario@79: * variable would result in an incorrect syntax error etisserant@0: */ ccb@202: control_variable: ccb@202: prev_declared_variable_name msousa@1053: {$$ = new symbolic_variable_c($1,locloc(@$)); $$->token = $1->token;}; mario@79: // control_variable: identifier {$$ = $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 mario@68: {$$ = new while_statement_c($2, $4, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | WHILE DO statement_list END_WHILE lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'WHILE' statement."); yynerrs++;} lbessard@131: | WHILE error DO statement_list END_WHILE lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'WHILE' statement."); yyerrok;} lbessard@131: | WHILE expression error statement_list END_WHILE lbessard@136: {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'DO' after test expression in ST 'WHILE' statement."); yyerrok;} lbessard@131: | WHILE expression DO END_WHILE lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no statement(s) defined after 'DO' in ST 'WHILE' statement."); yynerrs++;} lbessard@131: | WHILE expression DO error END_WHILE lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid statement(s) defined after 'DO' in ST 'WHILE' statement."); yyerrok;} lbessard@136: | WHILE expression error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'WHILE' statement in ST."); yyerrok;} lbessard@136: | WHILE expression DO statement_list END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'WHILE' statement in ST."); yynerrs++;} lbessard@131: | WHILE error END_WHILE lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'WHILE' statement."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: repeat_statement: etisserant@0: REPEAT statement_list UNTIL expression END_REPEAT mario@68: {$$ = new repeat_statement_c($2, $4, locloc(@$));} lbessard@131: /* ERROR_CHECK_BEGIN */ lbessard@131: | REPEAT UNTIL expression END_REPEAT lbessard@136: {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no statement(s) defined after 'REPEAT' in ST 'REPEAT' statement."); yynerrs++;} lbessard@131: | REPEAT error UNTIL expression END_REPEAT lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid statement(s) defined after 'REPEAT' for ST 'REPEAT' statement."); yyerrok;} lbessard@131: | REPEAT statement_list UNTIL END_REPEAT lbessard@136: {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no test expression defined after 'UNTIL' in ST 'REPEAT' statement.");} lbessard@131: | REPEAT statement_list UNTIL error END_REPEAT lbessard@136: {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid test expression defined after 'UNTIL' in ST 'REPEAT' statement."); yyerrok;} lbessard@136: | REPEAT statement_list END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'REPEAT' statement in ST."); yynerrs++;} lbessard@136: | REPEAT statement_list UNTIL expression error END_OF_INPUT lbessard@136: {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'REPEAT' statement in ST."); yyerrok;} lbessard@131: | REPEAT error END_REPEAT lbessard@136: {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'REPEAT' statement."); yyerrok;} lbessard@131: /* ERROR_CHECK_END */ etisserant@0: ; etisserant@0: etisserant@0: etisserant@0: exit_statement: mario@68: EXIT {$$ = new exit_statement_c(locloc(@$));} 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: mario@15: mario@177: mario@177: mario@177: /*************************************************************************************************/ mario@177: /* NOTE: These variables are really parameters we would like the stage2__ function to pass */ mario@177: /* to the yyparse() function. However, the yyparse() function is created automatically */ mario@177: /* by bison, so we cannot add parameters to this function. The only other */ mario@177: /* option is to use global variables! yuck! */ mario@177: /*************************************************************************************************/ mario@177: mario@15: /* A global flag used to tell the parser if overloaded funtions should be allowed. mario@15: * The IEC 61131-3 standard allows overloaded funtions in the standard library, mario@15: * but disallows them in user code... mario@177: * mario@177: * In essence, a parameter we would like to pass to the yyparse() function but mario@177: * have to do it using a global variable, as the yyparse() prototype is fixed by bison. mario@15: */ mario@15: bool allow_function_overloading = false; mario@15: msousa@350: /* | [var1_list ','] variable_name '..' */ msousa@350: /* NOTE: This is an extension to the standard!!! */ msousa@350: /* In order to be able to handle extensible standard functions msousa@350: * (i.e. standard functions that may have a variable number of msousa@350: * input parameters, such as AND(word#33, word#44, word#55, word#66), msousa@350: * we have extended the acceptable syntax to allow var_name '..' msousa@350: * in an input variable declaration. msousa@350: * msousa@350: * This allows us to parse the declaration of standard msousa@350: * extensible functions and load their interface definition msousa@350: * into the abstract syntax tree just like we do to other msousa@350: * user defined functions. msousa@350: * This has the advantage that we can later do semantic msousa@350: * checking of calls to functions (be it a standard or user defined msousa@350: * function) in (almost) exactly the same way. msousa@350: * msousa@350: * Of course, we have a flag that disables this syntax when parsing user msousa@350: * written code, so we only allow this extra syntax while parsing the msousa@350: * 'header' file that declares all the standard IEC 61131-3 functions. msousa@350: */ msousa@350: bool allow_extensible_function_parameters = false; msousa@350: mjsousa@934: /* A global flag used to tell the parser whether to allow use of DREF and '^' operators (defined in IEC 61131-3 v3) */ mjsousa@934: bool allow_ref_dereferencing; mjsousa@924: /* A global flag used to tell the parser whether to allow use of REF_TO ANY datatypes (non-standard extension) */ mjsousa@924: bool allow_ref_to_any = false; mjsousa@932: /* A global flag used to tell the parser whether to allow use of REF_TO as a struct or array element (non-standard extension) */ mjsousa@932: bool allow_ref_to_in_derived_datatypes = false; mjsousa@932: mjsousa@932: /* A pointer to the root of the parsing tree that will be generated by bison. */ mario@15: symbol_c *tree_root; mario@15: mario@15: mario@15: 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); */ mario@68: /* print_include_stack(); */ etisserant@0: } etisserant@0: lbessard@136: ccb@202: /* ERROR_CHECK_BEGIN */ lbessard@136: bool is_current_syntax_token() { ccb@202: switch (yychar) { ccb@202: case ';': ccb@202: case ',': ccb@202: case ')': ccb@202: case ']': ccb@202: case '+': ccb@202: case '*': ccb@202: case '-': ccb@202: case '/': ccb@202: case '<': ccb@202: case '>': ccb@202: case '=': ccb@202: case '&': ccb@202: case OR: ccb@202: case XOR: ccb@202: case AND: ccb@202: case AND2: ccb@202: case OPER_NE: ccb@202: case OPER_LE: ccb@202: case OPER_GE: ccb@202: case MOD: ccb@202: case OPER_EXP: ccb@202: case NOT: ccb@202: return true; ccb@202: default: ccb@202: return false; ccb@202: } lbessard@136: } ccb@202: /* ERROR_CHECK_END */ ccb@202: lbessard@136: lbessard@136: void print_err_msg(int first_line, mario@95: int first_column, msousa@286: const char *first_filename, msousa@287: long int first_order, mario@95: int last_line, mario@95: int last_column, msousa@286: const char *last_filename, msousa@287: long int last_order, mario@95: const char *additional_error_msg) { msousa@286: msousa@286: const char *unknown_file = ""; msousa@286: if (first_filename == NULL) first_filename = unknown_file; msousa@286: if ( last_filename == NULL) last_filename = unknown_file; msousa@286: mjsousa@1012: if (runtime_options.full_token_loc) { msousa@286: if (first_filename == last_filename) msousa@516: fprintf(stderr, "%s:%d-%d..%d-%d: error: %s\n", first_filename, first_line, first_column, last_line, last_column, additional_error_msg); msousa@286: else msousa@516: fprintf(stderr, "%s:%d-%d..%s:%d-%d: error: %s\n", first_filename, first_line, first_column, last_filename, last_line, last_column, additional_error_msg); msousa@286: } else { msousa@516: fprintf(stderr, "%s:%d: error: %s\n", first_filename, first_line, additional_error_msg); msousa@286: } lbessard@131: //fprintf(stderr, "error %d: %s\n", yynerrs /* a global variable */, additional_error_msg); etisserant@0: print_include_stack(); etisserant@0: } etisserant@0: etisserant@0: etisserant@0: msousa@350: /* If function overloading is on, we allow several functions with the same name. msousa@350: * msousa@350: * However, to support standard functions, we also allow functions named msousa@350: * AND, MOD, NOT, OR, XOR, ADD, ... msousa@350: */ msousa@350: /* msousa@350: identifier_c *token_2_identifier_c(char *value, ) { msousa@350: identifier_c tmp = new identifier_c(value, locloc(@$)); msousa@350: if (!allow_function_overloading) { msousa@350: fprintf(stderr, "Function overloading not allowed. Invalid identifier %s\n", ((token_c *)($$))->value); msousa@350: ERROR; msousa@350: } msousa@350: } msousa@350: } msousa@350: */ msousa@350: 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: */ mjsousa@958: poutype_identifier_c *il_operator_c_2_poutype_identifier_c(symbol_c *il_operator) { mjsousa@958: identifier_c * id = il_operator_c_2_identifier_c(il_operator); mjsousa@958: poutype_identifier_c *pou_id = new poutype_identifier_c(strdup(id->value)); mjsousa@958: mjsousa@958: *(symbol_c *)pou_id = *(symbol_c *)id; mjsousa@958: delete id; mjsousa@958: return pou_id; mjsousa@958: } mjsousa@958: mjsousa@958: mjsousa@958: identifier_c *il_operator_c_2_identifier_c(symbol_c *il_operator) { etisserant@0: const char *name = NULL; mario@68: identifier_c *res; etisserant@0: ccb@202: op_2_str(NOT, "NOT"); ccb@202: ccb@202: op_2_str(AND, "AND"); ccb@202: op_2_str(OR, "OR"); ccb@202: op_2_str(XOR, "XOR"); ccb@202: op_2_str(ADD, "ADD"); ccb@202: op_2_str(SUB, "SUB"); ccb@202: op_2_str(MUL, "MUL"); ccb@202: op_2_str(DIV, "DIV"); ccb@202: op_2_str(MOD, "MOD"); ccb@202: op_2_str(GT, "GT"); ccb@202: op_2_str(GE, "GE"); ccb@202: op_2_str(EQ, "EQ"); ccb@202: op_2_str(LT, "LT"); ccb@202: op_2_str(LE, "LE"); ccb@202: op_2_str(NE, "NE"); ccb@202: ccb@202: op_2_str(LD, "LD"); ccb@202: op_2_str(LDN, "LDN"); ccb@202: op_2_str(ST, "ST"); ccb@202: op_2_str(STN, "STN"); ccb@202: ccb@202: op_2_str(S, "S"); ccb@202: op_2_str(R, "R"); ccb@202: op_2_str(S1, "S1"); ccb@202: op_2_str(R1, "R1"); ccb@202: ccb@202: op_2_str(CLK, "CLK"); ccb@202: op_2_str(CU, "CU"); ccb@202: op_2_str(CD, "CD"); ccb@202: op_2_str(PV, "PV"); ccb@202: op_2_str(IN, "IN"); ccb@202: op_2_str(PT, "PT"); ccb@202: ccb@202: op_2_str(ANDN, "ANDN"); ccb@202: op_2_str(ORN, "ORN"); ccb@202: op_2_str(XORN, "XORN"); ccb@202: ccb@202: op_2_str(ADD, "ADD"); ccb@202: op_2_str(SUB, "SUB"); ccb@202: op_2_str(MUL, "MUL"); ccb@202: op_2_str(DIV, "DIV"); ccb@202: ccb@202: op_2_str(GT, "GT"); ccb@202: op_2_str(GE, "GE"); ccb@202: op_2_str(EQ, "EQ"); ccb@202: op_2_str(LT, "LT"); ccb@202: op_2_str(LE, "LE"); ccb@202: op_2_str(NE, "NE"); ccb@202: ccb@202: op_2_str(CAL, "CAL"); ccb@202: op_2_str(CALC, "CALC"); etisserant@0: op_2_str(CALCN, "CALCN"); ccb@202: op_2_str(RET, "RET"); ccb@202: op_2_str(RETC, "RETC"); etisserant@0: op_2_str(RETCN, "RETCN"); ccb@202: op_2_str(JMP, "JMP"); ccb@202: op_2_str(JMPC, "JMPC"); etisserant@0: op_2_str(JMPCN, "JMPCN"); etisserant@0: etisserant@0: if (name == NULL) etisserant@0: ERROR; mjsousa@958: /* mario@68: res = new identifier_c(strdup(name), mario@68: il_operator->first_line, mario@68: il_operator->first_column, msousa@286: il_operator->first_file, msousa@287: il_operator->first_order, mario@68: il_operator->last_line, msousa@286: il_operator->last_column, msousa@287: il_operator->last_file, msousa@287: il_operator->last_order mario@68: ); etisserant@0: free(il_operator); mjsousa@958: */ mjsousa@958: res = new identifier_c(strdup(name)); mjsousa@958: *(symbol_c *)res = *(symbol_c *)il_operator; mjsousa@958: delete il_operator; mjsousa@958: mario@68: return res; etisserant@0: } etisserant@0: etisserant@0: etisserant@40: #include "standard_function_names.c" 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 mario@73: "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 mario@68: "CTU","CTU_DINT","CTU_LINT","CTU_UDINT","CTU_ULINT", mario@68: "CTD","CTD_DINT","CTD_LINT","CTD_UDINT","CTD_ULINT", 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@40: extern const char *INCLUDE_DIRECTORIES[]; etisserant@40: mario@177: mjsousa@952: static int parse_files(const char *libfilename, const char *filename) { mjsousa@952: /* first parse the standard library file... */ mjsousa@952: /* Do not debug the standard library, even if debug flag is set! msousa@257: #if YYDEBUG msousa@257: yydebug = 1; msousa@257: #endif msousa@257: */ mjsousa@761: FILE *libfile = NULL; mjsousa@761: if((libfile = parse_file(libfilename)) == NULL) { msousa@757: char *errmsg = strdup2("Error opening library file ", libfilename); msousa@757: perror(errmsg); msousa@757: free(errmsg); msousa@757: /* we give up... */ msousa@757: return -1; msousa@757: } msousa@757: mjsousa@924: allow_function_overloading = true; msousa@350: allow_extensible_function_parameters = true; mjsousa@946: allow_ref_dereferencing = runtime_options.ref_standard_extensions; mjsousa@946: allow_ref_to_any = runtime_options.ref_nonstand_extensions; mjsousa@946: allow_ref_to_in_derived_datatypes = runtime_options.ref_nonstand_extensions; mjsousa@955: if (yyparse() != 0) { mjsousa@955: fprintf (stderr, "\nParsing failed because of too many consecutive syntax errors in standard library. Bailing out!\n"); mjsousa@955: exit(EXIT_FAILURE); mjsousa@955: } mjsousa@761: fclose(libfile); mjsousa@761: mjsousa@952: if (yynerrs > 0) { /* NOTE: yynerrs is a global variable */ mjsousa@952: /* Hopefully the libraries do not contain any errors, so this should not occur! */ mjsousa@952: fprintf (stderr, "\n%d error(s) found in %s. Bailing out!\n", yynerrs, libfilename); mjsousa@952: return -2; etisserant@0: } mjsousa@952: mjsousa@952: /* if by any chance the library is not complete, we now add the missing reserved keywords to the list!!! */ etisserant@0: for(int i = 0; standard_function_block_names[i] != NULL; i++) mjsousa@971: if (library_element_symtable.find(standard_function_block_names[i]) == mjsousa@971: library_element_symtable.end()) etisserant@0: library_element_symtable.insert(standard_function_block_names[i], standard_function_block_name_token); etisserant@0: etisserant@0: /* now parse the input file... */ msousa@257: #if YYDEBUG msousa@257: yydebug = 1; msousa@257: #endif mjsousa@761: FILE *mainfile = NULL; mjsousa@761: if ((mainfile = parse_file(filename)) == NULL) { msousa@757: char *errmsg = strdup2("Error opening main file ", filename); msousa@757: perror(errmsg); msousa@757: free(errmsg); mjsousa@952: return -3; msousa@757: } msousa@757: mjsousa@924: allow_function_overloading = false; msousa@350: allow_extensible_function_parameters = false; mjsousa@946: allow_ref_dereferencing = runtime_options.ref_standard_extensions; mjsousa@946: allow_ref_to_any = runtime_options.ref_nonstand_extensions; mjsousa@946: allow_ref_to_in_derived_datatypes = runtime_options.ref_nonstand_extensions; mjsousa@924: //allow_ref_to_any = false; /* we only allow REF_TO ANY in library functions/FBs, no matter what the user asks for in the command line */ msousa@757: msousa@757: if (yyparse() != 0) { msousa@757: fprintf (stderr, "\nParsing failed because of too many consecutive syntax errors. Bailing out!\n"); msousa@757: exit(EXIT_FAILURE); mario@85: } mjsousa@761: fclose(mainfile); mjsousa@761: etisserant@0: if (yynerrs > 0) { msousa@516: fprintf (stderr, "\n%d error(s) found. Bailing out!\n", yynerrs /* global variable */); etisserant@0: exit(EXIT_FAILURE); etisserant@0: } mjsousa@952: mjsousa@952: return 0; mjsousa@952: } mjsousa@952: mjsousa@952: mjsousa@952: mjsousa@952: mjsousa@952: mjsousa@952: /* We parse the input source code twice!! mjsousa@952: * 1st pass --> Pre-parsing mjsousa@952: * ------------------------- mjsousa@952: * The intention of the first pass is to fill up the library_element_symtable with the names of all mjsousa@952: * the POUs (Functions, FBs, Programs and Configurations), as well as all the Derived Datatypes. mjsousa@952: * mjsousa@952: * During this pass POUs are only parsed until their name is obtained, and the remaining source mjsousa@952: * code (variable declarations and body) is completely thrown away by flex. Datatype declarations mjsousa@952: * however are parsed normally! mjsousa@952: * mjsousa@952: * At the end of the pre-parsing, the AST will contain only the derived datatype declarations, mjsousa@952: * and this tree will be trown away (by simply resetting tree_root = NULL). mjsousa@952: * More importantly, the library_element_symtable will contain the names of all the POUs and mjsousa@952: * derived datatypes. mjsousa@952: * mjsousa@952: * 2st pass --> Normal parsing mjsousa@952: * ---------------------------- mjsousa@952: * In this second parse the whole source code is parsed correctly, and the AST is generated mjsousa@952: * completely. mjsousa@952: * mjsousa@952: * However, if the pre-parsing has been done before this normal parsing, the POUs may appear mjsousa@952: * in the source code in any order, as calling a POU (e.g. calling a function) that has not yet mjsousa@952: * been declared will no longer generate a parsing error because the name of the function being mjsousa@952: * called is already in the library_element_symtable. mjsousa@952: * mjsousa@952: * Declaring variables of datatypes that have not yet been declared will also be possible, as the mjsousa@952: * datatypes will also already be in the library_element_symtable! mjsousa@952: */ mjsousa@952: mjsousa@952: int stage2__(const char *filename, mjsousa@952: symbol_c **tree_root_ref mjsousa@952: ) { mjsousa@952: char *libfilename = NULL; mjsousa@952: mjsousa@952: /* Determine the full path name of the standard library file... */ mjsousa@952: if (runtime_options.includedir != NULL) mjsousa@952: INCLUDE_DIRECTORIES[0] = runtime_options.includedir; mjsousa@952: mjsousa@952: if ((libfilename = strdup3(INCLUDE_DIRECTORIES[0], "/", LIBFILE)) == NULL) { mjsousa@952: fprintf (stderr, "Out of memory. Bailing out!\n"); mjsousa@952: exit(EXIT_FAILURE); mjsousa@952: } mjsousa@952: mjsousa@952: /*******************************/ mjsousa@952: /* Do the PRE parsing run...! */ mjsousa@952: /*******************************/ mjsousa@956: if (runtime_options.pre_parsing) { mjsousa@956: // fprintf (stderr, "----> Starting pre-parsing!\n"); mjsousa@956: tree_root = NULL; mjsousa@956: set_preparse_state(); mjsousa@956: if (parse_files(libfilename, filename) < 0) mjsousa@956: exit(EXIT_FAILURE); mjsousa@956: // TODO: delete the current AST. For the moment, we leave all the objects in memory (not much of an issue in a program that always runs to completion). mjsousa@956: } mjsousa@952: /*******************************/ mjsousa@952: /* Do the main parsing run...! */ mjsousa@952: /*******************************/ mjsousa@952: // fprintf (stderr, "----> Starting normal parsing!\n"); mjsousa@952: tree_root = NULL; mjsousa@952: rst_preparse_state(); mjsousa@952: if (parse_files(libfilename, filename) < 0) mjsousa@952: exit(EXIT_FAILURE); lbessard@134: mjsousa@952: mjsousa@952: /* Final clean-up... */ mjsousa@952: free(libfilename); etisserant@0: if (tree_root_ref != NULL) etisserant@0: *tree_root_ref = tree_root; etisserant@0: etisserant@0: return 0; etisserant@0: } etisserant@0: msousa@756: msousa@756: msousa@756: msousa@756: msousa@756: msousa@756: msousa@756: msousa@756: msousa@756: msousa@756: msousa@756: msousa@756: msousa@756: