diff -r 17bffb57a8c5 -r 0f24db96b519 stage1_2/iec_bison.yy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage1_2/iec_bison.yy Fri Aug 19 17:33:57 2011 +0100 @@ -0,0 +1,8307 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt) + * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +/* + * An IEC 61131-3 compiler. + * + * Based on the + * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) + * + */ + +/* + * Stage 2 + * ======= + * + * This file contains the syntax definition of the textual + * languages IL and ST, as well as the textual version of SFC. + * The syntax parser, comprising the 2nd stage of the overall + * compiler, is generated by runing bison on this file. + */ + + + + +/**********************************************************************/ +/**********************************************************************/ +/**********************************************************************/ +/**********************************************************************/ +/******* *******/ +/******* The following syntax does not have any conflicts. *******/ +/******* *******/ +/******* P L E A S E K E E P I T T H A T W A Y ! *******/ +/******* =================================================== *******/ +/******* *******/ +/**********************************************************************/ +/**********************************************************************/ +/**********************************************************************/ +/**********************************************************************/ + + + + +%{ +#include /* required for strdup() */ + + +/* declare the token parser generated by flex... */ +int yylex(void); + +/* declare the error handler defined at the end of this file */ +void yyerror (const char *error_msg); + +/* produce a more verbose parsing error message */ +#define YYERROR_VERBOSE + +/* Include debuging code. + * Printing of debug info must then be activated by setting + * the variable yydebug to 1. + */ +#define YYDEBUG 0 + + +/* file with declaration of absyntax classes... */ +#include "../absyntax/absyntax.hh" + +/* file with declaration of token constants. Generated by bison! */ +#include "iec_bison.h" + +/* The interface through which bison and flex interact. */ +#include "stage1_2_priv.hh" + + +#include "../absyntax_utils/add_en_eno_param_decl.hh" /* required for add_en_eno_param_decl_c */ + +/* an ugly hack!! + * We will probably not need it when we decide + * to cut down the abstract syntax down to size. + * We keep it as it is until we get to write + * stages 3 and 4 of the compiler. Who knows, + * we might just find out that we really do need + * the abstract syntax tree to stay as it is + * afterall! + */ +/* for each element in list_c * + * execute the code + */ +#define FOR_EACH_ELEMENT(elem, list, code) { \ + symbol_c *elem; \ + for(int i = 0; i < list->n; i++) { \ + elem = list->elements[i]; \ + code; \ + } \ +} + + + +/* Macros used to pass the line and column locations when + * creating a new object for the abstract syntax tree. + */ +#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 +#define locf(foo) foo.first_line, foo.first_column, foo.first_file, foo.first_order +#define locl(foo) foo.last_line, foo.last_column, foo.last_file, foo.last_order + +/* Redefine the default action to take for each rule, so that the filenames are correctly processed... */ +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \ + (Current).first_file = YYRHSLOC(Rhs, 1).first_file; \ + (Current).first_order = YYRHSLOC(Rhs, 1).first_order; \ + (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC(Rhs, N).last_column; \ + (Current).last_file = YYRHSLOC(Rhs, 1).last_file; \ + (Current).last_order = YYRHSLOC(Rhs, 1).last_order; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC(Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC(Rhs, 0).last_column; \ + (Current).first_file = (Current).last_file = \ + YYRHSLOC(Rhs, 0).last_file; \ + (Current).first_order = (Current).last_order = \ + YYRHSLOC(Rhs, 0).last_order; \ + } \ + while (0) + + +/* A macro for printing out internal parser errors... */ +#define ERROR error_exit(__FILE__,__LINE__) +/* function defined in main.cc */ +extern void error_exit(const char *file_name, int line_no); + + + +/*************************/ +/* global variables... */ +/*************************/ +/* NOTE: For some strange reason bison ver 2.3 is including these declarations + * in the iec_bison.h file, which is in turn included by flex. + * We cannot therefore define any variables over here, but merely declare + * their existance (otherwise we get errors when linking the code, since we + * would get a new variable defined each time iec_bison.h is included!). + * Even though the variables are declared 'extern' over here, they will in + * fact be defined towards the end of this same file (i.e. in the prologue) + */ + + +/* NOTE: These variable are really parameters we would like the stage2__ function to pass + * to the yyparse() function. However, the yyparse() function is created automatically + * by bison, so we cannot add parameters to this function. The only other + * option is to use global variables! yuck! + */ + +/* A global flag used to tell the parser if overloaded funtions should be allowed. + * The IEC 61131-3 standard allows overloaded funtions in the standard library, + * but disallows them in user code... + */ +extern bool allow_function_overloading; + +/* A flag to tell the compiler whether to allow the declaration + * of extensible function (i.e. functions that may have a variable number of + * input parameters, such as AND(word#33, word#44, word#55, word#66). + * This is an extension to the standard syntax. + * See comments below for details why we support this! + */ +extern bool allow_extensible_function_parameters; + +/* A global flag used to tell the parser whether to include the full variable location + * when printing out error messages... + */ +extern bool full_token_loc; + +/* A pointer to the root of the parsing tree that will be generated + * by bison. + */ +extern symbol_c *tree_root; + + + +/************************/ +/* forward declarations */ +/************************/ +/* The functions declared here are defined at the end of this file... */ + +/* Convert an il_operator_c into an identifier_c */ +symbol_c *il_operator_c_2_identifier_c(symbol_c *il_operator); + +/* return if current token is a syntax element */ +/* ERROR_CHECK_BEGIN */ +bool is_current_syntax_token(); +/* ERROR_CHECK_END */ + +/* print an error message */ +void print_err_msg(int first_line, + int first_column, + const char *first_filename, + long int first_order, + int last_line, + int last_column, + const char *last_filename, + long int last_order, + const char *additional_error_msg); +%} + + + + +// %glr-parser +// %expect-rr 1 + + +/* The following definitions need to be inside a '%code requires' + * so that they are also included in the header files. If this were not the case, + * YYLTYPE would be delcared as something in the iec.cc file, and another thing + * (actually the default value of YYLTYPE) in the iec_bison.h heder file. + */ +%code requires { +/* define a new data type to store the locations, so we can also store + * the filename in which the token is expressed. + */ +/* NOTE: since this code will be placed in the iec_bison.h header file, + * as well as the iec.cc file that also includes the iec_bison.h header file, + * declaring the typedef struct yyltype__local here would result in a + * compilation error when compiling iec.cc, as this struct would be + * declared twice. + * We therefore use the #if !defined YYLTYPE ... + * to make sure only the first declaration is parsed by the C++ compiler. + * + * At first glance it seems that what we really should do is delcare the + * YYLTYPE directly as an anonymous struct, thus: + * #define YYLTYPE struct{ ...} + * however, this also results in compilation errors. + * + * I (Mario) think this is kind of a hack. If you know how to + * do this re-declaration of YYLTYPE properly, please let me know! + */ +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED + typedef struct { + int first_line; + int first_column; + const char *first_file; + long int first_order; + int last_line; + int last_column; + const char *last_file; + long int last_order; + } yyltype__local; + #define YYLTYPE yyltype__local +#endif +} + + + +%union { + symbol_c *leaf; + list_c *list; + char *ID; /* token value */ +} + +/* + TODO: DO we need to define a destructor do free + memory when recovering from errors, or do the + class destructors already handle this? + Following is example on how to define + detructors, using the syntax: + %destructor { CODE } SYMBOLS +%union + { + char *string; + } + %token STRING + %type string + %destructor { free ($$); } STRING string +*/ + + + + +/*************************************/ +/* Prelimenary helpful constructs... */ +/*************************************/ +/* A token used to identify the very end of the input file + * after all includes have already been processed. + * + * Flex automatically returns the token with value 0 + * at the end of the file. We therefore specify here + * a token with that exact same value here, so we can use it + * to detect the very end of the input files. + */ +%token END_OF_INPUT 0 + +/* A bogus token that, in principle, flex MUST NEVER generate */ +/* USE 1: + * ====== + * This token is currently also being used as the default + * initialisation value of the token_id member in + * the symbol_c base class. + * + * USE 2 + * ===== + * This token may also be used in the future to remove + * mysterious reduce/reduce conflicts due to the fact + * that our grammar may not be LALR(1) but merely LR(1). + * This means that bison cannot handle it without some + * caoxing from ourselves. We will then need this token + * to do the coaxing... + */ +%token BOGUS_TOKEN_ID + +%type start + +%type any_identifier + +%token prev_declared_variable_name_token +%token prev_declared_direct_variable_token +%token prev_declared_fb_name_token +%type prev_declared_variable_name +%type prev_declared_direct_variable +%type prev_declared_fb_name + +%token prev_declared_simple_type_name_token +%token prev_declared_subrange_type_name_token +%token prev_declared_enumerated_type_name_token +%token prev_declared_array_type_name_token +%token prev_declared_structure_type_name_token +%token prev_declared_string_type_name_token + +%type prev_declared_simple_type_name +%type prev_declared_subrange_type_name +%type prev_declared_enumerated_type_name +%type prev_declared_array_type_name +%type prev_declared_structure_type_name +%type prev_declared_string_type_name + +%token prev_declared_derived_function_name_token +%token prev_declared_derived_function_block_name_token +%token prev_declared_program_type_name_token +%type prev_declared_derived_function_name +%type prev_declared_derived_function_block_name +%type prev_declared_program_type_name + + + + +/**********************************************************************************/ +/* B XXX - Things that are missing from the standard, but should have been there! */ +/**********************************************************************************/ + +/* Pragmas that our compiler will accept. + * See the comment in iec.flex for why these pragmas exist. + */ +%token disable_code_generation_pragma_token +%token enable_code_generation_pragma_token +%type disable_code_generation_pragma +%type enable_code_generation_pragma + + +/* All other pragmas that we do not support... */ +/* In most stage 4, the text inside the pragmas will simply be copied to the output file. + * This allows us to insert C code (if using stage 4 generating C code) + * inside/interningled with the IEC 61131-3 code! + */ +%token pragma_token +%type pragma + +/* The joining of all previous pragmas, i.e. any possible pragma */ +%type any_pragma + + +/* Where do these tokens belong?? They are missing from the standard! */ +/* NOTE: There are other tokens related to these 'EN' ENO', that are also + * missing from the standard. However, their location in the annex B is + * relatively obvious, so they have been inserted in what seems to us their + * correct place in order to ease understanding of the parser... + * + * please read the comment above the definition of 'variable' in section B1.4 for details. + */ +%token EN +%token ENO +%type en_identifier +%type eno_identifier + + + + +/***************************/ +/* B 0 - Programming Model */ +/***************************/ +%type library +%type library_element_declaration + + +/*******************************************/ +/* B 1.1 - Letters, digits and identifiers */ +/*******************************************/ +/* Done totally within flex... + letter + digit + octal_digit + hex_digit +*/ +%token identifier_token +%type identifier + +/*********************/ +/* B 1.2 - Constants */ +/*********************/ +%type constant +%type non_negative_constant + +/******************************/ +/* B 1.2.1 - Numeric Literals */ +/******************************/ +/* Done totally within flex... + bit +*/ +%type numeric_literal +%type integer_literal +%type signed_integer +%token integer_token +%type integer +%token binary_integer_token +%type binary_integer +%token octal_integer_token +%type octal_integer +%token hex_integer_token +%type hex_integer +%token real_token +%type real +%type signed_real +%type real_literal +// %type exponent +%type bit_string_literal +%type boolean_literal + +%token safeboolean_true_literal_token +%token safeboolean_false_literal_token +%token boolean_true_literal_token +%token boolean_false_literal_token + +%token FALSE +%token TRUE + + +/*******************************/ +/* B 1.2.2 - Character Strings */ +/*******************************/ +%token single_byte_character_string_token +%token double_byte_character_string_token + +%type character_string +%type single_byte_character_string +%type double_byte_character_string + + +/***************************/ +/* B 1.2.3 - Time Literals */ +/***************************/ +%type time_literal + + +/************************/ +/* B 1.2.3.1 - Duration */ +/************************/ +%type duration +%type interval +%type days +%type fixed_point +%type hours +%type minutes +%type seconds +%type milliseconds + +%type integer_d +%type integer_h +%type integer_m +%type integer_s +%type integer_ms +%type fixed_point_d +%type fixed_point_h +%type fixed_point_m +%type fixed_point_s +%type fixed_point_ms + +%token fixed_point_token +%token fixed_point_d_token +%token integer_d_token +%token fixed_point_h_token +%token integer_h_token +%token fixed_point_m_token +%token integer_m_token +%token fixed_point_s_token +%token integer_s_token +%token fixed_point_ms_token +%token integer_ms_token + +// %token TIME +%token T_SHARP + + +/************************************/ +/* B 1.2.3.2 - Time of day and Date */ +/************************************/ +%type time_of_day +%type daytime +%type day_hour +%type day_minute +%type day_second +%type date +%type date_literal +%type year +%type month +%type day +%type date_and_time + +// %token TIME_OF_DAY +// %token DATE +%token D_SHARP +// %token DATE_AND_TIME + + +/**********************/ +/* B 1.3 - Data Types */ +/**********************/ +/* Strangely, the following symbol does seem to be required! */ +// %type data_type_name +%type non_generic_type_name + + +/***********************************/ +/* B 1.3.1 - Elementary Data Types */ +/***********************************/ +/* NOTES: + * + * - To make the definition of bit_string_literal more + * concise, it is useful to use an extra non-terminal + * symbol (i.e. a grouping or construct) that groups the + * following elements (BYTE, WORD, DWORD, LWORD). + * Note that the definition of bit_string_type_name + * (according to the spec) includes the above elements + * and an extra BOOL. + * We could use an extra construct with the first four + * elements to be used solely in the definition of + * bit_string_literal, but with the objective of not + * having to replicate the actions (if we ever need + * to change them, they would need to be changed in both + * bit_string_type_name and the extra grouping), we + * have re-defined bit_string_type_name as only including + * the first four elements. + * In order to have our parser implement the specification + * correctly we have augmented every occurence of + * bit_string_type_name in other rules with the BOOL + * token. Since bit_string_type_name only appears in + * the rule for elementary_type_name, this does not + * seem to be a big concession to make! + * + * - We have added a helper symbol to concentrate the + * instantiation of STRING and WSTRING into a single + * location (elementary_string_type_name). + * These two elements show up in several other rules, + * but we want to create the equivalent abstract syntax + * in a single location of this file, in order to make + * possible future changes easier to edit... + */ +%type elementary_type_name +%type numeric_type_name +%type integer_type_name +%type signed_integer_type_name +%type unsigned_integer_type_name +%type real_type_name +%type date_type_name +%type bit_string_type_name +/* helper symbol to concentrate the instantiation + * of STRING and WSTRING into a single location + */ +%type elementary_string_type_name + +%token BYTE +%token WORD +%token DWORD +%token LWORD + +%token LREAL +%token REAL + +%token SINT +%token INT +%token DINT +%token LINT + +%token USINT +%token UINT +%token UDINT +%token ULINT + +%token WSTRING +%token STRING +%token BOOL + +%token TIME +%token DATE +%token DATE_AND_TIME +%token DT +%token TIME_OF_DAY +%token TOD + +/******************************************************/ +/* Symbols defined in */ +/* "Safety Software Technical Specification, */ +/* Part 1: Concepts and Function Blocks, */ +/* Version 1.0 – Official Release" */ +/* by PLCopen - Technical Committee 5 - 2006-01-31 */ +/******************************************************/ + +%token SAFEBYTE +%token SAFEWORD +%token SAFEDWORD +%token SAFELWORD + +%token SAFELREAL +%token SAFEREAL + +%token SAFESINT +%token SAFEINT +%token SAFEDINT +%token SAFELINT + +%token SAFEUSINT +%token SAFEUINT +%token SAFEUDINT +%token SAFEULINT + +%token SAFEWSTRING +%token SAFESTRING +%token SAFEBOOL + +%token SAFETIME +%token SAFEDATE +%token SAFEDATE_AND_TIME +%token SAFEDT +%token SAFETIME_OF_DAY +%token SAFETOD + +/********************************/ +/* B 1.3.2 - Generic data types */ +/********************************/ +/* Strangely, the following symbol does seem to be required! */ +// %type generic_type_name + +/* The following tokens do not seem to be used either + * but we declare them so they become reserved words... + */ +%token ANY +%token ANY_DERIVED +%token ANY_ELEMENTARY +%token ANY_MAGNITUDE +%token ANY_NUM +%token ANY_REAL +%token ANY_INT +%token ANY_BIT +%token ANY_STRING +%token ANY_DATE + + +/********************************/ +/* B 1.3.3 - Derived data types */ +/********************************/ +%type derived_type_name +%type single_element_type_name +// %type simple_type_name +// %type subrange_type_name +// %type enumerated_type_name +// %type array_type_name +// %type structure_type_name + +%type data_type_declaration +/* helper symbol for data_type_declaration */ +%type type_declaration_list +%type type_declaration +%type single_element_type_declaration + +%type simple_type_declaration +%type simple_spec_init +%type simple_specification + +%type subrange_type_declaration +%type subrange_spec_init +%type subrange_specification +%type subrange + +%type enumerated_type_declaration +%type enumerated_spec_init +%type enumerated_specification +/* helper symbol for enumerated_value */ +%type enumerated_value_list +%type enumerated_value +//%type enumerated_value_without_identifier + +%type array_type_declaration +%type array_spec_init +%type array_specification +/* helper symbol for array_specification */ +%type array_subrange_list +%type array_initialization +/* helper symbol for array_initialization */ +%type array_initial_elements_list +%type array_initial_elements +%type array_initial_element + +%type structure_type_declaration +%type structure_specification +%type initialized_structure +%type structure_declaration +/* helper symbol for structure_declaration */ +%type structure_element_declaration_list +%type structure_element_declaration +%type structure_element_name +%type structure_initialization +/* helper symbol for structure_initialization */ +%type structure_element_initialization_list +%type structure_element_initialization + +//%type string_type_name +%type string_type_declaration +/* helper symbol for string_type_declaration */ +%type string_type_declaration_size +/* helper symbol for string_type_declaration */ +%type string_type_declaration_init + +%token ASSIGN +%token DOTDOT /* ".." */ +%token TYPE +%token END_TYPE +%token ARRAY +%token OF +%token STRUCT +%token END_STRUCT + + + +/*********************/ +/* B 1.4 - Variables */ +/*********************/ +%type variable +%type symbolic_variable +/* helper symbol for prog_cnxn */ +%type any_symbolic_variable +%type variable_name + + + + +/********************************************/ +/* B.1.4.1 Directly Represented Variables */ +/********************************************/ +/* Done totally within flex... + location_prefix + size_prefix +*/ +%token direct_variable_token +//%type direct_variable + + +/*************************************/ +/* B.1.4.2 Multi-element Variables */ +/*************************************/ +%type multi_element_variable +/* helper symbol for any_symbolic_variable */ +%type any_multi_element_variable +%type array_variable +/* helper symbol for any_symbolic_variable */ +%type any_array_variable +%type subscripted_variable +/* helper symbol for any_symbolic_variable */ +%type any_subscripted_variable +%type subscript_list +%type subscript +%type structured_variable +/* helper symbol for any_symbolic_variable */ +%type any_structured_variable +%type record_variable +/* helper symbol for any_symbolic_variable */ +%type any_record_variable +%type field_selector + + +/******************************************/ +/* B 1.4.3 - Declaration & Initialisation */ +/******************************************/ +%type input_declarations +/* helper symbol for input_declarations */ +%type input_declaration_list +%type input_declaration +%type edge_declaration +/* en_param_declaration is not in the standard, but should be! */ +%type en_param_declaration +%type var_init_decl +%type var1_init_decl +%type var1_list +%type array_var_init_decl +%type structured_var_init_decl +%type fb_name_decl +/* helper symbol for fb_name_decl */ +%type fb_name_list_with_colon +/* helper symbol for fb_name_list_with_colon */ +%type var1_list_with_colon +// %type fb_name_list +// %type fb_name +%type output_declarations +%type var_output_init_decl +%type var_output_init_decl_list +/* eno_param_declaration is not in the standard, but should be! */ +%type eno_param_declaration +%type input_output_declarations +/* helper symbol for input_output_declarations */ +%type var_declaration_list +%type var_declaration +%type temp_var_decl +%type var1_declaration +%type array_var_declaration +%type structured_var_declaration +%type var_declarations +%type retentive_var_declarations +%type located_var_declarations +/* helper symbol for located_var_declarations */ +%type located_var_decl_list +%type located_var_decl +%type external_var_declarations +/* helper symbol for external_var_declarations */ +%type external_declaration_list +%type external_declaration +%type global_var_name +%type global_var_declarations +/* helper symbol for global_var_declarations */ +%type global_var_decl_list +%type global_var_decl +%type global_var_spec +%type located_var_spec_init +%type location +%type global_var_list +%type string_var_declaration +%type single_byte_string_var_declaration +%type single_byte_string_spec +%type double_byte_string_var_declaration +%type double_byte_string_spec +%type incompl_located_var_declarations +/* helper symbol for incompl_located_var_declarations */ +%type incompl_located_var_decl_list +%type incompl_located_var_decl +%type incompl_location +%type var_spec +/* helper symbol for var_spec */ +%type string_spec +/* intermediate helper symbol for: + * - non_retentive_var_decls + * - var_declarations + */ +%type var_init_decl_list + +%token incompl_location_token + +%token VAR_INPUT +%token VAR_OUTPUT +%token VAR_IN_OUT +%token VAR_EXTERNAL +%token VAR_GLOBAL +%token END_VAR +%token RETAIN +%token NON_RETAIN +%token R_EDGE +%token F_EDGE +%token AT + + +/***********************/ +/* B 1.5.1 - Functions */ +/***********************/ +// %type function_name +/* helper symbol for IL language */ +%type function_name_no_clashes +%type function_name_simpleop_clashes +//%type function_name_expression_clashes +/* helper symbols for ST language */ +//%type function_name_NOT_clashes +%type function_name_no_NOT_clashes + +//%type standard_function_name +/* helper symbols for IL language */ +%type standard_function_name_no_clashes +%type standard_function_name_simpleop_clashes +%type standard_function_name_expression_clashes +/* helper symbols for ST language */ +%type standard_function_name_NOT_clashes +%type standard_function_name_no_NOT_clashes + +%type derived_function_name +%type function_declaration +/* helper symbol for function_declaration */ +%type function_name_declaration +%type io_var_declarations +%type function_var_decls +%type function_body +%type var2_init_decl +/* intermediate helper symbol for function_declaration */ +%type io_OR_function_var_declarations_list +/* intermediate helper symbol for function_var_decls */ +%type var2_init_decl_list + +%token standard_function_name_token + +%token FUNCTION +%token END_FUNCTION +%token CONSTANT + + +/*****************************/ +/* B 1.5.2 - Function Blocks */ +/*****************************/ +%type function_block_type_name +%type standard_function_block_name +%type derived_function_block_name +%type function_block_declaration +%type other_var_declarations +%type temp_var_decls +%type non_retentive_var_decls +%type function_block_body +/* intermediate helper symbol for function_declaration */ +%type io_OR_other_var_declarations_list +/* intermediate helper symbol for temp_var_decls */ +%type temp_var_decls_list + +%token standard_function_block_name_token + +%token FUNCTION_BLOCK +%token END_FUNCTION_BLOCK +%token VAR_TEMP +// %token END_VAR +%token VAR +// %token NON_RETAIN +// %token END_VAR + + +/**********************/ +/* B 1.5.3 - Programs */ +/**********************/ +%type program_type_name +%type program_declaration +/* helper symbol for program_declaration */ +%type program_var_declarations_list + +%token PROGRAM +%token END_PROGRAM + + +/********************************************/ +/* B 1.6 Sequential Function Chart elements */ +/********************************************/ + +%type sequential_function_chart +%type sfc_network +%type initial_step +%type step +%type action_association_list +%type step_name +%type action_association +/* helper symbol for action_association */ +%type indicator_name_list +%type action_name +%type action_qualifier +%type qualifier +%type timed_qualifier +%type action_time +%type indicator_name +%type transition +%type steps +%type step_name_list +%type transition_priority +%type transition_condition +%type action +%type action_body +%type transition_name + + +// %token ASSIGN +%token ACTION +%token END_ACTION + +%token TRANSITION +%token END_TRANSITION +%token FROM +%token TO +%token PRIORITY + +%token INITIAL_STEP +%token STEP +%token END_STEP + +%token L +%token D +%token SD +%token DS +%token SL + +%token N +%token P +/* NOTE: the following two clash with the R and S IL operators. + * It will have to be handled when we include parsing of SFC... + */ +/* +%token R +%token S +*/ + + +/********************************/ +/* B 1.7 Configuration elements */ +/********************************/ +%type configuration_name +%type resource_type_name +%type configuration_declaration +// helper symbol for +// - configuration_declaration +// - resource_declaration +// +%type optional_global_var_declarations +// helper symbol for configuration_declaration +%type optional_access_declarations +// helper symbol for configuration_declaration +%type optional_instance_specific_initializations +// helper symbol for configuration_declaration +%type resource_declaration_list +%type resource_declaration +%type single_resource_declaration +// helper symbol for single_resource_declaration +%type task_configuration_list +// helper symbol for single_resource_declaration +%type program_configuration_list +%type resource_name +// %type access_declarations +// helper symbol for access_declarations +// %type access_declaration_list +// %type access_declaration +// %type access_path +// helper symbol for access_path +%type any_fb_name_list +%type global_var_reference +// %type access_name +%type program_output_reference +%type program_name +// %type direction +%type task_configuration +%type task_name +%type task_initialization +// 3 helper symbols for task_initialization +%type task_initialization_single +%type task_initialization_interval +%type task_initialization_priority + +%type data_source +%type program_configuration +// helper symbol for program_configuration +%type optional_task_name +// helper symbol for program_configuration +%type optional_prog_conf_elements +%type prog_conf_elements +%type prog_conf_element +%type fb_task +%type prog_cnxn +%type prog_data_source +%type data_sink +%type instance_specific_initializations +// helper symbol for instance_specific_initializations +%type instance_specific_init_list +%type instance_specific_init +// helper symbol for instance_specific_init +%type fb_initialization + +%type prev_declared_global_var_name +%token prev_declared_global_var_name_token + +%type prev_declared_program_name +%token prev_declared_program_name_token + +%type prev_declared_resource_name +%token prev_declared_resource_name_token + +%token prev_declared_configuration_name_token + +// %type prev_declared_task_name +// %token prev_declared_task_name_token + +%token CONFIGURATION +%token END_CONFIGURATION +%token TASK +%token RESOURCE +%token ON +%token END_RESOURCE +%token VAR_CONFIG +%token VAR_ACCESS +// %token END_VAR +%token WITH +// %token PROGRAM +// %token RETAIN +// %token NON_RETAIN +// %token PRIORITY +%token SINGLE +%token INTERVAL +%token READ_WRITE +%token READ_ONLY + + +/***********************************/ +/* B 2.1 Instructions and Operands */ +/***********************************/ +%type instruction_list +%type il_instruction +%type il_incomplete_instruction +%type label +%type il_simple_operation +// helper symbol for il_simple_operation +//%type il_simple_operator_clash_il_operand +%type il_expression +%type il_jump_operation +%type il_fb_call +%type il_formal_funct_call +// helper symbol for il_formal_funct_call +%type il_expr_operator_clash_eol_list +%type il_operand +%type il_operand_list +// helper symbol for il_simple_operation +%type il_operand_list2 +%type simple_instr_list +%type il_simple_instruction +%type il_param_list +%type il_param_instruction_list +%type il_param_instruction +%type il_param_last_instruction +%type il_param_assignment +%type il_param_out_assignment + +%token EOL + + +/*******************/ +/* B 2.2 Operators */ +/*******************/ +%token sendto_identifier_token +%type sendto_identifier + +%type LD_operator +%type LDN_operator +%type ST_operator +%type STN_operator +%type NOT_operator +%type S_operator +%type R_operator +%type S1_operator +%type R1_operator +%type CLK_operator +%type CU_operator +%type CD_operator +%type PV_operator +%type IN_operator +%type PT_operator +%type AND_operator +%type AND2_operator +%type OR_operator +%type XOR_operator +%type ANDN_operator +%type ANDN2_operator +%type ORN_operator +%type XORN_operator +%type ADD_operator +%type SUB_operator +%type MUL_operator +%type DIV_operator +%type MOD_operator +%type GT_operator +%type GE_operator +%type EQ_operator +%type LT_operator +%type LE_operator +%type NE_operator +%type CAL_operator +%type CALC_operator +%type CALCN_operator +%type RET_operator +%type RETC_operator +%type RETCN_operator +%type JMP_operator +%type JMPC_operator +%type JMPCN_operator + +%type il_simple_operator +%type il_simple_operator_clash +%type il_simple_operator_clash1 +%type il_simple_operator_clash2 +%type il_simple_operator_noclash + +//%type il_expr_operator +%type il_expr_operator_clash +%type il_expr_operator_noclash + +%type il_assign_operator +%type il_assign_out_operator +%type il_call_operator +%type il_return_operator +%type il_jump_operator + + +%token LD +%token LDN +%token ST +%token STN +%token NOT +%token S +%token R +%token S1 +%token R1 +%token CLK +%token CU +%token CD +%token PV +%token IN +%token PT +%token AND +%token AND2 /* character '&' in the source code*/ +%token OR +%token XOR +%token ANDN +%token ANDN2 /* characters '&N' in the source code */ +%token ORN +%token XORN +%token ADD +%token SUB +%token MUL +%token DIV +%token MOD +%token GT +%token GE +%token EQ +%token LT +%token LE +%token NE +%token CAL +%token CALC +%token CALCN +%token RET +%token RETC +%token RETCN +%token JMP +%token JMPC +%token JMPCN + +%token SENDTO /* "=>" */ + + +/***********************/ +/* B 3.1 - Expressions */ +/***********************/ +/* NOTE: + * + * - unary_operator, multiply_operator, + * add_operator and comparison_operator + * are not required. Their values are integrated + * directly into other rules... + */ +%type expression +%type xor_expression +%type and_expression +%type comparison +%type equ_expression +// %type comparison_operator +%type add_expression +// %type add_operator +%type term +// %type multiply_operator +%type power_expression +%type unary_expression +// %type unary_operator +%type primary_expression +%type non_negative_primary_expression +/* intermediate helper symbol for primary_expression */ +%type function_invocation + +// %token AND +// %token XOR +// %token OR +// %token MOD +// %token NOT +%token OPER_NE +%token OPER_GE +%token OPER_LE +%token OPER_EXP + + +/********************/ +/* B 3.2 Statements */ +/********************/ +%type statement_list +%type statement + + + +/*********************************/ +/* B 3.2.1 Assignment Statements */ +/*********************************/ +%type assignment_statement +// %token ASSIGN /* ":=" */ + + +/*****************************************/ +/* B 3.2.2 Subprogram Control Statements */ +/*****************************************/ +%type subprogram_control_statement +%type return_statement +%type fb_invocation +// %type param_assignment +%type param_assignment_formal +%type param_assignment_nonformal +/* helper symbols for fb_invocation */ +%type param_assignment_formal_list +%type param_assignment_nonformal_list + +// %token ASSIGN +// %token SENDTO /* "=>" */ +%token RETURN + + +/********************************/ +/* B 3.2.3 Selection Statements */ +/********************************/ +%type selection_statement +%type if_statement +%type case_statement +%type case_element +%type case_list +%type case_list_element +/* helper symbol for if_statement */ +%type elseif_statement_list +/* helper symbol for elseif_statement_list */ +%type elseif_statement +/* helper symbol for case_statement */ +%type case_element_list + +%token IF +%token THEN +%token ELSIF +%token ELSE +%token END_IF + +%token CASE +// %token OF +// %token ELSE +%token END_CASE + + + +/********************************/ +/* B 3.2.4 Iteration Statements */ +/********************************/ +%type iteration_statement +%type for_statement +%type control_variable +%type while_statement +%type repeat_statement +%type exit_statement +/* Integrated directly into for_statement */ +// %type for_list + +%token FOR +// %token ASSIGN +// %token TO +%token BY +%token DO +%token END_FOR + +%token WHILE +// %token DO +%token END_WHILE + +%token REPEAT +%token UNTIL +%token END_REPEAT + +%token EXIT + + +%% + + + + +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ + + +start: + library {$$ = $1;} +; + + +/**********************************************************************************/ +/* B XXX - Things that are missing from the standard, but should have been there! */ +/**********************************************************************************/ + + +/* the pragmas... */ + + +disable_code_generation_pragma: + disable_code_generation_pragma_token {$$ = new disable_code_generation_pragma_c(locloc(@$));} + +enable_code_generation_pragma: + enable_code_generation_pragma_token {$$ = new enable_code_generation_pragma_c(locloc(@$));} + +pragma: + pragma_token {$$ = new pragma_c($1, locloc(@$));} + +any_pragma: + disable_code_generation_pragma +| enable_code_generation_pragma +| pragma +; + + +/* EN/ENO */ +/* Tese tokens are essentially used as variable names, so we handle them + * similarly to these... + */ +en_identifier: + EN {$$ = new identifier_c("EN", locloc(@$));} +; + +eno_identifier: + ENO {$$ = new identifier_c("ENO", locloc(@$));} +; + + + +/*************************************/ +/* Prelimenary helpful constructs... */ +/*************************************/ + +/* NOTE: + * short version: + * identifier is used for previously undeclared identifiers + * any_identifier is used when any identifier, previously + * declared or not, is required in the syntax. + * + * long version: + * When flex comes across an identifier, it first + * searches through the currently declared variables, + * functions, types, etc... to determine if it has + * been previously declared. + * Only if the identifier has not yet been declared + * will it return an identifier_token (later turned into + * an identifier symbol by the bison generated syntax parser). + * + * Some constructs in the syntax, such as when calling + * a function 'F(var1 := 1; var2 := 2);', will accept _any_ + * identifier in 'var1', even if it has been previously + * declared in the current scope, since var1 belongs to + * another scope (the variables declared in function F). + * + * For the above reason, we need to define the symbol + * any_identifier. All the symbols that may become an + * any_identifier are expected to be stored in the + * abstract syntax as a identifier_c + */ +/* NOTE: + * Type names, function names, function block type names and + * program type names are considerd keywords once they are defined, + * so may no longer be used for variable names! + * BUT the spec is confusing on this issue, as it is not clear when + * a function name should be considered as defined. If it is to be + * considered defined only from the location from where it is declared + * and onwards, it means that before it is declared its name may be + * used for variable names! + * This means that we must allow names previously used for functions + * (et. al.) to also constitue an any_identifier! + */ +any_identifier: + identifier +| prev_declared_fb_name +| prev_declared_variable_name +/**/ +| prev_declared_enumerated_type_name +| prev_declared_simple_type_name +| prev_declared_subrange_type_name +| prev_declared_array_type_name +| prev_declared_structure_type_name +| prev_declared_string_type_name +| prev_declared_derived_function_name +| prev_declared_derived_function_block_name +| prev_declared_program_type_name +/**/ +| prev_declared_resource_name +| prev_declared_program_name +| prev_declared_global_var_name +; + + +prev_declared_variable_name: prev_declared_variable_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_fb_name: prev_declared_fb_name_token {$$ = new identifier_c($1, locloc(@$));}; + +prev_declared_simple_type_name: prev_declared_simple_type_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_subrange_type_name: prev_declared_subrange_type_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_enumerated_type_name: prev_declared_enumerated_type_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_array_type_name: prev_declared_array_type_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_structure_type_name: prev_declared_structure_type_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_string_type_name: prev_declared_string_type_name_token {$$ = new identifier_c($1, locloc(@$));}; + +prev_declared_derived_function_name: prev_declared_derived_function_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_derived_function_block_name: prev_declared_derived_function_block_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_program_type_name: prev_declared_program_type_name_token {$$ = new identifier_c($1, locloc(@$));}; + + + +/***************************/ +/* B 0 - Programming Model */ +/***************************/ +library: + /* empty */ + {if (tree_root == NULL) + tree_root = new library_c(); + $$ = (list_c *)tree_root; + } +| library library_element_declaration + {$$ = $1; $$->add_element($2);} +| library any_pragma + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| library error library_element_declaration + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unknown syntax error."); yyerrok;} +| library error END_OF_INPUT + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unknown syntax error."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +library_element_declaration: + data_type_declaration +| function_declaration +| function_block_declaration +| program_declaration +| configuration_declaration +; + + + +/*******************************************/ +/* B 1.1 - Letters, digits and identifiers */ +/*******************************************/ +/* NOTE: the spec defines identifier as: + * identifier ::= (letter|('_' (letter|digit))) {['_'] (letter|digit)} + * In essence, any sequence of letters or digits, starting with a letter + * or '_'. + * + * On section 2.1.3 (pg 26) , the spec states + * "The keywords listed in annex C shall not be used for any other purpose, + * e.g., variable names or extensions as defined in 1.5.1." + * (NOTE: the spec itself does not follow this rule, as it defines standard + * functions with names identidal to keywords, e.g. 'MOD', 'NOT' !!. This is + * another issue altogether, and is worked around somewhere else...) + * + * This means that we must re-define indentifier so as to exclude + * any keywords defined in annex C. + * + * Note also that the list includes + * - Data type names + * - Function names + * - Function Block names + * This means that any named used for a function name, data type name + * or function block name, essentially becomes a keyword, and may therefore + * no longer be re-used for any other use! (see NOTE 2) + * + * In our case, excluding the keywords is achieved in the lexical parser, + * by two mechanisms: + * (1) giving higher priority to the keywords (tokens) than to identifiers, + * so when the lexical parser finds a keyword it will be parsed as a + * token before being parsed as an identifier. + * (2) when an identifier is found that is not a keyword, the lexical parser + * then looks in the global symbol table, and will not return an identifier + * if the name has been previously used as a data type name, function name, + * or function block name! (In these cases it will return a + * prev_declared_function_name_token, etc...). + * + * Unfortunately, the language (especially IL) uses tokens that are + * not defined as keywords in the spec (e.g. 'IN', 'R1', 'S1', 'PT', etc...)! + * This means that it is valid to name a function 'IN', a variable 'PT', etc... + * In order to solve this potential ambiguity, flex only parses the above + * identifiers as keywords / tokens if we are currently parsing IL code. + * When parsing all code other than IL code, the above identifiers are treated + * just like any other identifier. + * + * + * + * + * NOTE 2: + * I (Mario) find it strange that the writers of the spec really want + * names previously used for function names, data type names or function + * block names, to become full fledged keywords. I understand that they + * do not want these names being used as variable names, but how about + * enumeration values? How about structure element names? + * If we interpret the spec literally, these would not be accepted, + * which would probably burden the programmer quite a bit, in making sure + * all these name don't clash! + * + * + * + * NOTE 3: The keywords, as specified in Annex C are... + * + * - Data type names + * - Function names + * - Function Block names + * - ACTION...END_ACTION + * - ARRAY...OF + * - AT + * - CASE...OF...ELSE...END_CASE + * - CONFIGURATION...END_CONFIGURATION + * - CONSTANT + * - EN, ENO + * - EXIT + * - FALSE + * - F_EDGE + * - FOR...TO...BY...DO...END_FOR + * - FUNCTION...END_FUNCTION + * - FUNCTION_BLOCK...END_FUNCTION_BLOCK + * - IF...THEN...ELSIF...ELSE...END_IF + * - INITIAL_STEP...END_STEP + * - NOT, MOD, AND, XOR, OR + * - PROGRAM...WITH... + * - PROGRAM...END_PROGRAM + * - R_EDGE + * - READ_ONLY, READ_WRITE + * - REPEAT...UNTIL...END_REPEAT + * - RESOURCE...ON...END_RESOURCE + * - RETAIN, NON_RETAIN + * - RETURN + * - STEP...END_STEP + * - STRUCT...END_STRUCT + * - TASK + * - TRANSITION...FROM...TO...END_TRANSITION + * - TRUE + * - TYPE...END_TYPE + * - VAR...END_VAR + * - VAR_INPUT...END_VAR + * - VAR_OUTPUT...END_VAR + * - VAR_IN_OUT...END_VAR + * - VAR_TEMP...END_VAR + * - VAR_EXTERNAL...END_VAR + * - VAR_ACCESS...END_VAR + * - VAR_CONFIG...END_VAR + * - VAR_GLOBAL...END_VAR + * - WHILE...DO...END_WHILE + * - WITH + */ + +identifier: + identifier_token {$$ = new identifier_c($1, locloc(@$));} +; + + + +/*********************/ +/* B 1.2 - Constants */ +/*********************/ +constant: + numeric_literal +| character_string +| time_literal +| bit_string_literal +| boolean_literal +/* NOTE: in order to remove reduce/reduce conflicts, + * [between -9.5 being parsed as + * (i) a signed real, + * (ii) or as a real preceded by the '-' operator + * ] + * we need to define a variant of the constant construct + * where any constant is never preceded by the '-' character. + * In order to do this, we have borugh the signed_real + * directly into the definition of the constant construct + * (so we can define another non_negative_constant + * construct that does not include it!) + */ +| signed_real +/* NOTE: in order to remove reduce/reduce conflicts, + * unsigned_integer, signed_integer, binary_integer, octal_integer + * and hex_integer have been integrated directly into + * the constants construct, instead of belonging to + * both the bit_string_literal or integer_literal + * construct. + */ +/* NOTE: unsigned_integer, although used in some + * rules, is not defined in the spec! + * We therefore replaced unsigned_integer as integer + */ +/*| integer {} */ /* i.e. an unsigned_integer */ /* NOTE: already included as a signed integer! */ +| signed_integer +| binary_integer +| octal_integer +| hex_integer +; + + +/* NOTE: in order to remove reduce/reduce conflicts, + * [between -9.5 being parsed as + * (i) a signed real, + * (ii) or as a real preceded by the '-' operator + * ] + * we need to define a variant of the constant construct + * where any constant is never preceded by the '-' character. + * In order to do this, we have borugh the signed_real + * directly into the definition of the constant construct + * (so we can define another non_negative_constant + * construct that does not include it!) + */ +non_negative_constant: + numeric_literal +| character_string +| time_literal +| bit_string_literal +| boolean_literal +/* NOTE: in order to remove reduce/reduce conflicts, + * [between -9.5 being parsed as + * (i) a signed real, + * (ii) or as a real preceded by the '-' operator + * ] + * we need to define a variant of the constant construct + * where any constant is never preceded by the '-' character. + * In order to do this, we have borugh the signed_real + * directly into the definition of the constant construct + * (so we can define another non_negative_constant + * construct that does not include it!) + */ +/* | signed_real */ +| real /* an unsigned real */ +/* NOTE: in order to remove reduce/reduce conflicts, + * unsigned_integer, signed_integer, binary_integer, octal_integer + * and hex_integer have been integrated directly into + * the constants construct, instead of belonging to + * both the bit_string_literal or integer_literal + * construct. + */ +/* NOTE: unsigned_integer, although used in some + * rules, is not defined in the spec! + * We therefore replaced unsigned_integer as integer + */ +| integer /* i.e. an unsigned_integer */ +/* | signed_integer */ +| binary_integer +| octal_integer +| hex_integer +; + + +/******************************/ +/* B 1.2.1 - Numeric Literals */ +/******************************/ +/* NOTES: + * + * - integer is parsed by flex, but signed_integer + * is parsed by bison. Flex cannot parse a signed + * integer correctly! For example: '123+456' + * would be parsed by flex as an {integer} {signed_integer} + * instead of {integer} '+' {integer} + * + * - Neither flex nor bison can parse a real_literal + * completely (and correctly). + * Note that we cannot use the definition of real in bison as + * real: signed_integer '.' integer [exponent] + * exponent: {'E'|'e'} ['+'|'-'] integer + * because 123e45 would be parsed by flex as + * integer (123) identifier (e45). + * I.e., flex never hands over an 'e' directly to + * bison, but rather interprets it as an identifier. + * I guess we could jump through hoops and get it + * working in bison, but the following alternative + * seems more straight forward... + * + * We therefore had to break up the definition of + * real_literal in discrete parts: + * real_literal: [real_type_name '#'] singned_real + * signed_real: ['+'|'-'] real + * Flex handles real, while bison handles signed_real + * and real_literal. + * + * - According to the spec, integer '.' integer + * may be reduced to either a real or a fixed_point. + * It is nevertheless possible to figure out from the + * context which of the two rules should be used in + * the reduction. + * Unfortunately, due to the issue described above + * regarding the exponent of a real, the syntax + * integer '.' integer + * must be parsed by flex as a single token (i.e. + * fixed_point_token). This means we must add fixed_point + * to the definition of real! + * + * - The syntax also uses a construct + * fixed_point: integer ['.' integer] + * Notice that real is not defined based on fixed point, + * but rather off integer thus: + * real: integer '.' integer [exponent] + * This means that a real may not be composed of a single + * integer, unlike the construct fixed_point! + * This also means that a + * integer '.' integer + * could be reduced to either a real or a fixed_point + * construct. It is probably possible to decide by looking + * at the context, BUT: + * Unfortunatley, due to the reasons explained way above, + * a real (with an exponent) has to be handled by flex as a + * whole. This means that we cannot leave to bison (the syntax + * parser) the decision of how to reduce an + * integer '.' integer + * (either to real or to fixed_point) + * The decision on how to reduce it would need to be done by + * ther lexical analyser (i.e. flex). But flex cannot do this + * sort of thing. + * The solution I (Mario) adopted is to have flex return + * a real_token on (notice that exponent is no longer optional) + * integer '.' integer exponent + * and to return a fixed_point_token when it finds + * integer '.' integer + * We now redefine real and fixed_point to be + * fixed_point: fixed_point_token | integer + * real: real_token | fixed_point_token + */ +real: + real_token {$$ = new real_c($1, locloc(@$));} +| fixed_point_token {$$ = new real_c($1, locloc(@$));} +; + +integer: integer_token {$$ = new integer_c($1, locloc(@$));}; +binary_integer: binary_integer_token {$$ = new binary_integer_c($1, locloc(@$));}; +octal_integer: octal_integer_token {$$ = new octal_integer_c($1, locloc(@$));}; +hex_integer: hex_integer_token {$$ = new hex_integer_c($1, locloc(@$));}; + +numeric_literal: + integer_literal +| real_literal +; + + +integer_literal: + integer_type_name '#' signed_integer + {$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));} +| integer_type_name '#' binary_integer + {$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));} +| integer_type_name '#' octal_integer + {$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));} +| integer_type_name '#' hex_integer + {$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));} +/* NOTE: see note in the definition of constant for reason + * why signed_integer, binary_integer, octal_integer + * and hex_integer are missing here! + */ +/* ERROR_CHECK_BEGIN */ +| integer_type_name signed_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} +| integer_type_name binary_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} +| integer_type_name octal_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} +| integer_type_name hex_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between integer type name and value in integer literal."); yynerrs++;} +| integer_type_name '#' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for integer literal.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for integer literal."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +signed_integer: + integer +| '+' integer {$$ = $2;} +| '-' integer {$$ = new neg_integer_c($2, locloc(@$));} +; + + +real_literal: +/* NOTE: see note in the definition of constant for reason + * why signed_real is missing here! + */ +/* signed_real */ + real_type_name '#' signed_real + {$$ = new real_literal_c($1, $3, locf(@1), locl(@3));} +/* ERROR_CHECK_BEGIN */ +| real_type_name signed_real + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between real type name and value in real literal."); yynerrs++;} +| real_type_name '#' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for real literal.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for real literal."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +signed_real: + real +| '+' real {$$ = $2;} +| '-' real {$$ = new neg_real_c($2, locloc(@2));} +; + + + +bit_string_literal: + bit_string_type_name '#' integer /* i.e. unsigned_integer */ + {$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));} +| bit_string_type_name '#' binary_integer + {$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));} +| bit_string_type_name '#' octal_integer + {$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));} +| bit_string_type_name '#' hex_integer + {$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));} +/* NOTE: see note in the definition of constant for reason + * why unsigned_integer, binary_integer, octal_integer + * and hex_integer are missing here! + */ +/* NOTE: see note under the B 1.2.1 section of token + * and grouping type definition for reason why the use of + * bit_string_type_name, although seemingly incorrect, is + * really correct here! + */ +/* ERROR_CHECK_BEGIN */ +| bit_string_type_name integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} +| bit_string_type_name binary_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} +| bit_string_type_name octal_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} +| bit_string_type_name hex_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between bit string type name and value in bit string literal."); yynerrs++;} +| bit_string_type_name '#' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for bit string literal.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for bit string literal."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +boolean_literal: + boolean_true_literal_token + {$$ = new boolean_literal_c(new bool_type_name_c(locloc(@$)), + new boolean_true_c(locloc(@$)), + locloc(@$)); + } +| boolean_false_literal_token + {$$ = new boolean_literal_c(new bool_type_name_c(locloc(@$)), + new boolean_false_c(locloc(@$)), + locloc(@$)); + } +| safeboolean_true_literal_token + {$$ = new boolean_literal_c(new safebool_type_name_c(locloc(@$)), + new boolean_true_c(locloc(@$)), + locloc(@$)); + } +| safeboolean_false_literal_token + {$$ = new boolean_literal_c(new safebool_type_name_c(locloc(@$)), + new boolean_false_c(locloc(@$)), + locloc(@$)); + } +| FALSE + {$$ = new boolean_literal_c(NULL, + new boolean_false_c(locloc(@$)), + locloc(@$)); + } +| TRUE + {$$ = new boolean_literal_c(NULL, + new boolean_true_c(locloc(@$)), + locloc(@$)); + } +/* +| BOOL '#' '1' {} +| BOOL '#' '0' {} +*/ +/* NOTE: the rules + * BOOL '#' '1' + * and + * BOOL '#' '0' + * do not work as expected... + * Consider that we are using 'BOOL' and '#' as tokens + * that flex hands over to bison (yacc). Because flex would + * then parse the single '1' or '0' as an integer, + * the rule in bison would have to be + * BOOL '#' integer, followed by verifying of the + * integer has the correct value! + * + * We therefore have flex return TRUE whenever it + * comes across 'TRUE' or 'BOOL#1', and FALSE whenever + * it comes across 'FALSE' or 'BOOL#0'. + * Note that this means that flex will parse "BOOL#01" + * as FALSE followed by an integer ('1'). + * Bison should detect this as an error, so we should + * be OK. + * + * Another option would be to change the rules to accept + * BOOL '#' integer + * but then check whether the integer has a correct + * value! At the moment I feel that the first option + * is more straight forward. + */ +; + + + +/*******************************/ +/* B 1.2.2 - Character Strings */ +/*******************************/ +/* Transform the tokens given us by flex into leafs */ +single_byte_character_string: single_byte_character_string_token + {$$ = new single_byte_character_string_c($1, locloc(@$));}; + +double_byte_character_string: double_byte_character_string_token + {$$ = new double_byte_character_string_c($1, locloc(@$));}; + + +character_string: + single_byte_character_string +| double_byte_character_string +; + + + + + +/***************************/ +/* B 1.2.3 - Time Literals */ +/***************************/ +time_literal: + time_of_day +| date +| date_and_time +| duration +; + + +/************************/ +/* B 1.2.3.1 - Duration */ +/************************/ +duration: +/* (T | TIME) '#' ['-'] interval */ +/* NOTE: since TIME is also a data type, it is a keyword + * and may therefore be handled by a token. + * + * Unfortunately T is not a data type, and therefore + * not a keyword. This means that we may have variables named T! + * Flex cannot return the token TIME when it comes across a single T! + * + * We therefore have flex returning the token T_SHARP + * when it comes across 'T#' + */ + TIME '#' interval + {$$ = new duration_c(new time_type_name_c(locloc(@1)), NULL, $3, locloc(@$));} +| TIME '#' '-' interval + {$$ = new duration_c(new time_type_name_c(locloc(@1)), new neg_time_c(locloc(@$)), $4, locloc(@$));} +| T_SHARP interval + {$$ = new duration_c(new time_type_name_c(locloc(@1)), NULL, $2, locloc(@$));} +| T_SHARP '-' interval + {$$ = new duration_c(new time_type_name_c(locloc(@1)), new neg_time_c(locloc(@$)), $3, locloc(@$));} +| SAFETIME '#' interval + {$$ = new duration_c(new safetime_type_name_c(locloc(@1)), NULL, $3, locloc(@$));} +| SAFETIME '#' '-' interval + {$$ = new duration_c(new safetime_type_name_c(locloc(@1)), new neg_time_c(locloc(@$)), $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| TIME interval + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME' and interval in duration."); yynerrs++;} +| TIME '-' interval + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME' and interval in duration."); yynerrs++;} +| TIME '#' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for duration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for duration."); yyclearin;} + yyerrok; + } +| T_SHARP error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no value defined for duration.");} + else {print_err_msg(locf(@2), locl(@2), "invalid value for duration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +interval: + days +| hours +| minutes +| seconds +| milliseconds +; + +integer_d: integer_d_token {$$ = new integer_c($1, locloc(@$));}; +integer_h: integer_h_token {$$ = new integer_c($1, locloc(@$));}; +integer_m: integer_m_token {$$ = new integer_c($1, locloc(@$));}; +integer_s: integer_s_token {$$ = new integer_c($1, locloc(@$));}; +integer_ms: integer_ms_token {$$ = new integer_c($1, locloc(@$));}; + +fixed_point_d: + fixed_point_d_token + {$$ = new fixed_point_c($1, locloc(@$));} +| integer_d +; + +fixed_point_h: + fixed_point_h_token + {$$ = new fixed_point_c($1, locloc(@$));} +| integer_h +; + +fixed_point_m: + fixed_point_m_token + {$$ = new fixed_point_c($1, locloc(@$));} +| integer_m +; + +fixed_point_s: + fixed_point_s_token + {$$ = new fixed_point_c($1, locloc(@$));} +| integer_s +; + +fixed_point_ms: + fixed_point_ms_token + {$$ = new fixed_point_c($1, locloc(@$));} +| integer_ms +; + + +fixed_point: + fixed_point_token + {$$ = new fixed_point_c($1, locloc(@$));} +| integer +; + + +days: +/* fixed_point ('d') */ + fixed_point_d + {$$ = new days_c($1, NULL, locloc(@$));} +/*| integer ('d') ['_'] hours */ +| integer_d hours + {$$ = new days_c($1, $2, locloc(@$));} +| integer_d '_' hours + {$$ = new days_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| integer_d '_' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for hours in duration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for hours in duration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +hours: +/* fixed_point ('h') */ + fixed_point_h + {$$ = new hours_c($1, NULL, locloc(@$));} +/*| integer ('h') ['_'] minutes */ +| integer_h minutes + {$$ = new hours_c($1, $2, locloc(@$));} +| integer_h '_' minutes + {$$ = new hours_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| integer_h '_' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for minutes in duration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for minutes in duration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ + +; + +minutes: +/* fixed_point ('m') */ + fixed_point_m + {$$ = new minutes_c($1, NULL, locloc(@$));} +/*| integer ('m') ['_'] seconds */ +| integer_m seconds + {$$ = new minutes_c($1, $2, locloc(@$));} +| integer_m '_' seconds + {$$ = new minutes_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| integer_m '_' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for seconds in duration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for seconds in duration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +seconds: +/* fixed_point ('s') */ + fixed_point_s + {$$ = new seconds_c($1, NULL, locloc(@$));} +/*| integer ('s') ['_'] milliseconds */ +| integer_s milliseconds + {$$ = new seconds_c($1, $2, locloc(@$));} +| integer_s '_' milliseconds + {$$ = new seconds_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| integer_s '_' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for milliseconds in duration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for milliseconds in duration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +milliseconds: +/* fixed_point ('ms') */ + fixed_point_ms + {$$ = new milliseconds_c($1, locloc(@$));} +; + + + +/************************************/ +/* B 1.2.3.2 - Time of day and Date */ +/************************************/ +time_of_day: + TIME_OF_DAY '#' daytime + {$$ = new time_of_day_c(new tod_type_name_c(locloc(@1)), $3, locloc(@$));} +| SAFETIME_OF_DAY '#' daytime + {$$ = new time_of_day_c(new safetod_type_name_c(locloc(@1)), $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| TIME_OF_DAY daytime + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME_OF_DAY' and daytime in time of day."); yynerrs++;} +| TIME_OF_DAY '#' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for time of day.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for time of day."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +daytime: + day_hour ':' day_minute ':' day_second + {$$ = new daytime_c($1, $3, $5, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| ':' day_minute ':' day_second + {$$ = NULL; print_err_msg(locf(@1), locl(@4), "no value defined for hours in daytime."); yynerrs++;} +| error ':' day_minute ':' day_second + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid value defined for hours in daytime."); yyerrok;} +| day_hour day_minute ':' day_second + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between hours and minutes in daytime."); yynerrs++;} +| day_hour ':' ':' day_second + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no value defined for minutes in daytime."); yynerrs++;} +| day_hour ':' error ':' day_second + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value defined for minutes in daytime."); yyerrok;} +| day_hour ':' day_minute day_second + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "':' missing between minutes and seconds in daytime."); yynerrs++;} +| day_hour ':' day_minute ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@4), locf(@5), "no value defined for seconds in daytime.");} + else {print_err_msg(locf(@5), locl(@5), "invalid value for seconds in daytime."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +day_hour: integer; +day_minute: integer; +day_second: fixed_point; + + +date: + DATE '#' date_literal + {$$ = new date_c(new date_type_name_c(locloc(@1)), $3, locloc(@$));} +| D_SHARP date_literal + {$$ = new date_c(new date_type_name_c(locloc(@1)), $2, locloc(@$));} +| SAFEDATE '#' date_literal + {$$ = new date_c(new safedate_type_name_c(locloc(@1)), $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| DATE date_literal + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'DATE' and date literal in date."); yynerrs++;} +| DATE '#' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for date.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for date."); yyclearin;} + yyerrok; + } +| D_SHARP error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no value defined for date.");} + else {print_err_msg(locf(@2), locl(@2), "invalid value for date."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +date_literal: + year '-' month '-' day + {$$ = new date_literal_c($1, $3, $5, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| '-' month '-' day + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no value defined for year in date literal."); yynerrs++;} +| year month '-' day + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'-' missing between year and month in date literal."); yynerrs++;} +| year '-' '-' day + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no value defined for month in date literal."); yynerrs++;} +| year '-' error '-' day + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value defined for month in date literal."); yyerrok;} +| year '-' month day + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "'-' missing between month and day in date literal."); yynerrs++;} +| year '-' month '-' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@4), locf(@5), "no value defined for day in date literal.");} + else {print_err_msg(locf(@5), locl(@5), "invalid value for day in date literal."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +year: integer; +month: integer; +day: integer; + + +date_and_time: + DATE_AND_TIME '#' date_literal '-' daytime + {$$ = new date_and_time_c(new dt_type_name_c(locloc(@1)), $3, $5, locloc(@$));} +| SAFEDATE_AND_TIME '#' date_literal '-' daytime + {$$ = new date_and_time_c(new safedt_type_name_c(locloc(@1)), $3, $5, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| DATE_AND_TIME date_literal '-' daytime + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'DATE_AND_TIME' and date literal in date and time."); yynerrs++;} +| DATE_AND_TIME '#' '-' daytime + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no value defined for date literal in date and time."); yynerrs++;} +| DATE_AND_TIME '#' error '-' daytime + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value for date literal in date and time."); yyerrok;} +| DATE_AND_TIME '#' date_literal daytime + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "'-' missing between date literal and daytime in date and time."); yynerrs++;} +| DATE_AND_TIME '#' date_literal '-' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@4), locf(@5), "no value defined for daytime in date and time.");} + else {print_err_msg(locf(@5), locl(@5), "invalid value for daytime in date and time."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + + + + +/**********************/ +/* B 1.3 - Data Types */ +/**********************/ +/* Strangely, the following symbol does seem to be required! */ +/* +data_type_name: + non_generic_type_name +| generic_type_name +; +*/ + +non_generic_type_name: + elementary_type_name +| derived_type_name +; + + + +/***********************************/ +/* B 1.3.1 - Elementary Data Types */ +/***********************************/ + /******************************************************/ + /* SAFExxxx Symbols defined in */ + /* "Safety Software Technical Specification, */ + /* Part 1: Concepts and Function Blocks, */ + /* Version 1.0 – Official Release" */ + /* by PLCopen - Technical Committee 5 - 2006-01-31 */ + /******************************************************/ + +elementary_type_name: + numeric_type_name +| date_type_name +| bit_string_type_name +| elementary_string_type_name +| TIME {$$ = new time_type_name_c(locloc(@$));} +| BOOL {$$ = new bool_type_name_c(locloc(@$));} +/* NOTE: see note under the B 1.2.1 section of token + * and grouping type definition for reason why BOOL + * was added to this definition. + */ +| SAFETIME {$$ = new safetime_type_name_c(locloc(@$));} +| SAFEBOOL {$$ = new safebool_type_name_c(locloc(@$));} +; + +numeric_type_name: + integer_type_name +| real_type_name +; + +integer_type_name: + signed_integer_type_name +| unsigned_integer_type_name +; + +signed_integer_type_name: + SINT {$$ = new sint_type_name_c(locloc(@$));} +| INT {$$ = new int_type_name_c(locloc(@$));} +| DINT {$$ = new dint_type_name_c(locloc(@$));} +| LINT {$$ = new lint_type_name_c(locloc(@$));} +| SAFESINT {$$ = new safesint_type_name_c(locloc(@$));} +| SAFEINT {$$ = new safeint_type_name_c(locloc(@$));} +| SAFEDINT {$$ = new safedint_type_name_c(locloc(@$));} +| SAFELINT {$$ = new safelint_type_name_c(locloc(@$));} +; + +unsigned_integer_type_name: + USINT {$$ = new usint_type_name_c(locloc(@$));} +| UINT {$$ = new uint_type_name_c(locloc(@$));} +| UDINT {$$ = new udint_type_name_c(locloc(@$));} +| ULINT {$$ = new ulint_type_name_c(locloc(@$));} +| SAFEUSINT {$$ = new safeusint_type_name_c(locloc(@$));} +| SAFEUINT {$$ = new safeuint_type_name_c(locloc(@$));} +| SAFEUDINT {$$ = new safeudint_type_name_c(locloc(@$));} +| SAFEULINT {$$ = new safeulint_type_name_c(locloc(@$));} +; + +real_type_name: + REAL {$$ = new real_type_name_c(locloc(@$));} +| LREAL {$$ = new lreal_type_name_c(locloc(@$));} +| SAFEREAL {$$ = new safereal_type_name_c(locloc(@$));} +| SAFELREAL {$$ = new safelreal_type_name_c(locloc(@$));} +; + +date_type_name: + DATE {$$ = new date_type_name_c(locloc(@$));} +| TIME_OF_DAY {$$ = new tod_type_name_c(locloc(@$));} +| TOD {$$ = new tod_type_name_c(locloc(@$));} +| DATE_AND_TIME {$$ = new dt_type_name_c(locloc(@$));} +| DT {$$ = new dt_type_name_c(locloc(@$));} +| SAFEDATE {$$ = new safedate_type_name_c(locloc(@$));} +| SAFETIME_OF_DAY {$$ = new safetod_type_name_c(locloc(@$));} +| SAFETOD {$$ = new safetod_type_name_c(locloc(@$));} +| SAFEDATE_AND_TIME {$$ = new safedt_type_name_c(locloc(@$));} +| SAFEDT {$$ = new safedt_type_name_c(locloc(@$));} +; + + +bit_string_type_name: + BYTE {$$ = new byte_type_name_c(locloc(@$));} +| WORD {$$ = new word_type_name_c(locloc(@$));} +| DWORD {$$ = new dword_type_name_c(locloc(@$));} +| LWORD {$$ = new lword_type_name_c(locloc(@$));} +| SAFEBYTE {$$ = new safebyte_type_name_c(locloc(@$));} +| SAFEWORD {$$ = new safeword_type_name_c(locloc(@$));} +| SAFEDWORD {$$ = new safedword_type_name_c(locloc(@$));} +| SAFELWORD {$$ = new safelword_type_name_c(locloc(@$));} +/* NOTE: see note under the B 1.2.1 section of token + * and grouping type definition for reason why the BOOL + * was omitted from this definition. + */ +; + + +/* Helper symbol to concentrate the instantiation + * of STRING and WSTRING into a single location. + * + * These two elements show up in several other rules, + * but we want to create the equivalent abstract syntax + * in a single location of this file, in order to make + * possible future changes easier to edit... + */ +elementary_string_type_name: + STRING {$$ = new string_type_name_c(locloc(@$));} +| WSTRING {$$ = new wstring_type_name_c(locloc(@$));} +| SAFESTRING {$$ = new safestring_type_name_c(locloc(@$));} +| SAFEWSTRING {$$ = new safewstring_type_name_c(locloc(@$));} +; + + + +/********************************/ +/* B 1.3.2 - Generic data types */ +/********************************/ +/* Strangely, the following symbol does not seem to be required! */ +/* +generic_type_name: + ANY +| ANY_DERIVED +| ANY_ELEMENTARY +| ANY_MAGNITUDE +| ANY_NUM +| ANY_REAL +| ANY_INT +| ANY_BIT +| ANY_STRING +| ANY_DATE +; +*/ + + +/********************************/ +/* B 1.3.3 - Derived data types */ +/********************************/ + +derived_type_name: + single_element_type_name +| prev_declared_array_type_name +| prev_declared_structure_type_name +| prev_declared_string_type_name +; + +single_element_type_name: + prev_declared_simple_type_name +/* Include the following if arrays of function blocks are to be allowed! + * Since the standard does not allow them, + * we leave it commented out for the time being... + */ +//| prev_declared_derived_function_block_name +| prev_declared_subrange_type_name +| prev_declared_enumerated_type_name +; + +/* NOTE: in order to remove a reduce/reduce conflict, + * all occurences of simple_type_name, etc... + * have been replaced with identifier! + */ +/* +simple_type_name: identifier; +subrange_type_name: identifier; +enumerated_type_name: identifier; +array_type_name: identifier; +structure_type_name: identifier; +*/ + +data_type_declaration: + TYPE type_declaration_list END_TYPE + {$$ = new data_type_declaration_c($2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| TYPE END_TYPE + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no data type declared in data type(s) declaration."); yynerrs++;} +| TYPE error type_declaration_list END_TYPE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'TYPE' in data type(s) declaration."); yyerrok;} +| TYPE type_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed data type(s) declaration."); yyerrok;} +| TYPE error END_TYPE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in data type(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for data_type_declaration */ +type_declaration_list: + type_declaration ';' + {$$ = new type_declaration_list_c(locloc(@$)); $$->add_element($1);} +| type_declaration_list type_declaration ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new type_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid data type declaration."); yyerrok;} +| type_declaration error + {$$ = new type_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of data type declaration."); yyerrok;} +| type_declaration_list type_declaration error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of data type declaration."); yyerrok;} +| type_declaration_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid data type declaration."); yyerrok;} +| type_declaration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after data type declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +type_declaration: + single_element_type_declaration +| array_type_declaration +| structure_type_declaration +| string_type_declaration +; + +single_element_type_declaration: + simple_type_declaration +| subrange_type_declaration +| enumerated_type_declaration +; + +simple_type_declaration: +/* simple_type_name ':' simple_spec_init */ + identifier ':' simple_spec_init + {$$ = new simple_type_declaration_c($1, $3, locloc(@$)); + library_element_symtable.insert($1, prev_declared_simple_type_name_token); + } +/* ERROR_CHECK_BEGIN */ +| error ':' simple_spec_init + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for data type declaration.");yyerrok;} +| identifier simple_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in simple type declaration."); yynerrs++;} +| identifier ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in data type declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in data type declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +simple_spec_init: + simple_specification + /* The following commented line was changed to the + * next two lines so that we wouldn't + * have the first element of a simple_spec_init_c() + * pointing to another simple_spec_init_c! + */ +/* +| simple_specification ASSIGN constant + {$$ = new simple_spec_init_c($1, $3);} +*/ +| elementary_type_name ASSIGN constant + {$$ = new simple_spec_init_c($1, $3, locloc(@$));} +| prev_declared_simple_type_name ASSIGN constant + {$$ = new simple_spec_init_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| elementary_type_name constant + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in specification with initialization."); yynerrs++;} +| prev_declared_simple_type_name constant + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in specification with initialization."); yynerrs++;} +| elementary_type_name ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in specification with initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid initial value in specification with initialization."); yyclearin;} + yyerrok; + } +| prev_declared_simple_type_name ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in specification with initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid initial value in specification with initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* When converting to C/C++, we need to know whether + * the elementary_type_name is being used in a variable + * declaration or elsewhere (ex. declaration of a derived + * type), so the abstract syntax has the elementary_type_name + * wrapped inside a simple_spec_init_c. + * The exact same thing occurs with prev_declared_simple_type_name. + * + * This is why in the definition of simple_spec_init, + * simple_specification was brocken up into its + * constituent components... + */ +simple_specification: +// elementary_type_name | simple_type_name + elementary_type_name + {$$ = new simple_spec_init_c($1, NULL, locloc(@$));} +| prev_declared_simple_type_name + {$$ = new simple_spec_init_c($1, NULL, locloc(@$));} +; + + +subrange_type_declaration: +/* subrange_type_name ':' subrange_spec_init */ + identifier ':' subrange_spec_init + {$$ = new subrange_type_declaration_c($1, $3, locloc(@$)); + library_element_symtable.insert($1, prev_declared_subrange_type_name_token); + } +/* ERROR_CHECK_BEGIN */ +| error ':' subrange_spec_init + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for subrange type declaration."); yyerrok;} +| identifier subrange_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in subrange type declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +subrange_spec_init: + subrange_specification + {$$ = new subrange_spec_init_c($1, NULL, locloc(@$));} +| subrange_specification ASSIGN signed_integer + {$$ = new subrange_spec_init_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| subrange_specification signed_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in subrange specification with initialization."); yynerrs++;} +| subrange_specification ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in subrange specification with initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid initial value in subrange specification with initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +subrange_specification: + integer_type_name '(' subrange ')' + {$$ = new subrange_specification_c($1, $3, locloc(@$));} +| prev_declared_subrange_type_name + {$$ = new subrange_specification_c($1, NULL, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| integer_type_name '(' ')' + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no subrange defined in subrange specification."); yynerrs++;} +| integer_type_name '(' error ')' + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid subrange defined in subrange specification."); yyerrok;} +| integer_type_name '(' subrange error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing after subrange defined in subrange specification."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +subrange: + signed_integer DOTDOT signed_integer + {$$ = new subrange_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| signed_integer signed_integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'..' missing between bounds in subrange definition."); yynerrs++;} +| signed_integer DOTDOT error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for upper bound in subrange definition.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for upper bound in subrange definition."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +enumerated_type_declaration: +/* enumerated_type_name ':' enumerated_spec_init */ + identifier ':' enumerated_spec_init + {$$ = new enumerated_type_declaration_c($1, $3, locloc(@$)); + library_element_symtable.insert($1, prev_declared_enumerated_type_name_token); + } +/* ERROR_CHECK_BEGIN */ +| error ':' enumerated_spec_init + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for enumerated type declaration."); yyerrok;} +| identifier enumerated_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in enumerated type declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +enumerated_spec_init: + enumerated_specification + {$$ = new enumerated_spec_init_c($1, NULL, locloc(@$));} +| enumerated_specification ASSIGN enumerated_value + {$$ = new enumerated_spec_init_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| enumerated_specification enumerated_value + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in enumerated specification with initialization."); yynerrs++;} +| enumerated_specification ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined in enumerated specification with initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value in enumerated specification with initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +enumerated_specification: + '(' enumerated_value_list ')' + {$$ = $2;} +| prev_declared_enumerated_type_name +/* ERROR_CHECK_BEGIN */ +| '(' ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no enumerated value list defined in enumerated specification."); yynerrs++;} +| '(' error ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid enumerated value list defined in enumerated specification.");yyerrok;} +| '(' enumerated_value_list error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of enumerated specification."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for enumerated_specification */ +enumerated_value_list: + enumerated_value + {$$ = new enumerated_value_list_c(locloc(@$)); $$->add_element($1);} +| enumerated_value_list ',' enumerated_value + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| enumerated_value_list enumerated_value + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in enumerated value list.");} +| enumerated_value_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined in enumerated value list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value in enumerated value list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +enumerated_value: + identifier + {$$ = new enumerated_value_c(NULL, $1, locloc(@$));} +| prev_declared_enumerated_type_name '#' any_identifier + {$$ = new enumerated_value_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| prev_declared_enumerated_type_name any_identifier + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between enumerated type name and value in enumerated literal."); yynerrs++;} +| prev_declared_enumerated_type_name '#' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for enumerated literal.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for enumerated literal."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +/* +enumerated_value_without_identifier: + prev_declared_enumerated_type_name '#' any_identifier + {$$ = new enumerated_value_c($1, $3, locloc(@$));} +; +*/ + + +array_type_declaration: +/* array_type_name ':' array_spec_init */ + identifier ':' array_spec_init + {$$ = new array_type_declaration_c($1, $3, locloc(@$)); + library_element_symtable.insert($1, prev_declared_array_type_name_token); + } +/* ERROR_CHECK_BEGIN */ +| identifier array_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in array type declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +array_spec_init: + array_specification + {$$ = new array_spec_init_c($1, NULL, locloc(@$));} +| array_specification ASSIGN array_initialization + {$$ = new array_spec_init_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| array_specification array_initialization + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in array specification with initialization."); yynerrs++;} +| array_specification ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in array specification with initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid initial value in array specification with initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +array_specification: + prev_declared_array_type_name +| ARRAY '[' array_subrange_list ']' OF non_generic_type_name + {$$ = new array_specification_c($3, $6, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| ARRAY array_subrange_list ']' OF non_generic_type_name + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'[' missing before subrange list in array specification."); yynerrs++;} +| ARRAY '[' ']' OF non_generic_type_name + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no subrange list defined in array specification."); yynerrs++;} +| ARRAY '[' error ']' OF non_generic_type_name + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid subrange list defined in array specification."); yyerrok;} +| ARRAY OF non_generic_type_name + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no subrange list defined in array specification."); yynerrs++;} +| ARRAY error OF non_generic_type_name + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid subrange list defined in array specification."); yyerrok;} +| ARRAY '[' array_subrange_list OF non_generic_type_name + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "']' missing after subrange list in array specification."); yynerrs++;} +| ARRAY '[' array_subrange_list ']' non_generic_type_name + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "'OF' missing between subrange list and item type name in array specification."); yynerrs++;} +| ARRAY '[' array_subrange_list ']' OF error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no item data type defined in array specification.");} + else {print_err_msg(locf(@3), locl(@3), "invalid item data type in array specification."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* helper symbol for array_specification */ +array_subrange_list: + subrange + {$$ = new array_subrange_list_c(locloc(@$)); $$->add_element($1);} +| array_subrange_list ',' subrange + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| array_subrange_list subrange + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in subrange list."); yynerrs++;} +| array_subrange_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no subrange defined in subrange list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid subrange in subrange list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +array_initialization: + '[' array_initial_elements_list ']' + {$$ = $2;} +/* ERROR_CHECK_BEGIN */ +| '[' ']' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no initial values list defined in array initialization."); yynerrs++;} +| '[' error ']' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid initial values list defined in array initialization."); yyerrok;} +| '[' array_initial_elements_list error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "']' missing at the end of array initialization."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* helper symbol for array_initialization */ +array_initial_elements_list: + array_initial_elements + {$$ = new array_initial_elements_list_c(locloc(@$)); $$->add_element($1);} +| array_initial_elements_list ',' array_initial_elements + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN +| array_initial_elements_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no array initial value in array initial values list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid array initial value in array initial values list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +array_initial_elements: + array_initial_element +| integer '(' ')' +| integer '(' array_initial_element ')' + {$$ = new array_initial_elements_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| integer '(' error ')' + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid array initial value in array initial values list."); yyerrok;} +| integer '(' array_initial_element error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of array initial value in array initial values list."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +array_initial_element: + constant +| enumerated_value +| structure_initialization +| array_initialization +; + + + +structure_type_declaration: +/* structure_type_name ':' structure_specification */ + identifier ':' structure_specification + {$$ = new structure_type_declaration_c($1, $3, locloc(@$)); + library_element_symtable.insert($1, prev_declared_structure_type_name_token); + } +/* ERROR_CHECK_BEGIN */ +| identifier structure_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in structure type declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +structure_specification: + structure_declaration +| initialized_structure +; + + +initialized_structure: + prev_declared_structure_type_name + {$$ = new initialized_structure_c($1, NULL, locloc(@$));} +| prev_declared_structure_type_name ASSIGN structure_initialization + {$$ = new initialized_structure_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| prev_declared_structure_type_name structure_initialization + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in structure specification with initialization."); yynerrs++;} +| prev_declared_structure_type_name ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined in structure specification with initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value in structure specification with initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +structure_declaration: + STRUCT structure_element_declaration_list END_STRUCT + {$$ = $2;} +/* ERROR_CHECK_BEGIN */ +| STRUCT END_STRUCT + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no structure element declared in structure type declaration."); yynerrs++;} +| STRUCT error structure_element_declaration_list END_STRUCT + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'STRUCT' in structure type declaration."); yyerrok;} +| STRUCT structure_element_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed structure type declaration."); yyerrok;} +| STRUCT error END_STRUCT + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in structure type declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for structure_declaration */ +structure_element_declaration_list: + structure_element_declaration ';' + {$$ = new structure_element_declaration_list_c(locloc(@$)); $$->add_element($1);} +| structure_element_declaration_list structure_element_declaration ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new structure_element_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid structure element declaration."); yyerrok;} +| structure_element_declaration error + {$$ = new structure_element_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of structure element declaration."); yyerrok;} +| structure_element_declaration_list structure_element_declaration error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of structure element declaration."); yyerrok;} +| structure_element_declaration_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid structure element declaration."); yyerrok;} +| structure_element_declaration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after structure element declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +structure_element_declaration: + structure_element_name ':' simple_spec_init + {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} +| structure_element_name ':' subrange_spec_init + {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} +| structure_element_name ':' enumerated_spec_init + {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} +| structure_element_name ':' array_spec_init + {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} +| structure_element_name ':' initialized_structure + {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| structure_element_name simple_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and simple specification."); yynerrs++;} +| structure_element_name subrange_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and subrange specification."); yynerrs++;} +| structure_element_name enumerated_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and enumerated specification."); yynerrs++;} +| structure_element_name array_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and array specification."); yynerrs++;} +| structure_element_name initialized_structure + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and structure specification."); yynerrs++;} +| structure_element_name ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in structure element declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in structure element declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +structure_element_name: any_identifier; + + +structure_initialization: + '(' structure_element_initialization_list ')' + {$$ = $2;} +/* ERROR_CHECK_BEGIN */ +| '(' error ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid structure element initialization list in structure initialization."); yyerrok;} +| '(' structure_element_initialization_list error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "expecting ')' at the end of structure element initialization list in structure initialization."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for structure_initialization */ +structure_element_initialization_list: + structure_element_initialization + {$$ = new structure_element_initialization_list_c(locloc(@$)); $$->add_element($1);} +| structure_element_initialization_list ',' structure_element_initialization + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN +| structure_element_initialization_list structure_element_initialization + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in structure element initialization list in structure initialization."); yynerrs++;} +| structure_element_initialization_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no structure element initialization defined in structure initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid structure element initialization in structure initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +structure_element_initialization: + structure_element_name ASSIGN constant + {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} +| structure_element_name ASSIGN enumerated_value + {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} +| structure_element_name ASSIGN array_initialization + {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} +| structure_element_name ASSIGN structure_initialization + {$$ = new structure_element_initialization_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| structure_element_name constant + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in structure element initialization."); yynerrs++;} +| structure_element_name enumerated_value + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in enumerated structure element initialization."); yynerrs++;} +| structure_element_name array_initialization + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in array structure element initialization."); yynerrs++;} +| structure_element_name structure_initialization + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing in structured structure element initialization."); yynerrs++;} +| structure_element_name ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in structured structure element initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid initial value in structured structure element initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* NOTE: in order to remove a reduce/reduce conflict, + * all occurences of string_type_name + * have been replaced with identifier! + */ +/* +string_type_name: identifier; +*/ + +string_type_declaration: +/* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */ + identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init + {$$ = new string_type_declaration_c($1, $3, $4, $5, locloc(@$)); + library_element_symtable.insert($1, prev_declared_string_type_name_token); + } +; + + +/* helper symbol for string_type_declaration */ +string_type_declaration_size: + '[' integer ']' + {$$ = $2;} +/* REMOVED !! */ +//| /* empty */ +// {$$ = NULL;} +; +/* The syntax contains a reduce/reduce conflict. + * The optional '[' ']' + * has been changed to become mandatory to remove the conflict. + * + * The conflict arises because + * new_str_type : STRING := "hello!" + * may be reduced to a string_type_declaration OR + * a simple_type_declaration. + * + * Our change forces it to be reduced to a + * simple_type_declaration! + * We chose this option because changing the definition + * of simple_spec_init would force us to change all the other + * rules in which it appears. The change we made has no + * side-effects! + */ + +/* helper symbol for string_type_declaration */ +string_type_declaration_init: + /* empty */ + {$$ = NULL;} +| ASSIGN character_string + {$$ = $2;} +; + + + +/*********************/ +/* B 1.4 - Variables */ +/*********************/ +/* NOTE: The standard is erroneous in it's definition of 'variable' because: + * - The standard considers 'ENO' as a keyword... + * - ...=> which means that it may never be parsed as an 'identifier'... + * - ...=> and therefore may never be used as the name of a variable inside an expression. + * - However, a function/FB must be able to assign the ENO parameter + * it's value, doing it in an assignment statement, and therefore using the 'ENO' + * character sequence as an identifier! + * The obvious solution is to also allow the ENO keyword to be + * used as the name of a variable. Note that this variable may be used + * even though it is not explicitly declared as a function/FB variable, + * as the standard requires us to define it implicitly in this case! + * There are three ways of achieving this: + * (i) simply not define EN and ENO as keywords in flex (lexical analyser) + * and let them be considered 'identifiers'. Aditionally, add some code + * so that if they are not explicitly declared, we add them automatically to + * the declaration of each Functions and FB, where they would then be parsed + * as a previously_declared_variable. + * This approach has the advantage the EN and ENO would automatically be valid + * in every location where it needs to be valid, namely in the explicit declaration + * of these same variables, or when they are used within expressions. + * However, this approach has the drawback that + * EN and ENO could then also be used anywhere a standard identifier is allowed, + * including in the naming of Functions, FBs, Programs, Configurations, Resources, + * SFC Actions, SFC Steps, etc... + * This would mean that we would then have to add a lexical analysis check + * within the bison code (syntax analyser) to all the above constructs to make sure + * that the identifier being used is not EN or ENO. + * (ii) The other approach is to define EN and ENO as keywords / tokens in flex + * (lexical analyser) and then change the syntax in bison to acomodate + * these tokens wherever they could correctly appear. + * This has the drawback that we need to do some changes to the synax defintion. + * (iii) Yet a another option is to mix the above two methods. + * Define EN and ENO as tokens in flex, but change (only) the syntax for + * variable declaration to allow these tokens to also be used in declaring variables. + * From this point onwards these tokens are then considered a previously_declared_variable, + * since flex will first check for this before even checking for tokens. + * + * I (Mario) cuurretnly (2011) believe the cleanest method of achieving this goal + * is to use option (iii) + * However, considering that: + * - I have already previously implemented option (ii); + * - option (iii) requires that flex parse the previously_declared_variable + * before parsing any token. We already support this (remeber that this is + * used mainly to allow some IL operators as well as PRIORITY, etc. tokens + * to be used as identifiers, since the standard does not define them as keywords), + * but this part of the code in flex is often commented out as usually people do not expect + * us to follow the standard in the strict sense, but rather consider those + * tokens as keywords; + * considering the above, we currently carry on using option (ii). + */ +variable: + symbolic_variable +| prev_declared_direct_variable +| eno_identifier + {$$ = new symbolic_variable_c($1, locloc(@$));} +; + + +symbolic_variable: +/* NOTE: To be entirely correct, variable_name must be replacemed by + * prev_declared_variable_name | prev_declared_fb_name | prev_declared_global_var_name + */ + prev_declared_fb_name + {$$ = new symbolic_variable_c($1, locloc(@$));} +| prev_declared_global_var_name + {$$ = new symbolic_variable_c($1, locloc(@$));} +| prev_declared_variable_name + {$$ = new symbolic_variable_c($1, locloc(@$));} +| multi_element_variable +/* +| identifier + {$$ = new symbolic_variable_c($1, locloc(@$));} +*/ +; + + +/* NOTE: in section B 1.7, when configuring a program, symbolic_variable + * is used. Nevertheless, during the parsing of a configuration, + * the variables in question are out of scope, so we should + * be allowing any_identifier instead of prev_declared_variable_name! + * + * We therefore need a new any_symbolic_variable construct that + * allows the use of any_identifier instead of previously declared + * variables, function blocks, etc... + */ +any_symbolic_variable: +// variable_name -> replaced by any_identifier + any_identifier + {$$ = new symbolic_variable_c($1, locloc(@$));} +| any_multi_element_variable +; + + +/* for yet undeclared variable names ! */ +variable_name: identifier; + + + + + +/********************************************/ +/* B.1.4.1 Directly Represented Variables */ +/********************************************/ +prev_declared_direct_variable: prev_declared_direct_variable_token {$$ = new direct_variable_c($1, locloc(@$));}; + + + + +/*************************************/ +/* B.1.4.2 Multi-element Variables */ +/*************************************/ +multi_element_variable: + array_variable +| structured_variable +; + +/* please see note above any_symbolic_variable */ +any_multi_element_variable: + any_array_variable +| any_structured_variable +; + + +array_variable: + subscripted_variable '[' subscript_list ']' + {$$ = new array_variable_c($1, $3, locloc(@$));} +; + +/* please see note above any_symbolic_variable */ +any_array_variable: + any_subscripted_variable '[' subscript_list ']' + {$$ = new array_variable_c($1, $3, locloc(@$));} +; + + +subscripted_variable: + symbolic_variable +; + + +/* please see note above any_symbolic_variable */ +any_subscripted_variable: + any_symbolic_variable +; + + +subscript_list: + subscript + {$$ = new subscript_list_c(locloc(@$)); $$->add_element($1);} +| subscript_list ',' subscript + {$$ = $1; $$->add_element($3);} +; + + +subscript: expression; + + +structured_variable: + record_variable '.' field_selector + {$$ = new structured_variable_c($1, $3, locloc(@$));} +; + + +/* please see note above any_symbolic_variable */ +any_structured_variable: + any_record_variable '.' field_selector + {$$ = new structured_variable_c($1, $3, locloc(@$));} +; + + + +record_variable: + symbolic_variable +; + + +/* please see note above any_symbolic_variable */ +any_record_variable: + any_symbolic_variable +; + + +field_selector: + any_identifier +| eno_identifier +; + + + + + + +/******************************************/ +/* B 1.4.3 - Declaration & Initialisation */ +/******************************************/ +input_declarations: + VAR_INPUT input_declaration_list END_VAR + {$$ = new input_declarations_c(NULL, $2, new explicit_definition_c(), locloc(@$));} +| VAR_INPUT RETAIN input_declaration_list END_VAR + {$$ = new input_declarations_c(new retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} +| VAR_INPUT NON_RETAIN input_declaration_list END_VAR + {$$ = new input_declarations_c(new non_retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR_INPUT END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in input variable(s) declaration."); yynerrs++;} +| VAR_INPUT RETAIN END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive input variable(s) declaration."); yynerrs++;} +| VAR_INPUT NON_RETAIN END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in non-retentive input variable(s) declaration."); yynerrs++;} +| VAR_INPUT error input_declaration_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_INPUT' in input variable(s) declaration."); yyerrok;} +| VAR_INPUT RETAIN error input_declaration_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive input variable(s) declaration."); yyerrok;} +| VAR_INPUT NON_RETAIN error input_declaration_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive input variable(s) declaration."); yyerrok;} +| VAR_INPUT input_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed input variable(s) declaration."); yyerrok;} +| VAR_INPUT RETAIN input_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive input variable(s) declaration."); yyerrok;} +| VAR_INPUT NON_RETAIN input_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed non-retentive input variable(s) declaration."); yyerrok;} +| VAR_INPUT error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in input variable(s) declaration."); yyerrok;} +| VAR_INPUT RETAIN error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in retentive input variable(s) declaration."); yyerrok;} +| VAR_INPUT NON_RETAIN error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in non-retentive input variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for input_declarations */ +input_declaration_list: + input_declaration ';' + {$$ = new input_declaration_list_c(locloc(@$)); $$->add_element($1);} +| input_declaration_list input_declaration ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new input_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid input variable(s) declaration."); yyerrok;} +| input_declaration error + {$$ = new input_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of input variable(s) declaration."); yyerrok;} +| input_declaration_list input_declaration error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of input variable(s) declaration."); yyerrok;} +| input_declaration_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid input variable(s) declaration."); yyerrok;} +| input_declaration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after input variable(s) declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +/* NOTE: The formal definition of 'input_declaration' as defined in the standard is erroneous, + * as it does not allow a user defined 'EN' input parameter. However, + * The semantic description of the languages clearly states that this is allowed. + * We have added the 'en_param_declaration' clause to cover for this. + */ +input_declaration: + var_init_decl +| edge_declaration +| en_param_declaration +; + + +edge_declaration: + var1_list ':' BOOL R_EDGE + {$$ = new edge_declaration_c(new raising_edge_option_c(locloc(@3)), $1, locloc(@$));} +| var1_list ':' BOOL F_EDGE + {$$ = new edge_declaration_c(new falling_edge_option_c(locloc(@3)), $1, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list BOOL R_EDGE + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in edge declaration."); yynerrs++;} +| var1_list BOOL F_EDGE + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in edge declaration."); yynerrs++;} +| var1_list ':' BOOL R_EDGE F_EDGE + {$$ = 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++;} +| var1_list ':' BOOL F_EDGE R_EDGE + {$$ = 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++;} +| var1_list ':' R_EDGE + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in edge declaration."); yynerrs++;} +| var1_list ':' F_EDGE + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in edge declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +/* NOTE: The formal definition of the standard is erroneous, as it simply does not + * consider the EN and ENO keywords! + * The semantic description of the languages clearly states that these may be + * used in several ways. One of them is to declare an EN input parameter. + * We have added the 'en_param_declaration' clause to cover for this. + * + * Please read the comment above the definition of 'variable' in section B1.4 for details. + */ +en_param_declaration: + en_identifier ':' BOOL ASSIGN boolean_literal + {$$ = new en_param_declaration_c($1, new bool_type_name_c(locloc(@$)), $5, new explicit_definition_c(), locloc(@$));} +| en_identifier ':' BOOL ASSIGN integer + {$$ = new en_param_declaration_c($1, new bool_type_name_c(locloc(@$)), $5, new explicit_definition_c(), locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| en_identifier BOOL ASSIGN boolean_literal + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in EN declaration."); yynerrs++;} +| en_identifier BOOL ASSIGN integer + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in EN declaration."); yynerrs++;} +| en_identifier ':' ASSIGN boolean_literal + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in EN declaration."); yynerrs++;} +| en_identifier ':' ASSIGN integer + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'BOOL' missing in EN declaration."); yynerrs++;} +| en_identifier ':' BOOL ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in EN declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in EN declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +var_init_decl: + var1_init_decl +| array_var_init_decl +| structured_var_init_decl +| fb_name_decl +| string_var_declaration +; + + + + +var1_init_decl: + var1_list ':' simple_spec_init + {$$ = new var1_init_decl_c($1, $3, locloc(@$));} +| var1_list ':' subrange_spec_init + {$$ = new var1_init_decl_c($1, $3, locloc(@$));} +| var1_list ':' enumerated_spec_init + {$$ = new var1_init_decl_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list simple_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and simple specification."); yynerrs++;} +| var1_list subrange_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and subrange specification."); yynerrs++;} +| var1_list enumerated_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and enumerated specification."); yynerrs++;} +| var1_list ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in variable declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +/* NOTE: + * The syntax + * variable_name DOTDOT + * is an extension to the standard!!! + * + * In order to be able to handle extensible standard functions + * (i.e. standard functions that may have a variable number of + * input parameters, such as AND(word#33, word#44, word#55, word#66), + * we have extended the acceptable syntax to allow var_name '..' + * in an input variable declaration. + * + * This allows us to parse the declaration of standard + * extensible functions and load their interface definition + * into the abstract syntax tree just like we do to other + * user defined functions. + * This has the advantage that we can later do semantic + * checking of calls to functions (be it a standard or user defined + * function) in (almost) exactly the same way. + * + * Of course, we have a flag that disables this syntax when parsing user + * written code, so we only allow this extra syntax while parsing the + * 'header' file that declares all the standard IEC 61131-3 functions. + */ +var1_list: + variable_name + {$$ = new var1_list_c(locloc(@$)); $$->add_element($1); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + } +| variable_name integer DOTDOT + {$$ = new var1_list_c(locloc(@$)); $$->add_element(new extensible_input_parameter_c($1, $2, locloc(@$))); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + if (!allow_extensible_function_parameters) print_err_msg(locf(@1), locl(@2), "invalid syntax in variable name declaration."); + } + | var1_list ',' variable_name + {$$ = $1; $$->add_element($3); + variable_name_symtable.insert($3, prev_declared_variable_name_token); + } + | var1_list ',' variable_name integer DOTDOT + {$$ = $1; $$->add_element(new extensible_input_parameter_c($3, $4, locloc(@$))); + variable_name_symtable.insert($3, prev_declared_variable_name_token); + if (!allow_extensible_function_parameters) print_err_msg(locf(@1), locl(@2), "invalid syntax in variable name declaration."); + } +/* ERROR_CHECK_BEGIN */ +| var1_list variable_name + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in variable list."); yynerrs++;} +| var1_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no variable name defined in variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid variable name in variable declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +array_var_init_decl: + var1_list ':' array_spec_init + {$$ = new array_var_init_decl_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list array_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and array specification."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +structured_var_init_decl: + var1_list ':' initialized_structure + {$$ = new structured_var_init_decl_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list initialized_structure + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and structured specification."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +/* NOTE: see notes above fb_name_list and var1_list + * for reason why ':' was removed from this rule! + * In essence, to remove a shift/reduce conflict, + * the ':' was moved to var1_list and fb_name_list! + */ +fb_name_decl: +/* fb_name_list ':' function_block_type_name */ + fb_name_list_with_colon function_block_type_name + {$$ = new fb_name_decl_c($1, $2, NULL, locloc(@$));} +/*| fb_name_list ':' function_block_type_name ASSIGN structure_initialization */ +| fb_name_list_with_colon function_block_type_name ASSIGN structure_initialization + {$$ = new fb_name_decl_c($1, $2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| fb_name_list_with_colon ASSIGN structure_initialization + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block type name defined in function block declaration with initialization."); yynerrs++;} +| fb_name_list_with_colon function_block_type_name structure_initialization + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':=' missing in function block declaration with initialization."); yynerrs++;} +| fb_name_list_with_colon function_block_type_name ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no initialization defined in function block declaration.");} + else {print_err_msg(locf(@4), locl(@4), "invalid initialization in function block declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +/* NOTE: In order to remove a reduce/reduce conflict between + * var1_list and fb_name_list, which are identical to each + * other, fb_name_list has been redefined to be a var1_list. + * + * In order to remove a further shift/reduce conflict, var1_list + * is imediately transfomred into var1_list_with_colon + * (i.e. it includes the ':' following the list), which + * means that fb_name_list is built from a + * var1_list_with_colon after all! + */ +/* +fb_name_list: + (* fb_name *) + identifier + {$$ = new fb_name_list_c($1); + variable_name_symtable.insert($1, prev_declared_fb_name_token); + } +(* | fb_name_list ',' fb_name *) +| fb_name_list ',' identifier + {$$ = $1; $$->add_element($3); + variable_name_symtable.insert($3, prev_declared_fb_name_token); + } +; +*/ + +fb_name_list_with_colon: + var1_list_with_colon + {$$ = new fb_name_list_c(locloc(@$)); + /* fill up the new fb_name_list_c object with the references + * contained in the var1_list_c object. + */ + FOR_EACH_ELEMENT(elem, $1, {$$->add_element(elem);}); + delete $1; + /* change the tokens associated with the symbols stored in + * the variable name symbol table from prev_declared_variable_name_token + * to prev_declared_fb_name_token + */ + FOR_EACH_ELEMENT(elem, $$, {variable_name_symtable.set(elem, prev_declared_fb_name_token);}); + } +; + +/* helper symbol for fb_name_list_with_colon */ +var1_list_with_colon: + var1_list ':' +; + + +// fb_name: identifier; + + + +output_declarations: + VAR_OUTPUT var_output_init_decl_list END_VAR + {$$ = new output_declarations_c(NULL, $2, new explicit_definition_c(), locloc(@$));} +| VAR_OUTPUT RETAIN var_output_init_decl_list END_VAR + {$$ = new output_declarations_c(new retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} +| VAR_OUTPUT NON_RETAIN var_output_init_decl_list END_VAR + {$$ = new output_declarations_c(new non_retain_option_c(locloc(@2)), $3, new explicit_definition_c(), locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR_OUTPUT END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in output variable(s) declaration."); yynerrs++;} +| VAR_OUTPUT RETAIN END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive output variable(s) declaration."); yynerrs++;} +| VAR_OUTPUT NON_RETAIN END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in non-retentive output variable(s) declaration."); yynerrs++;} +| VAR_OUTPUT error var_output_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_OUPUT' in output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT RETAIN error var_output_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT NON_RETAIN error var_output_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT var_output_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT RETAIN var_output_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT NON_RETAIN var_output_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed non-retentive output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT RETAIN error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in retentive output variable(s) declaration."); yyerrok;} +| VAR_OUTPUT NON_RETAIN error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in non-retentive output variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* NOTE: The formal definition of 'var_output_init_decl' as defined in the standard is erroneous, + * as it does not allow a user defined 'ENO' output parameter. However, + * The semantic description of the languages clearly states that this is allowed. + * We have added the 'eno_param_declaration' clause to cover for this. + * + * Please read the comment above the definition of 'variable' in section B1.4 for details. + */ +var_output_init_decl: + var_init_decl +| eno_param_declaration +; + +var_output_init_decl_list: + var_output_init_decl ';' + {$$ = new var_init_decl_list_c(locloc(@$)); $$->add_element($1);} +| var_output_init_decl_list var_output_init_decl ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| var_output_init_decl_list var_output_init_decl error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of variable(s) declaration."); yyerrok;} +| var_output_init_decl_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* NOTE: The formal definition of the standard is erroneous, as it simply does not + * consider the EN and ENO keywords! + * The semantic description of the languages clearly states that these may be + * used in several ways. One of them is to declare an ENO output parameter. + * We have added the 'eno_param_declaration' clause to cover for this. + * + * Please read the comment above the definition of 'variable' in section B1.4 for details. + */ +eno_param_declaration: + eno_identifier ':' BOOL + /* NOTE We do _NOT_ include this variable in the previously_declared_variable symbol table! + * Please read the comment above the definition of 'variable' for the reason for this. + */ + {$$ = new eno_param_declaration_c($1, new bool_type_name_c(locloc(@$)), new explicit_definition_c(), locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| eno_identifier BOOL + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and specification in ENO declaration."); yynerrs++;} +| eno_identifier ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in ENO declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in ENO declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +input_output_declarations: + VAR_IN_OUT var_declaration_list END_VAR + {$$ = new input_output_declarations_c($2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR_IN_OUT END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in in_out variable(s) declaration."); yynerrs++;} +| VAR_IN_OUT error var_declaration_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_IN_OUT' in in_out variable(s) declaration."); yyerrok;} +| VAR_IN_OUT var_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed in_out variable(s) declaration."); yyerrok;} +| VAR_IN_OUT error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in in_out variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + +/* helper symbol for input_output_declarations */ +var_declaration_list: + var_declaration ';' + {$$ = new var_declaration_list_c(locloc(@$)); $$->add_element($1);} +| var_declaration_list var_declaration ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new var_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid variable(s) declaration."); yyerrok;} +| var_declaration error + {$$ = new var_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of variable(s) declaration."); yyerrok;} +| var_declaration_list var_declaration error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of variable(s) declaration."); yyerrok;} +| var_declaration_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid variable(s) declaration."); yyerrok;} +| var_declaration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after variable(s) declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +var_declaration: + temp_var_decl +| fb_name_decl +; + + +temp_var_decl: + var1_declaration +| array_var_declaration +| structured_var_declaration +| string_var_declaration +; + +var1_declaration: + var1_list ':' simple_specification + {$$ = new var1_init_decl_c($1, $3, locloc(@$));} +| var1_list ':' subrange_specification + {$$ = new var1_init_decl_c($1, $3, locloc(@$));} +| var1_list ':' enumerated_specification + {$$ = new var1_init_decl_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list simple_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and simple specification."); yynerrs++;} +| var1_list subrange_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and subrange specification."); yynerrs++;} +| var1_list enumerated_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and enumerated specification."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + + +array_var_declaration: + var1_list ':' array_specification + {$$ = new array_var_declaration_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list array_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and array specification."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +structured_var_declaration: + var1_list ':' prev_declared_structure_type_name + {$$ = new structured_var_declaration_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list prev_declared_structure_type_name + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and structured specification."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +var_declarations: + VAR var_init_decl_list END_VAR + {$$ = new var_declarations_c(NULL, $2, locloc(@$));} +| VAR CONSTANT var_init_decl_list END_VAR + {$$ = new var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in variable(s) declaration."); yynerrs++;} +| VAR CONSTANT END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in constant variable(s) declaration."); yynerrs++;} +| VAR error var_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@3), "unexpected token after 'VAR' in variable(s) declaration."); yyerrok;} +| VAR CONSTANT error var_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant variable(s) declaration."); yyerrok;} +| VAR var_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed variable(s) declaration."); yyerrok;} +| VAR CONSTANT var_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant variable(s) declaration."); yyerrok;} +| VAR error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in variable(s) declaration."); yyerrok;} +| VAR CONSTANT error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +retentive_var_declarations: + VAR RETAIN var_init_decl_list END_VAR + {$$ = new retentive_var_declarations_c($3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR RETAIN END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive variable(s) declaration."); yynerrs++;} +| VAR RETAIN error var_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive variable(s) declaration."); yyerrok;} +| VAR RETAIN var_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive variable(s) declaration."); yyerrok;} +| VAR RETAIN error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in retentive variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +located_var_declarations: + VAR located_var_decl_list END_VAR + {$$ = new located_var_declarations_c(NULL, $2, locloc(@$));} +| VAR CONSTANT located_var_decl_list END_VAR + {$$ = new located_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} +| VAR RETAIN located_var_decl_list END_VAR + {$$ = new located_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));} +| VAR NON_RETAIN located_var_decl_list END_VAR + {$$ = new located_var_declarations_c(new non_retain_option_c(locloc(@2)), $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR NON_RETAIN END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in non-retentive located variable(s) declaration."); yynerrs++;} +| VAR error located_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR' in located variable(s) declaration."); yyerrok;} +| VAR CONSTANT error located_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant located variable(s) declaration."); yyerrok;} +| VAR RETAIN error located_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive located variable(s) declaration."); yyerrok;} +| VAR NON_RETAIN error located_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive located variable(s) declaration."); yyerrok;} +| VAR located_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed located variable(s) declaration."); yyerrok;} +| VAR CONSTANT located_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant located variable(s) declaration."); yyerrok;} +| VAR RETAIN located_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive located variable(s) declaration."); yyerrok;} +| VAR NON_RETAIN located_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed non-retentive located variable(s) declaration."); yyerrok;} +| VAR NON_RETAIN error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in non retentive variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* helper symbol for located_var_declarations */ +located_var_decl_list: + located_var_decl ';' + {$$ = new located_var_decl_list_c(locloc(@$)); $$->add_element($1);} +| located_var_decl_list located_var_decl ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new located_var_decl_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid located variable declaration."); yyerrok;} +| located_var_decl error + {$$ = new located_var_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of located variable declaration."); yyerrok;} +| located_var_decl_list located_var_decl error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of located variable declaration."); yyerrok;} +| located_var_decl_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid located variable declaration."); yyerrok;} +| located_var_decl_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after located variable declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +located_var_decl: + variable_name location ':' located_var_spec_init + {$$ = new located_var_decl_c($1, $2, $4, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + } +| location ':' located_var_spec_init + {$$ = new located_var_decl_c(NULL, $1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| variable_name location located_var_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between located variable location and specification."); yynerrs++;} +| location located_var_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between located variable location and specification."); yynerrs++;} +| variable_name location ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in located variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in located variable declaration."); yyclearin;} + yyerrok; + } +| location ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in located variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in located variable declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + + +external_var_declarations: + VAR_EXTERNAL external_declaration_list END_VAR + {$$ = new external_var_declarations_c(NULL, $2, locloc(@$));} +| VAR_EXTERNAL CONSTANT external_declaration_list END_VAR + {$$ = new external_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR_EXTERNAL END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in external variable(s) declaration."); yynerrs++;} +| VAR_EXTERNAL CONSTANT END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in constant external variable(s) declaration."); yynerrs++;} +| VAR_EXTERNAL error external_declaration_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_EXTERNAL' in external variable(s) declaration."); yyerrok;} +| VAR_EXTERNAL CONSTANT error external_declaration_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant external variable(s) declaration."); yyerrok;} +| VAR_EXTERNAL external_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed external variable(s) declaration."); yyerrok;} +| VAR_EXTERNAL CONSTANT external_declaration_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant external variable(s) declaration."); yyerrok;} +| VAR_EXTERNAL error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in external variable(s) declaration."); yyerrok;} +| VAR_EXTERNAL CONSTANT error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant external variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for external_var_declarations */ +external_declaration_list: + external_declaration ';' + {$$ = new external_declaration_list_c(locloc(@$)); $$->add_element($1);} +| external_declaration_list external_declaration ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new external_declaration_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid external variable declaration."); yyerrok;} +| external_declaration error + {$$ = new external_declaration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of external variable declaration."); yyerrok;} +| external_declaration_list external_declaration error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of external variable declaration."); yyerrok;} +| external_declaration_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid external variable declaration."); yyerrok;} +| external_declaration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after external variable declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +external_declaration: + global_var_name ':' simple_specification + {$$ = new external_declaration_c($1, $3, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + } +| global_var_name ':' subrange_specification + {$$ = new external_declaration_c($1, $3, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + } +| global_var_name ':' enumerated_specification + {$$ = new external_declaration_c($1, $3, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + } +| global_var_name ':' array_specification + {$$ = new external_declaration_c($1, $3, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + } +| global_var_name ':' prev_declared_structure_type_name + {$$ = new external_declaration_c($1, $3, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_variable_name_token); + } +| global_var_name ':' function_block_type_name + {$$ = new external_declaration_c($1, $3, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_fb_name_token); + } +/* ERROR_CHECK_BEGIN */ +| global_var_name simple_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and simple specification."); yynerrs++;} +| global_var_name subrange_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and subrange specification."); yynerrs++;} +| global_var_name enumerated_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and enumerated specification."); yynerrs++;} +| global_var_name array_specification + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and array specification."); yynerrs++;} +| global_var_name prev_declared_structure_type_name + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and structured specification."); yynerrs++;} +| global_var_name function_block_type_name + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between external variable name and function block type specification."); yynerrs++;} +| global_var_name ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in external variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in external variable declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +global_var_name: identifier; + + +global_var_declarations: + VAR_GLOBAL global_var_decl_list END_VAR + {$$ = new global_var_declarations_c(NULL, $2, locloc(@$));} +| VAR_GLOBAL CONSTANT global_var_decl_list END_VAR + {$$ = new global_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} +| VAR_GLOBAL RETAIN global_var_decl_list END_VAR + {$$ = new global_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR_GLOBAL END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in global variable(s) declaration."); yynerrs++;} +| VAR_GLOBAL CONSTANT END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in constant global variable(s) declaration."); yynerrs++;} +| VAR_GLOBAL RETAIN END_VAR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable declared in retentive global variable(s) declaration."); yynerrs++;} +| VAR_GLOBAL error global_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_GLOBAL' in global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL CONSTANT error global_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL RETAIN error global_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL global_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL CONSTANT global_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL RETAIN global_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed retentive global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL CONSTANT error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant global variable(s) declaration."); yyerrok;} +| VAR_GLOBAL RETAIN error END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unknown error in constant global variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* helper symbol for global_var_declarations */ +global_var_decl_list: + global_var_decl ';' + {$$ = new global_var_decl_list_c(locloc(@$)); $$->add_element($1);} +| global_var_decl_list global_var_decl ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new global_var_decl_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid global variable(s) declaration."); yyerrok;} +| global_var_decl error + {$$ = new global_var_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of global variable(s) declaration."); yyerrok;} +| global_var_decl_list global_var_decl error + {$$ = $1; print_err_msg(locl(@1), locf(@2), "';' missing at end of global variable(s) declaration."); yyerrok;} +| global_var_decl_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid global variable(s) declaration."); yyerrok;} +| global_var_decl_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after global variable(s) declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +global_var_decl: +/* NOTE : This possibility defined in standard has no sense and generate a conflict (disabled) + global_var_spec ':' + {$$ = new global_var_decl_c($1, NULL, locloc(@$));} +*/ + global_var_spec ':' located_var_spec_init + {$$ = new global_var_decl_c($1, $3, locloc(@$));} +| global_var_spec ':' function_block_type_name + {$$ = new global_var_decl_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| global_var_list located_var_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between global variable list and type specification."); yynerrs++;} +| global_var_name location located_var_spec_init + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between global variable specification and type specification."); yynerrs++;} +| global_var_spec function_block_type_name + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between global variable specification and function block type specification."); yynerrs++;} +| global_var_spec ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in global variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in global variable declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +global_var_spec: + global_var_list {$$ = $1;} +| location + {$$ = new global_var_spec_c(NULL, $1, locloc(@$));} +| global_var_name location + {$$ = new global_var_spec_c($1, $2, locloc(@$)); + variable_name_symtable.insert($1, prev_declared_global_var_name_token); + } +; + + +located_var_spec_init: + simple_spec_init +| subrange_spec_init +| enumerated_spec_init +| array_spec_init +| initialized_structure +| single_byte_string_spec +| double_byte_string_spec +; + + +location: + AT direct_variable_token + {$$ = new location_c(new direct_variable_c($2, locloc(@$)), locloc(@$)); + direct_variable_symtable.insert($2, prev_declared_direct_variable_token); + } +/* ERROR_CHECK_BEGIN */ +| AT error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no location defined in location declaration.");} + else {print_err_msg(locf(@2), locl(@2), "invalid location in global location declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +global_var_list: + global_var_name + {$$ = new global_var_list_c(locloc(@$)); $$->add_element($1); + variable_name_symtable.insert($1, prev_declared_global_var_name_token); + } +| global_var_list ',' global_var_name + {$$ = $1; $$->add_element($3); + variable_name_symtable.insert($3, prev_declared_global_var_name_token); + } +/* ERROR_CHECK_BEGIN */ +| global_var_list global_var_name + {$$ = new global_var_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "',' missing in global variable list."); yynerrs++;} +| global_var_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no variable name defined in global variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid variable name in global variable declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +string_var_declaration: + single_byte_string_var_declaration +| double_byte_string_var_declaration +; + +single_byte_string_var_declaration: + var1_list ':' single_byte_string_spec + {$$ = new single_byte_string_var_declaration_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list single_byte_string_spec + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and string type specification."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +/* NOTE: The constructs + * + * [W]STRING + * and + * [W]STRING ASSIGN single_byte_character_string + * + * were removed as they are already contained + * within a other constructs. + * + * single_byte_string_spec is used in: + * - single_byte_string_var_declaration -> + * -> string_var_declaration ---> var_init_decl + * |--> temp_var_decl + * |--> var2_init_decl + * - located_var_spec_init + * + * STRING [ASSIGN string_constant] -> elementary_string_type_name -> + * -> simple_spec -> simple_specification -> simple_spec_init -> + * -> located_var_spec_init + * + * STRING [ASSIGN string_constant] -> elementary_string_type_name -> + * -> simple_spec -> simple_specification -> simple_spec_init -> + * -> var1_init_decl -> var_init_decl + * + * STRING [ASSIGN string_constant] -> elementary_string_type_name -> + * -> simple_spec -> simple_specification -> simple_spec_init -> + * -> var1_init_decl -> var2_init_decl + * + * STRING [ASSIGN string_constant] -> elementary_string_type_name -> + * -> simple_spec -> simple_specification -> + * -> var1_declaration -> temp_var_decl + */ +single_byte_string_spec: +/* STRING + {$$ = new single_byte_string_spec_c(NULL, NULL);} +*/ + STRING '[' integer ']' + {$$ = 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(@$));} +/* +| STRING ASSIGN single_byte_character_string + {$$ = new single_byte_string_spec_c($1, NULL, $3, locloc(@$));} +*/ +| STRING '[' integer ']' ASSIGN single_byte_character_string + {$$ = 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(@$));} +/* ERROR_CHECK_BEGIN */ +| STRING '[' error ']' + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited string type specification."); yyerrok;} +| STRING '[' error ']' ASSIGN single_byte_character_string + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited string type specification."); yyerrok;} +| STRING '[' ']' + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited string type specification."); yynerrs++;} +| STRING '[' ']' ASSIGN single_byte_character_string + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited string type specification."); yynerrs++;} +| STRING '[' integer error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "expecting ']' after length definition for limited string type specification."); yyerrok;} +| STRING '[' integer ']' single_byte_character_string + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':=' missing before limited string type initialization."); yynerrs++;} +| STRING '[' integer ']' ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@5), locf(@6), "no initial value defined in limited string type initialization.");} + else {print_err_msg(locf(@6), locl(@6), "invalid initial value in limited string type initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +double_byte_string_var_declaration: + var1_list ':' double_byte_string_spec + {$$ = new double_byte_string_var_declaration_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| var1_list double_byte_string_spec + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between variable list and double byte string type specification."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +double_byte_string_spec: +/* WSTRING + {$$ = new double_byte_string_spec_c($1, NULL, NULL, locloc(@$));} +*/ + WSTRING '[' integer ']' + {$$ = 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(@$));} + +/* +| WSTRING ASSIGN double_byte_character_string + {$$ = new double_byte_string_spec_c($1, NULL, $3, locloc(@$));} +*/ +| WSTRING '[' integer ']' ASSIGN double_byte_character_string + {$$ = 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(@$));} +/* ERROR_CHECK_BEGIN */ +| WSTRING '[' error ']' + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited double byte string type specification."); yyerrok;} +| WSTRING '[' error ']' ASSIGN single_byte_character_string + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid length value for limited double byte string type specification."); yyerrok;} +| WSTRING '[' ']' + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited double byte string type specification."); yynerrs++;} +| WSTRING '[' ']' ASSIGN single_byte_character_string + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "missing length value for limited double byte string type specification."); yynerrs++;} +| WSTRING '[' integer error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "expecting ']' after length definition for limited double byte string type specification."); yyerrok;} +| WSTRING '[' integer ']' single_byte_character_string + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':=' missing before limited double byte string type initialization."); yynerrs++;} +| WSTRING '[' integer ']' ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@5), locf(@6), "no initial value defined double byte in limited string type initialization.");} + else {print_err_msg(locf(@6), locl(@6), "invalid initial value in limited double byte string type initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +incompl_located_var_declarations: + VAR incompl_located_var_decl_list END_VAR + {$$ = new incompl_located_var_declarations_c(NULL, $2, locloc(@$));} +| VAR RETAIN incompl_located_var_decl_list END_VAR + {$$ = new incompl_located_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));} +| VAR NON_RETAIN incompl_located_var_decl_list END_VAR + {$$ = new incompl_located_var_declarations_c(new non_retain_option_c(locloc(@2)), $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR incompl_located_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed incomplete located variable(s) declaration."); yyerrok;} +| VAR RETAIN incompl_located_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed incomplete retentive located variable(s) declaration."); yyerrok;} +| VAR NON_RETAIN incompl_located_var_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed incomplete non-retentive located variable(s) declaration."); yyerrok;} +| VAR error incompl_located_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR' in incomplete located variable(s) declaration."); yyerrok;} +| VAR RETAIN error incompl_located_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive located variable(s) declaration."); yyerrok;} +| VAR NON_RETAIN error incompl_located_var_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive located variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for incompl_located_var_declarations */ +incompl_located_var_decl_list: + incompl_located_var_decl ';' + {$$ = new incompl_located_var_decl_list_c(locloc(@$)); $$->add_element($1);} +| incompl_located_var_decl_list incompl_located_var_decl ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| incompl_located_var_decl error + {$$ = new incompl_located_var_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of incomplete located variable declaration."); yyerrok;} +| incompl_located_var_decl_list incompl_located_var_decl error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of incomplete located variable declaration."); yyerrok;} +| incompl_located_var_decl_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid incomplete located variable declaration."); yyerrok;} +| incompl_located_var_decl_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after incomplete located variable declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +incompl_located_var_decl: + variable_name incompl_location ':' var_spec + {$$ = new incompl_located_var_decl_c($1, $2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| variable_name incompl_location var_spec + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between incomplete located variable and type specification."); yynerrs++; + } +| variable_name incompl_location ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no specification defined in incomplete located variable declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid specification in incomplete located variable declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +incompl_location: + AT incompl_location_token + {$$ = new incompl_location_c($2, locloc(@$));} +; + + +var_spec: + simple_specification +| subrange_specification +| enumerated_specification +| array_specification +| prev_declared_structure_type_name +| string_spec +; + + +/* helper symbol for var_spec */ +string_spec: +/* STRING + {$$ = new single_byte_limited_len_string_spec_c($1, NULL, locloc(@$));} +*/ + STRING '[' integer ']' + {$$ = new single_byte_limited_len_string_spec_c(new string_type_name_c(locloc(@1)), $3, locloc(@$));} +/* +| WSTRING + {$$ = new double_byte_limited_len_string_spec_c($1, NULL, locloc(@$));} +*/ +| WSTRING '[' integer ']' + {$$ = new double_byte_limited_len_string_spec_c(new wstring_type_name_c(locloc(@1)), $3, locloc(@$));} +; + + + + +/* intermediate helper symbol for: + * - non_retentive_var_decls + * - var_declarations + */ +var_init_decl_list: + var_init_decl ';' + {$$ = new var_init_decl_list_c(locloc(@$)); $$->add_element($1);} +| var_init_decl_list var_init_decl ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| var_init_decl_list var_init_decl error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of variable(s) declaration."); yyerrok;} +| var_init_decl_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + + +/***********************/ +/* B 1.5.1 - Functions */ +/***********************/ +/* +function_name: + prev_declared_derived_function_name +| standard_function_name +; +*/ + +/* The following rules should be set such as: + * function_name: function_name_no_clashes | function_name_simpleop_clashes | function_name_expression_clashes + * function_name: function_name_no_NOT_clashes | function_name_NOT_clashes; + */ + +function_name_no_clashes: prev_declared_derived_function_name | standard_function_name_no_clashes; +function_name_simpleop_clashes: standard_function_name_simpleop_clashes; +//function_name_expression_clashes: standard_function_name_expression_clashes; + +function_name_no_NOT_clashes: prev_declared_derived_function_name | standard_function_name_no_NOT_clashes; +//function_name_NOT_clashes: standard_function_name_NOT_clashes; + + +/* NOTE: The list of standard function names + * includes the standard functions MOD(), NOT() + * + * Strangely enough, MOD and NOT are reserved keywords, + * so shouldn't be used for function names. + * + * The specification contradicts itself! + * Our workaround is to treat MOD as a token, + * but to include this token as a + * standard_function_name. + * + * The names of all other standard functions get + * preloaded into the library_element_symbol_table + * with the token value of + * standard_function_name_token + * Actually, simply for completeness, MOD is also + * loaded into the library_element_symbol_table, but + * it is irrelevant since flex will catch MOD as a + * token, before it interprets it as an identifier, + * and looks in the library_element_symbol_table to check + * whether it has been previously declared. + * + * NOTE: The same as the above also occurs with the IL + * operators NOT AND OR XOR ADD SUB MUL DIV MOD + * GT GE EQ LT LE NE. + * Note that MOD is once again in the list! + * Anyway, we give these the same treatement as + * MOD, since we are writing a parser for ST and + * IL simultaneously. If this were not the case, + * the ST parser would not need the tokens NOT AND ... + * + * NOTE: Note that 'NOT' is special, as it conflicts + * with two operators: the IL 'NOT' operator, and + * the unary operator 'NOT' in ST!! + * + * NOTE: The IL language is ambiguous, since using NOT, AND, ... + * may be interpreted as either an IL operator, or + * as a standard function call! + * I (Mario) opted to interpret it as an IL operator. + * This requires changing the syntax for IL language + * function calling, to exclude all function with + * names that clash with IL operators. I therefore + * created the constructs + * function_name_without_clashes + * standard_function_name_without_clashes + * to include all function names, except those that clash + * with IL operators. These constructs are only used + * within the IL language! + */ +/* The following rules should be set such as: + * standard_function_name: standard_function_name_no_clashes | standard_function_name_simpleop_clashes | standard_function_name_expression_clashes + * standard_function_name: standard_function_name_no_NOT_clashes | standard_function_name_NOT_clashes; + */ + +/* +standard_function_name: + standard_function_name_no_clashes +| standard_function_name_expression_clashes +| standard_function_name_NOT_clashes +//| standard_function_name_simpleop_only_clashes +; +*/ + +standard_function_name_no_NOT_clashes: + standard_function_name_no_clashes +| standard_function_name_expression_clashes +//| standard_function_name_simpleop_only_clashes +; + +standard_function_name_no_clashes: + standard_function_name_token + {$$ = new identifier_c($1, locloc(@$));} +; + + +standard_function_name_simpleop_clashes: + standard_function_name_NOT_clashes +//| standard_function_name_simpleop_only_clashes +; + +standard_function_name_NOT_clashes: + NOT + {$$ = new identifier_c(strdup("NOT"), locloc(@$));} +; + +/* Add here any other IL simple operators that collide + * with standard function names! + * Don't forget to uncomment the equivalent lines in + * - standard_function_name_simpleop_clashes + * - standard_function_name + * - standard_function_name_no_NOT_clashes + */ +/* +standard_function_name_simpleop_only_clashes: +; +*/ + +standard_function_name_expression_clashes: + AND {$$ = new identifier_c(strdup("AND"), locloc(@$));} +| OR {$$ = new identifier_c(strdup("OR"), locloc(@$));} +| XOR {$$ = new identifier_c(strdup("XOR"), locloc(@$));} +| ADD {$$ = new identifier_c(strdup("ADD"), locloc(@$));} +| SUB {$$ = new identifier_c(strdup("SUB"), locloc(@$));} +| MUL {$$ = new identifier_c(strdup("MUL"), locloc(@$));} +| DIV {$$ = new identifier_c(strdup("DIV"), locloc(@$));} +| MOD {$$ = new identifier_c(strdup("MOD"), locloc(@$));} +| GT {$$ = new identifier_c(strdup("GT"), locloc(@$));} +| GE {$$ = new identifier_c(strdup("GE"), locloc(@$));} +| EQ {$$ = new identifier_c(strdup("EQ"), locloc(@$));} +| LT {$$ = new identifier_c(strdup("LT"), locloc(@$));} +| LE {$$ = new identifier_c(strdup("LE"), locloc(@$));} +| NE {$$ = new identifier_c(strdup("NE"), locloc(@$));} +/* + AND_operator {$$ = il_operator_c_2_identifier_c($1);} +//NOTE: AND2 (corresponding to the source code string '&') does not clash +// with a standard function name, so should be commented out! +//| AND2_operator {$$ = il_operator_c_2_identifier_c($1);} +| OR_operator {$$ = il_operator_c_2_identifier_c($1);} +| XOR_operator {$$ = il_operator_c_2_identifier_c($1);} +| ADD_operator {$$ = il_operator_c_2_identifier_c($1);} +| SUB_operator {$$ = il_operator_c_2_identifier_c($1);} +| MUL_operator {$$ = il_operator_c_2_identifier_c($1);} +| DIV_operator {$$ = il_operator_c_2_identifier_c($1);} +| MOD_operator {$$ = il_operator_c_2_identifier_c($1);} +| GT_operator {$$ = il_operator_c_2_identifier_c($1);} +| GE_operator {$$ = il_operator_c_2_identifier_c($1);} +| EQ_operator {$$ = il_operator_c_2_identifier_c($1);} +| LT_operator {$$ = il_operator_c_2_identifier_c($1);} +| LE_operator {$$ = il_operator_c_2_identifier_c($1);} +| NE_operator {$$ = il_operator_c_2_identifier_c($1);} +*/ +; + + +derived_function_name: + identifier +| prev_declared_derived_function_name + {$$ = $1; + if (!allow_function_overloading) { + fprintf(stderr, "Function overloading not allowed. Invalid identifier %s\n", ((token_c *)($1))->value); + ERROR; + } + } +| AND + {$$ = new identifier_c("AND", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"AND\" not allowed. Invalid identifier\n"); + } +| OR + {$$ = new identifier_c("OR", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"OR\" not allowed. Invalid identifier\n"); + } +| XOR + {$$ = new identifier_c("XOR", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"XOR\" not allowed. Invalid identifier\n"); + } +| NOT + {$$ = new identifier_c("NOT", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"NOT\" not allowed. Invalid identifier\n"); + } +| MOD + {$$ = new identifier_c("MOD", locloc(@$)); + if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"MOD\" not allowed. Invalid identifier\n"); + } +; + + +function_declaration: +/* FUNCTION derived_function_name ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ + function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION + {$$ = new function_declaration_c($1, $3, $4, $5, locloc(@$)); + add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + if (allow_function_overloading) { + switch (library_element_symtable.find_value($1)) { + case prev_declared_derived_function_name_token: + /* do nothing, already in map. */ + break; + case BOGUS_TOKEN_ID: + /* Not yet in map. Must insert...*/ + library_element_symtable.insert($1, prev_declared_derived_function_name_token); + break; + default: + /* Already in map but associated with something else other than a funtion name! */ + ERROR; + } + } else { + library_element_symtable.insert($1, prev_declared_derived_function_name_token); + } + } +/* | FUNCTION derived_function_name ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ +| function_name_declaration ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION + {$$ = new function_declaration_c($1, $3, $4, $5, locloc(@$)); + add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + if (allow_function_overloading) { + switch (library_element_symtable.find_value($1)) { + case prev_declared_derived_function_name_token: /* do nothing, already in map. */ break; + case BOGUS_TOKEN_ID: library_element_symtable.insert($1, prev_declared_derived_function_name_token); break; + default: ERROR; + } + } else { + library_element_symtable.insert($1, prev_declared_derived_function_name_token); + } + } +/* ERROR_CHECK_BEGIN */ +| function_name_declaration elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after function name in function declaration."); yynerrs++;} +| function_name_declaration derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after function name in function declaration."); yynerrs++;} +| function_name_declaration ':' io_OR_function_var_declarations_list function_body END_FUNCTION + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no return type defined in function declaration."); yynerrs++;} +| function_name_declaration ':' error io_OR_function_var_declarations_list function_body END_FUNCTION + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid return type defined in function declaration."); yyerrok;} +| function_name_declaration ':' elementary_type_name function_body END_FUNCTION + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared in function declaration."); yynerrs++;} +| function_name_declaration ':' derived_type_name function_body END_FUNCTION + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared in function declaration."); yynerrs++;} +| function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list END_FUNCTION + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no body defined in function declaration."); yynerrs++;} +| function_name_declaration ':' derived_type_name io_OR_function_var_declarations_list END_FUNCTION + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no body defined in function declaration."); yynerrs++;} +| function_name_declaration ':' elementary_type_name END_FUNCTION + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared and body defined in function declaration."); yynerrs++;} +| function_name_declaration ':' derived_type_name END_FUNCTION + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no variable(s) declared and body defined in function declaration."); yynerrs++;} +| function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list function_body END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locf(@3), "unclosed function declaration."); yynerrs++;} +| function_name_declaration ':' derived_type_name io_OR_function_var_declarations_list function_body END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed function declaration."); yynerrs++;} +| function_name_declaration error END_FUNCTION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in function declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + +/* helper symbol for function_declaration */ +/* NOTE: due to reduce/reduce conflicts between identifiers + * being reduced to either a variable or an enumerator value, + * we were forced to keep a symbol table of the names + * of all declared variables. Variables are no longer + * created from simple identifier_token, but from + * prev_declared_variable_name_token. + * + * BUT, in functions the function name itself may be used as + * a variable! In order to be able to parse this correctly, + * the token parser (flex) must return a prev_declared_variable_name_token + * when it comes across the function name, while parsing + * the function itself. + * We do this by inserting the function name into the variable + * symbol table, and having flex return a prev_declared_variable_name_token + * whenever it comes across it. + * When we finish parsing the function the variable name + * symbol table is cleared of all entries, and the function + * name is inserted into the library element symbol table. This + * means that from then onwards flex will return a + * derived_function_name_token whenever it comes across the + * function name. + * + * In order to insert the function name into the variable_name + * symbol table BEFORE the function body gets parsed, we + * need the parser to reduce a construct that contains the + * the function name. That is why we created this extra + * construct (function_name_declaration), i.e. to force + * the parser to reduce it, before parsing the function body! + */ +function_name_declaration: + FUNCTION derived_function_name + {$$ = $2; + /* the function name functions as a + * variable within the function itself! + * + * Remember that the variable_name_symtable + * is cleared once the end of the function + * is parsed. + */ + variable_name_symtable.insert($2, prev_declared_variable_name_token); + } +/* ERROR_CHECK_BEGIN */ +| FUNCTION error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no function name defined in function declaration.");} + else {print_err_msg(locf(@2), locl(@2), "invalid function name in function declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +/* intermediate helper symbol for function_declaration */ +io_OR_function_var_declarations_list: + io_var_declarations + {$$ = new var_declarations_list_c(locloc(@1));$$->add_element($1);} +| function_var_decls + {$$ = new var_declarations_list_c(locloc(@1));$$->add_element($1);} +| io_OR_function_var_declarations_list io_var_declarations + {$$ = $1; $$->add_element($2);} +| io_OR_function_var_declarations_list function_var_decls + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| io_OR_function_var_declarations_list retentive_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected retentive variable(s) declaration in function declaration."); yynerrs++;} +| io_OR_function_var_declarations_list located_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected located variable(s) declaration in function declaration."); yynerrs++;} +| io_OR_function_var_declarations_list external_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected external variable(s) declaration in function declaration."); yynerrs++;} +| io_OR_function_var_declarations_list global_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected global variable(s) declaration in function declaration."); yynerrs++;} +| io_OR_function_var_declarations_list incompl_located_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected incomplete located variable(s) declaration in function declaration."); yynerrs++;} +| io_OR_function_var_declarations_list temp_var_decls + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected temporary located variable(s) declaration in function declaration."); yynerrs++;} +| io_OR_function_var_declarations_list non_retentive_var_decls + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected non-retentive variable(s) declaration in function declaration."); yynerrs++;} +/*| io_OR_function_var_declarations_list access_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected access variable(s) declaration in function declaration."); yynerrs++;}*/ +| io_OR_function_var_declarations_list instance_specific_initializations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected instance specific initialization(s) in function declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +io_var_declarations: + input_declarations +| output_declarations +| input_output_declarations +; + + +function_var_decls: + VAR CONSTANT var2_init_decl_list END_VAR + {$$ = new function_var_decls_c(new constant_option_c(locloc(@2)), $3, locloc(@$));} +| VAR var2_init_decl_list END_VAR + {$$ = new function_var_decls_c(NULL, $2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR error var2_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR' in function variable(s) declaration."); yyerrok;} +| VAR CONSTANT error var2_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'CONSTANT' in constant function variable(s) declaration."); yyerrok;} +| VAR var2_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed function variable(s) declaration."); yyerrok;} +| VAR CONSTANT var2_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed constant function variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* intermediate helper symbol for function_var_decls */ +var2_init_decl_list: + var2_init_decl ';' + {$$ = new var2_init_decl_list_c(locloc(@$)); $$->add_element($1);} +| var2_init_decl_list var2_init_decl ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| var2_init_decl error + {$$ = new var2_init_decl_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of function variable(s) declaration."); yyerrok;} +| var2_init_decl_list var2_init_decl error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of function variable(s) declaration."); yyerrok;} +| var2_init_decl_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid function variable(s) declaration."); yyerrok;} +| var2_init_decl_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after function variable(s) declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +function_body: + statement_list {$$ = $1;} /* if we leave it for the default action we get a type clash! */ +| instruction_list {$$ = $1;} /* if we leave it for the default action we get a type clash! */ +/* +| ladder_diagram +| function_block_diagram +*/ +; + + +var2_init_decl: + var1_init_decl +| array_var_init_decl +| structured_var_init_decl +| string_var_declaration +; + + + +/*****************************/ +/* B 1.5.2 - Function Blocks */ +/*****************************/ +function_block_type_name: + prev_declared_derived_function_block_name +| standard_function_block_name +; + + +standard_function_block_name: standard_function_block_name_token {$$ = new identifier_c($1, locloc(@$));}; + +derived_function_block_name: identifier; + + +function_block_declaration: + FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK + {$$ = new function_block_declaration_c($2, $3, $4, locloc(@$)); + add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ + library_element_symtable.insert($2, prev_declared_derived_function_block_name_token); + /* Clear the variable_name_symtable. Since + * we have finished parsing the function block, + * the variable names are now out of scope, so + * are no longer valid! + */ + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + } +/* ERROR_CHECK_BEGIN */ +| FUNCTION_BLOCK io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in function block declaration."); yynerrs++;} +| FUNCTION_BLOCK error io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name in function block declaration."); yyerrok;} +| FUNCTION_BLOCK derived_function_block_name function_block_body END_FUNCTION_BLOCK + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared in function declaration."); yynerrs++;} +| FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list END_FUNCTION_BLOCK + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no body defined in function block declaration."); yynerrs++;} +| FUNCTION_BLOCK derived_function_block_name END_FUNCTION_BLOCK + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared and body defined in function block declaration."); yynerrs++;} +| FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "no variable(s) declared and body defined in function block declaration."); yynerrs++;} +| FUNCTION_BLOCK error END_FUNCTION_BLOCK + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in function block declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + +/* intermediate helper symbol for function_declaration */ +/* { io_var_declarations | other_var_declarations } */ +/* + * NOTE: we re-use the var_declarations_list_c + */ +io_OR_other_var_declarations_list: + io_var_declarations + {$$ = new var_declarations_list_c(locloc(@$));$$->add_element($1);} +| other_var_declarations + {$$ = new var_declarations_list_c(locloc(@$));$$->add_element($1);} +| io_OR_other_var_declarations_list io_var_declarations + {$$ = $1; $$->add_element($2);} +| io_OR_other_var_declarations_list other_var_declarations + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| io_OR_other_var_declarations_list located_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected located variable(s) declaration in function block declaration."); yynerrs++;} +| io_OR_other_var_declarations_list global_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected global variable(s) declaration in function block declaration."); yynerrs++;} +/*| io_OR_other_var_declarations_list access_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected access variable(s) declaration in function block declaration."); yynerrs++;}*/ +| io_OR_other_var_declarations_list instance_specific_initializations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected instance specific initialization(s) in function block declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +/* NOTE: + * The IEC specification gives the following definition: + * other_var_declarations ::= + * external_var_declarations + * | var_declarations + * | retentive_var_declarations + * | non_retentive_var_declarations + * | temp_var_decls + * | incompl_located_var_declarations + * + * Nvertheless, the symbol non_retentive_var_declarations + * is not defined in the spec. This seems to me (Mario) + * to be a typo, so non_retentive_var_declarations + * has been replaced with non_retentive_var_decls + * in the following rule! + */ +other_var_declarations: + temp_var_decls +| non_retentive_var_decls +| external_var_declarations +| var_declarations +| retentive_var_declarations +| incompl_located_var_declarations +; + + +temp_var_decls: + VAR_TEMP temp_var_decls_list END_VAR + {$$ = new temp_var_decls_c($2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR_TEMP END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in temporary variable(s) declaration."); yynerrs++;} +| VAR_TEMP temp_var_decls_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "unclosed temporary variable(s) declaration."); yyerrok;} +| VAR_TEMP error temp_var_decls_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_TEMP' in function variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* intermediate helper symbol for temp_var_decls */ +temp_var_decls_list: + temp_var_decl ';' + {$$ = new temp_var_decls_list_c(locloc(@$)); $$->add_element($1);} +| temp_var_decls_list temp_var_decl ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new temp_var_decls_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid temporary variable(s) declaration."); yyerrok;} +| temp_var_decl error + {$$ = new temp_var_decls_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at end of temporary variable(s) declaration."); yyerrok;} +| temp_var_decls_list temp_var_decl error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of temporary variable(s) declaration."); yyerrok;} +| temp_var_decls_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid temporary variable(s) declaration."); yyerrok;} +| temp_var_decls_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after temporary variable(s) declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +non_retentive_var_decls: + VAR NON_RETAIN var_init_decl_list END_VAR + {$$ = new non_retentive_var_decls_c($3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR NON_RETAIN var_init_decl_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unclosed non-retentive temporary variable(s) declaration."); yyerrok;} +| VAR NON_RETAIN error var_init_decl_list END_VAR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive temporary variable(s) declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + +function_block_body: + statement_list {$$ = $1;} +| instruction_list {$$ = $1;} +| sequential_function_chart {$$ = $1;} +/* +| ladder_diagram +| function_block_diagram +| +*/ +; + + + + +/**********************/ +/* B 1.5.3 - Programs */ +/**********************/ +program_type_name: identifier; + + +program_declaration: + PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM + {$$ = new program_declaration_c($2, $3, $4, locloc(@$)); + library_element_symtable.insert($2, prev_declared_program_type_name_token); + /* Clear the variable_name_symtable. Since + * we have finished parsing the program declaration, + * the variable names are now out of scope, so + * are no longer valid! + */ + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + } +/* ERROR_CHECK_BEGIN */ +| PROGRAM program_var_declarations_list function_block_body END_PROGRAM + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no program name defined in program declaration.");} +| PROGRAM error program_var_declarations_list function_block_body END_PROGRAM + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid program name in program declaration."); yyerrok;} +| PROGRAM program_type_name function_block_body END_PROGRAM + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared in program declaration."); yynerrs++;} +| PROGRAM program_type_name program_var_declarations_list END_PROGRAM + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no body defined in program declaration."); yynerrs++;} +| PROGRAM program_type_name END_PROGRAM + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared and body defined in program declaration."); yynerrs++;} +| PROGRAM program_type_name program_var_declarations_list function_block_body END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed program declaration."); yynerrs++;} +| PROGRAM error END_PROGRAM + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in program declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* helper symbol for program_declaration */ +/* + * NOTE: we re-use the var_declarations_list_c + */ +program_var_declarations_list: + io_var_declarations + {$$ = new var_declarations_list_c(locloc(@$)); $$->add_element($1);} +| other_var_declarations + {$$ = new var_declarations_list_c(locloc(@$)); $$->add_element($1);} +| located_var_declarations + {$$ = new var_declarations_list_c(locloc(@$)); $$->add_element($1);} +| program_var_declarations_list io_var_declarations + {$$ = $1; $$->add_element($2);} +| program_var_declarations_list other_var_declarations + {$$ = $1; $$->add_element($2);} +| program_var_declarations_list located_var_declarations + {$$ = $1; $$->add_element($2);} +/* +| program_var_declarations_list program_access_decls + {$$ = $1; $$->add_element($2);} +*/ +/* ERROR_CHECK_BEGIN */ +| program_var_declarations_list global_var_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected global variable(s) declaration in function block declaration."); yynerrs++;} +/*| program_var_declarations_list access_declarations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected access variable(s) declaration in function block declaration."); yynerrs++;}*/ +| program_var_declarations_list instance_specific_initializations + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected instance specific initialization(s) in function block declaration."); yynerrs++; + } +/* ERROR_CHECK_END */ +; + + +/* TODO ... */ +/* +program_access_decls: + VAR_ACCESS program_access_decl_list END_VAR +; +*/ + +/* helper symbol for program_access_decls */ +/* +program_access_decl_list: + program_access_decl ';' +| program_access_decl_list program_access_decl ';' +; +*/ + +/* +program_access_decl: + access_name ':' symbolic_variable ':' non_generic_type_name +| access_name ':' symbolic_variable ':' non_generic_type_name direction +; +*/ + + + +/********************************************/ +/* B 1.6 Sequential Function Chart elements * +/********************************************/ + +sequential_function_chart: + sfc_network + {$$ = new sequential_function_chart_c(locloc(@$)); $$->add_element($1);} +| sequential_function_chart sfc_network + {$$ = $1; $$->add_element($2);} +; + +sfc_network: + initial_step + {$$ = new sfc_network_c(locloc(@$)); $$->add_element($1);} +| sfc_network step + {$$ = $1; $$->add_element($2);} +| sfc_network transition + {$$ = $1; $$->add_element($2);} +| sfc_network action + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| sfc_network error + {$$ = $1; print_err_msg(locl(@1), locf(@2), "unexpected token after SFC network in sequencial function chart."); yyerrok;} +/* ERROR_CHECK_END */ +; + +initial_step: + INITIAL_STEP step_name ':' action_association_list END_STEP +// INITIAL_STEP identifier ':' action_association_list END_STEP + {$$ = new initial_step_c($2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| INITIAL_STEP ':' action_association_list END_STEP + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "no step name defined in initial step declaration."); yynerrs++;} +| INITIAL_STEP error ':' action_association_list END_STEP + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid step name defined in initial step declaration."); yyerrok;} +| INITIAL_STEP step_name action_association_list END_STEP + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':' missing after step name in initial step declaration."); yynerrs++;} +| INITIAL_STEP step_name ':' error END_STEP + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid action association list in initial step declaration."); yyerrok;} +| INITIAL_STEP step_name ':' action_association_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed initial step declaration."); yynerrs++;} +| INITIAL_STEP error END_STEP + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in initial step declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +step: + STEP step_name ':' action_association_list END_STEP +// STEP identifier ':' action_association_list END_STEP + {$$ = new step_c($2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| STEP ':' action_association_list END_STEP + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no step name defined in step declaration."); yynerrs++;} +| STEP error ':' action_association_list END_STEP + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid step name defined in step declaration."); yyerrok;} +| STEP step_name action_association_list END_STEP + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':' missing after step name in step declaration."); yynerrs++;} +| STEP step_name ':' error END_STEP + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid action association list in step declaration."); yyerrok;} +| STEP step_name ':' action_association_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@3), "invalid action association list in step declaration."); yynerrs++;} +| STEP error END_STEP + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in step declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for: + * - initial_step + * - step + */ +action_association_list: + /* empty */ + {$$ = new action_association_list_c(locloc(@$));} +| action_association_list action_association ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| action_association_list action_association error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at end of action association declaration."); yyerrok;} +| action_association_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after action association declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +// step_name: identifier; +step_name: any_identifier; + +action_association: + action_name '(' {cmd_goto_sfc_qualifier_state();} action_qualifier {cmd_pop_state();} indicator_name_list ')' + {$$ = new action_association_c($1, $4, $6, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +/*| action_name '(' error ')' + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid qualifier defined in action association."); yyerrok;}*/ +/* ERROR_CHECK_END */ +; + +/* helper symbol for action_association */ +indicator_name_list: + /* empty */ + {$$ = new indicator_name_list_c(locloc(@$));} +| indicator_name_list ',' indicator_name + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| indicator_name_list indicator_name + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing at end of action association declaration."); yynerrs++;} +| indicator_name_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no indicator defined in indicator list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid indicator in indicator list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +// action_name: identifier; +action_name: any_identifier; + +action_qualifier: + /* empty */ + {$$ = NULL;} +| qualifier + {$$ = new action_qualifier_c($1, NULL, locloc(@$));} +| timed_qualifier ',' action_time + {$$ = new action_qualifier_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| timed_qualifier action_time + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "',' missing between timed qualifier and action time in action qualifier."); yynerrs++;} +| timed_qualifier ',' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no action time defined in action qualifier.");} + else {print_err_msg(locf(@3), locl(@3), "invalid action time in action qualifier."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +qualifier: + N {$$ = new qualifier_c(strdup("N"), locloc(@$));} +| R {$$ = new qualifier_c(strdup("R"), locloc(@$));} +| S {$$ = new qualifier_c(strdup("S"), locloc(@$));} +| P {$$ = new qualifier_c(strdup("P"), locloc(@$));} +; + +timed_qualifier: + L {$$ = new timed_qualifier_c(strdup("L"), locloc(@$));} +| D {$$ = new timed_qualifier_c(strdup("D"), locloc(@$));} +| SD {$$ = new timed_qualifier_c(strdup("SD"), locloc(@$));} +| DS {$$ = new timed_qualifier_c(strdup("DS"), locloc(@$));} +| SL {$$ = new timed_qualifier_c(strdup("SL"), locloc(@$));} +; + +action_time: + duration +| variable +; + +indicator_name: variable; + +// transition_name: identifier; +transition_name: any_identifier; + + +steps: + step_name + {$$ = new steps_c($1, NULL, locloc(@$));} +| '(' step_name_list ')' + {$$ = new steps_c(NULL, $2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| '(' step_name_list error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "expecting ')' at the end of step list in transition declaration."); yyerrok;} +| '(' error ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid step list in transition declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +step_name_list: + step_name ',' step_name + {$$ = new step_name_list_c(locloc(@$)); $$->add_element($1); $$->add_element($3);} +| step_name_list ',' step_name + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| step_name_list step_name + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in step list."); yynerrs++;} +| step_name_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no step name defined in step list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid step name in step list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +/* NOTE: flex will automatically pop() out of body_state to previous state. + * We do not need to give a command from bison to return to previous flex state, + * after forcing flex to go to body_state. + */ +transition: + TRANSITION transition_priority + FROM steps TO steps + {cmd_goto_body_state();} transition_condition + END_TRANSITION + {$$ = new transition_c(NULL, $2, $4, $6, $8, locloc(@$));} +//| TRANSITION identifier FROM steps TO steps ... +| TRANSITION transition_name transition_priority + FROM steps TO steps + {cmd_goto_body_state();} transition_condition + END_TRANSITION + {$$ = new transition_c($2, $3, $5, $7, $9, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| TRANSITION error transition_priority FROM steps TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid transition name defined in transition declaration."); yyerrok;} +| TRANSITION transition_name error FROM steps TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid transition priority defined in transition declaration."); yyerrok;} +| TRANSITION transition_priority FROM TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no origin step(s) defined in transition declaration."); yynerrs++;} +| TRANSITION transition_name transition_priority FROM TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no origin step(s) defined in transition declaration."); yynerrs++;} +| TRANSITION transition_priority FROM error TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid origin step(s) defined in transition declaration."); yyerrok;} +| TRANSITION transition_name transition_priority FROM error TO steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locf(@5), locl(@5), "invalid origin step(s) defined in transition declaration."); yyerrok;} +| TRANSITION transition_priority FROM steps steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "'TO' missing between origin step(s) and destination step(s) in transition declaration."); yynerrs++;} +| TRANSITION transition_name transition_priority FROM steps steps {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@5), locf(@6), "'TO' missing between origin step(s) and destination step(s) in transition declaration."); yynerrs++;} +| TRANSITION transition_priority FROM steps TO {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@5), locf(@7), "no destination step(s) defined in transition declaration."); yynerrs++;} +| TRANSITION transition_name transition_priority FROM steps TO {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@6), locf(@8), "no destination step(s) defined in transition declaration."); yynerrs++;} +| TRANSITION transition_priority FROM steps TO error {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid destination step(s) defined in transition declaration."); yyerrok;} +| TRANSITION transition_name transition_priority FROM steps TO error {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locf(@7), locl(@7), "invalid destination step(s) defined in transition declaration."); yyerrok;} +| TRANSITION transition_priority {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@2), locf(@4), "no origin and destination step(s) defined in transition declaration."); yynerrs++;} +| TRANSITION transition_name transition_priority {cmd_goto_body_state();} transition_condition END_TRANSITION + {$$ = NULL; print_err_msg(locl(@3), locf(@5), "no origin and destination step(s) defined in transition declaration."); yynerrs++;} +/*| TRANSITION transition_priority FROM steps TO steps {cmd_goto_body_state();} transition_condition error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@6), "unclosed transition declaration."); yyerrok;} +| TRANSITION transition_name transition_priority FROM steps TO steps {cmd_goto_body_state();} transition_condition error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@7), "unclosed transition declaration."); yyerrok;}*/ +| TRANSITION error END_TRANSITION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in transition declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +transition_priority: + /* empty */ + {$$ = NULL;} +| '(' {cmd_goto_sfc_priority_state();} PRIORITY {cmd_pop_state();} ASSIGN integer ')' + {$$ = $6;} +/* ERROR_CHECK_BEGIN +| '(' ASSIGN integer ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'PRIORITY' missing between '(' and ':=' in transition declaration with priority."); yynerrs++;} +| '(' error ASSIGN integer ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "expecting 'PRIORITY' between '(' and ':=' in transition declaration with priority."); yyerrok;} + ERROR_CHECK_END */ +; + + +transition_condition: + ':' eol_list simple_instr_list + {$$ = new transition_condition_c($3, NULL, locloc(@$));} +| ASSIGN expression ';' + {$$ = new transition_condition_c(NULL, $2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| eol_list simple_instr_list + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing before IL condition in transition declaration."); yynerrs++;} +| ':' eol_list error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no instructions defined in IL condition of transition declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid instructions in IL condition of transition declaration."); yyclearin;} + yyerrok; + } +| ASSIGN ';' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no expression defined in ST condition of transition declaration."); yynerrs++;} +| ASSIGN error ';' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid expression defined in ST condition of transition declaration."); yyerrok;} +| ASSIGN expression error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "expecting ';' after expression defined in ST condition of transition declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + +action: +// ACTION identifier ':' ... + ACTION action_name {cmd_goto_body_state();} action_body END_ACTION + {$$ = new action_c($2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| ACTION {cmd_goto_body_state();} action_body END_ACTION + {$$ = NULL; print_err_msg(locl(@1), locf(@3), "no action name defined in action declaration."); yynerrs++;} +| ACTION error {cmd_goto_body_state();} action_body END_ACTION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid action name defined in action declaration."); yyerrok;} +| ACTION action_name {cmd_goto_body_state();} function_block_body END_ACTION + {$$ = NULL; print_err_msg(locl(@2), locf(@4), "':' missing after action name in action declaration."); yynerrs++;} +/*| ACTION action_name {cmd_goto_body_state();} action_body END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed action declaration."); yyerrok;}*/ +| ACTION error END_ACTION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in action declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +action_body: + ':' function_block_body + {$$ = $2;} +/* ERROR_CHECK_BEGIN */ +| ':' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no body defined in action declaration.");} + else {print_err_msg(locf(@2), locl(@2), "invalid body defined in action declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +/********************************/ +/* B 1.7 Configuration elements */ +/********************************/ +/* NOTE: + * It is not clear from reading the specification to which namespace + * the names of resources, tasks and programs belong to. + * + * The following syntax assumes that resource and program names belong to the + * same namespace as the variables defined within + * the resource/configuration (i.e. VAR_GLOBAL). + * Task names belong to a namespace all of their own, since they don't + * produce conflicts in the syntax parser, so we might just as well + * leave them be! ;-) + * The above decision was made taking into + * account that inside a VAR_CONFIG declaration global variables + * may be referenced starting off from the resource name as: + * resource_name.program_name.variable_name + * Notice how resource names and program names are used in a very similar + * manner as are variable names. + * Using a single namespace for all the above mentioned names + * also makes it easier to write the syntax parser!! ;-) Using a private + * namespace for each of the name types (resource names, program names, + * global varaiable names), i.e. letting the names be re-used across + * each of the groups (resource, program, global variables), produces + * reduce/reduce conflicts in the syntax parser. Actually, it is only + * the resource names that need to be distinguished into a + * prev_declared_resource_name so as not to conflict with [gloabl] variable + * names in the 'data' construct. + * The program names are only tracked to make sure that two programs do not + * get the same name. + * + * Using a single namespace does have the drawback that the user will + * not be able to re-use names for resources or programs if these + * have already been used to name a variable! + * + * If it ever becomes necessary to change this interpretation of + * the syntax, then this section of the syntax parser must be updated! + */ +prev_declared_global_var_name: prev_declared_global_var_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_resource_name: prev_declared_resource_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_program_name: prev_declared_program_name_token {$$ = new identifier_c($1, locloc(@$));}; +// prev_declared_task_name: prev_declared_task_name_token {$$ = new identifier_c($1, locloc(@$));}; + + + + + + +configuration_name: identifier; + +/* NOTE: The specification states that valid resource type names + * are implementation defined, i.e. each implementaion will define + * what resource types it supports. + * We are implementing this syntax parser to be used by any + * implementation, so at the moment we accept any identifier + * as a resource type name. + * This implementation should probably be changed in the future. We + * should probably have a resource_type_name_token, and let the + * implementation load the global symbol library with the + * accepted resource type names before parsing the code. + * + */ +resource_type_name: any_identifier; + +configuration_declaration: + CONFIGURATION configuration_name + optional_global_var_declarations + single_resource_declaration + {variable_name_symtable.pop(); + direct_variable_symtable.pop();} + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = new configuration_declaration_c($2, $3, $4, $6, $7, locloc(@$)); + library_element_symtable.insert($2, prev_declared_configuration_name_token); + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + } +| CONFIGURATION configuration_name + optional_global_var_declarations + resource_declaration_list + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = new configuration_declaration_c($2, $3, $4, $5, $6, locloc(@$)); + library_element_symtable.insert($2, prev_declared_configuration_name_token); + variable_name_symtable.pop(); + direct_variable_symtable.pop(); +} +/* ERROR_CHECK_BEGIN */ +| CONFIGURATION + optional_global_var_declarations + single_resource_declaration + {variable_name_symtable.pop(); + direct_variable_symtable.pop();} + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no configuration name defined in configuration declaration."); yynerrs++;} +| CONFIGURATION + optional_global_var_declarations + resource_declaration_list + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no configuration name defined in configuration declaration."); yynerrs++;} +| CONFIGURATION error + optional_global_var_declarations + single_resource_declaration + {variable_name_symtable.pop(); + direct_variable_symtable.pop();} + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid configuration name defined in configuration declaration."); yyerrok;} +| CONFIGURATION error + optional_global_var_declarations + resource_declaration_list + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid configuration name defined in configuration declaration."); yyerrok;} +| CONFIGURATION configuration_name + optional_global_var_declarations + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no resource(s) defined in configuration declaration."); yynerrs++;} +| CONFIGURATION configuration_name + optional_global_var_declarations + error + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid resource(s) defined in configuration declaration."); yyerrok;} +/*| CONFIGURATION configuration_name + optional_global_var_declarations + single_resource_declaration + {variable_name_symtable.pop(); + direct_variable_symtable.pop();} + optional_access_declarations + optional_instance_specific_initializations + END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed configuration declaration."); yyerrok;}*/ +| CONFIGURATION configuration_name + optional_global_var_declarations + resource_declaration_list + optional_access_declarations + optional_instance_specific_initializations + END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed configuration declaration."); yyerrok;} +| CONFIGURATION error END_CONFIGURATION + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in configuration declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + +// helper symbol for +// - configuration_declaration +// - resource_declaration +// +optional_global_var_declarations: + // empty + {$$ = NULL;} +| global_var_declarations +; + + +// helper symbol for configuration_declaration // +optional_access_declarations: + // empty + {$$ = NULL;} +//| access_declarations +; + +// helper symbol for configuration_declaration // +optional_instance_specific_initializations: + // empty + {$$ = NULL;} +| instance_specific_initializations +; + +// helper symbol for configuration_declaration // +resource_declaration_list: + resource_declaration + {$$ = new resource_declaration_list_c(locloc(@$)); $$->add_element($1);} +| resource_declaration_list resource_declaration + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| resource_declaration_list error + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected token after resource declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +resource_declaration: + RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} resource_name ON resource_type_name + optional_global_var_declarations + single_resource_declaration + END_RESOURCE + {$$ = new resource_declaration_c($3, $5, $6, $7, locloc(@$)); + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + variable_name_symtable.insert($3, prev_declared_resource_name_token); + } +/* ERROR_CHECK_BEGIN */ +| RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} ON resource_type_name + optional_global_var_declarations + single_resource_declaration + END_RESOURCE + {$$ = NULL; print_err_msg(locl(@1), locf(@3), "no resource name defined in resource declaration."); yynerrs++;} +/*| RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} resource_name ON resource_type_name + optional_global_var_declarations + single_resource_declaration + END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@5), "unclosed resource declaration."); yyerrok;}*/ +| RESOURCE error END_RESOURCE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in resource declaration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +single_resource_declaration: + task_configuration_list program_configuration_list + {$$ = new single_resource_declaration_c($1, $2, locloc(@$));} +; + + +// helper symbol for single_resource_declaration // +task_configuration_list: + // empty + {$$ = new task_configuration_list_c(locloc(@$));} +| task_configuration_list task_configuration ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| task_configuration_list task_configuration error + {$$ = $1; print_err_msg(locl(@1), locf(@2), "';' missing at the end of task configuration in resource declaration."); yyerrok;} +| task_configuration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after task configuration in resource declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +// helper symbol for single_resource_declaration // +program_configuration_list: + program_configuration ';' + {$$ = new program_configuration_list_c(locloc(@$)); $$->add_element($1);} +| program_configuration_list program_configuration ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| program_configuration error + {$$ = new program_configuration_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at the end of program configuration in resource declaration."); yyerrok;} +| program_configuration_list program_configuration error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of program configuration in resource declaration."); yyerrok;} +| program_configuration_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid program configuration in resource declaration."); yyerrok;} +| program_configuration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after program configuration in resource declaration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +resource_name: identifier; + +/* +access_declarations: + VAR_ACCESS access_declaration_list END_VAR + {$$ = NULL;} +// ERROR_CHECK_BEGIN // +| VAR_ACCESS END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in access variable(s) declaration."); yynerrs++;} +| VAR_ACCESS error access_declaration_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_ACCESS' in access variable(s) declaration."); yyerrok;} +| VAR_ACCESS access_declaration_list error END_VAR + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed access variable(s) declaration."); yyerrok;} +| VAR_ACCESS error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in access variable(s) declaration."); yyerrok;} +// ERROR_CHECK_END // +; + +// helper symbol for access_declarations // +access_declaration_list: + access_declaration ';' +| access_declaration_list access_declaration ';' +// ERROR_CHECK_BEGIN // +| error ';' + {$$ = // create a new list //; + print_err_msg(locf(@1), locl(@1), "invalid access variable declaration."); yyerrok;} +| access_declaration error + {$$ = // create a new list //; + print_err_msg(locl(@1), locf(@2), "';' missing at the end of access variable declaration."); yyerrok;} +| access_declaration_list access_declaration error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of access variable declaration."); yyerrok;} +| access_declaration_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid access variable declaration."); yyerrok;} +| access_declaration_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after access variable declaration."); yynerrs++;} +// ERROR_CHECK_END // +; + + +access_declaration: + access_name ':' access_path ':' non_generic_type_name +| access_name ':' access_path ':' non_generic_type_name direction +; + + +access_path: + prev_declared_direct_variable +| prev_declared_resource_name '.' prev_declared_direct_variable +| any_fb_name_list symbolic_variable +| prev_declared_resource_name '.' any_fb_name_list symbolic_variable +| prev_declared_program_name '.' any_fb_name_list symbolic_variable +| prev_declared_resource_name '.' prev_declared_program_name '.' any_fb_name_list symbolic_variable +; +*/ + +// helper symbol for +// - access_path +// - instance_specific_init +// +/* NOTE: The fb_name_list refers to funtion block variables + * that have been declared in a scope outside the one we are + * currently parsing, so we must accept them to be any_identifier! + * + * Beware that other locations of this syntax parser also require + * a fb_name_list. In those locations the function blocks are being declared, + * so only currently un-used identifiers (i.e. identifier) may be accepted. + * + * In order to distinguish the two, here we use any_fb_name_list, while + * in the the locations we simply use fb_name_list! + */ +any_fb_name_list: + // empty + {$$ = new any_fb_name_list_c(locloc(@$));} +//| fb_name_list fb_name '.' +| any_fb_name_list any_identifier '.' + {$$ = $1; $$->add_element($2);} +; + + + +global_var_reference: +// [resource_name '.'] global_var_name ['.' structure_element_name] // + prev_declared_global_var_name + {$$ = new global_var_reference_c(NULL, $1, NULL, locloc(@$));} +| prev_declared_global_var_name '.' structure_element_name + {$$ = new global_var_reference_c(NULL, $1, $3, locloc(@$));} +| prev_declared_resource_name '.' prev_declared_global_var_name + {$$ = new global_var_reference_c($1, $3, NULL, locloc(@$));} +| prev_declared_resource_name '.' prev_declared_global_var_name '.' structure_element_name + {$$ = new global_var_reference_c($1, $3, $5, locloc(@$));} +; + + +//access_name: identifier; + + +program_output_reference: +/* NOTE: + * program_output_reference is merely used within data_source. + * data_source is merely used within task_initialization + * task_initialization appears in a configuration declaration + * _before_ the programs are declared, so we cannot use + * prev_declared_program_name, as what might seem correct at first. + * + * The semantic checker must later check whether the identifier + * used really refers to a program declared after the task + * initialization! + */ +// prev_declared_program_name '.' symbolic_variable + program_name '.' symbolic_variable + {$$ = new program_output_reference_c($1, $3, locloc(@$));} +; + +program_name: identifier; + +/* +direction: + READ_WRITE + {$$ = NULL;} +| READ_ONLY + {$$ = NULL;} +; +*/ + +task_configuration: + TASK task_name task_initialization + {$$ = new task_configuration_c($2, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| TASK task_initialization + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no task name defined in task declaration."); yynerrs++;} +| TASK error task_initialization + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid task name defined in task declaration."); yyerrok;} +| TASK task_name error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no task initialization defined in task declaration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid task initialization in task declaration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* NOTE: The specification does not mention the namespace to which task names + * should belong to. Unlike resource and program names, for the moment we + * let the task names belong to their own private namespace, as they do not + * produce any conflicts in the syntax parser. + * If in the future our interpretation of the spec. turns out to be incorrect, + * the definition of task_name may have to be changed! + */ +task_name: any_identifier; + + +task_initialization: +// '(' [SINGLE ASSIGN data_source ','] [INTERVAL ASSIGN data_source ','] PRIORITY ASSIGN integer ')' // + '(' {cmd_goto_task_init_state();} task_initialization_single task_initialization_interval task_initialization_priority ')' + {$$ = new task_initialization_c($3, $4, $5, locloc(@$));} +; + + +task_initialization_single: +// [SINGLE ASSIGN data_source ','] + /* empty */ + {$$ = NULL;} +| SINGLE ASSIGN {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} + {$$ = $4;} +/* ERROR_CHECK_BEGIN */ +| SINGLE {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} + {$$ = NULL; print_err_msg(locl(@1), locf(@3), "':=' missing after 'SINGLE' in task initialization."); yynerrs++;} +| SINGLE ASSIGN {cmd_pop_state();} ',' {cmd_goto_task_init_state();} + {$$ = NULL; print_err_msg(locl(@2), locf(@4), "no data source defined in 'SINGLE' statement of task initialization."); yynerrs++;} +| SINGLE ASSIGN {cmd_pop_state();} error ',' {cmd_goto_task_init_state();} + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid data source defined in 'SINGLE' statement of task initialization."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +task_initialization_interval: +// [INTERVAL ASSIGN data_source ','] + /* empty */ + {$$ = NULL;} +| INTERVAL ASSIGN {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} + {$$ = $4;} +/* ERROR_CHECK_BEGIN */ +| INTERVAL {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} + {$$ = NULL; print_err_msg(locl(@1), locf(@3), "':=' missing after 'INTERVAL' in task initialization.");} +| INTERVAL ASSIGN {cmd_pop_state();} ',' {cmd_goto_task_init_state();} + {$$ = NULL; print_err_msg(locl(@2), locf(@4), "no data source defined in 'INTERVAL' statement of task initialization."); yynerrs++;} +| INTERVAL ASSIGN {cmd_pop_state();} error ',' {cmd_goto_task_init_state();} + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid data source defined in 'INTERVAL' statement of task initialization."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + +task_initialization_priority: +// PRIORITY ASSIGN integer + PRIORITY ASSIGN {cmd_pop_state();} integer + {$$ = $4;} +/* ERROR_CHECK_BEGIN */ +| PRIORITY {cmd_pop_state();} integer + {$$ = NULL; print_err_msg(locl(@1), locf(@3), "':=' missing after 'PRIORITY' in task initialization."); yynerrs++;} +| PRIORITY ASSIGN {cmd_pop_state();} error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@4), "no priority number defined in 'PRIORITY' statement of task initialization.");} + else {print_err_msg(locf(@4), locl(@4), "invalid priority number in 'PRIORITY' statement of task initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +data_source: + constant +| global_var_reference +| program_output_reference +| prev_declared_direct_variable +; + +program_configuration: +// PROGRAM [RETAIN | NON_RETAIN] program_name [WITH task_name] ':' program_type_name ['(' prog_conf_elements ')'] // + PROGRAM program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = new program_configuration_c(NULL, $2, $3, $5, $6, locloc(@$)); + variable_name_symtable.insert($2, prev_declared_program_name_token); + } +| PROGRAM RETAIN program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = new program_configuration_c(new retain_option_c(locloc(@2)), $3, $4, $6, $7, locloc(@$)); + variable_name_symtable.insert($3, prev_declared_program_name_token); + } +| PROGRAM NON_RETAIN program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = new program_configuration_c(new non_retain_option_c(locloc(@2)), $3, $4, $6, $7, locloc(@$)); + variable_name_symtable.insert($3, prev_declared_program_name_token); + } +/* ERROR_CHECK_BEGIN */ +| PROGRAM program_name optional_task_name ':' identifier optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@5), locl(@5), "invalid program type name after ':' in program configuration."); yynerrs++;} +| PROGRAM RETAIN program_name optional_task_name ':' identifier optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid program type name after ':' in program configuration."); yynerrs++;} +| PROGRAM NON_RETAIN program_name optional_task_name ':' identifier optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid program type name after ':' in program configuration."); yynerrs++;} +| PROGRAM error program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'PROGRAM' in program configuration."); yyerrok;} +| PROGRAM RETAIN error program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'RETAIN' in retentive program configuration."); yyerrok;} +| PROGRAM NON_RETAIN error program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "unexpected token after 'NON_RETAIN' in non-retentive program configuration."); yyerrok;} +| PROGRAM optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no program name defined in program configuration."); yynerrs++;} +| PROGRAM RETAIN optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no program name defined in retentive program configuration."); yynerrs++;} +| PROGRAM NON_RETAIN optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no program name defined in non-retentive program configuration."); yynerrs++;} +| PROGRAM error optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid program name defined in program configuration."); yyerrok;} +| PROGRAM RETAIN error optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid program name defined in retentive program configuration."); yyerrok;} +| PROGRAM NON_RETAIN error optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid program name defined in non-retentive program configuration."); yyerrok;} +| PROGRAM program_name optional_task_name prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "':' missing after program name or optional task name in program configuration."); yynerrs++;} +| PROGRAM RETAIN program_name optional_task_name prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':' missing after program name or optional task name in retentive program configuration."); yynerrs++;} +| PROGRAM NON_RETAIN program_name optional_task_name prev_declared_program_type_name optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "':' missing after program name or optional task name in non-retentive program configuration."); yynerrs++;} +| PROGRAM program_name optional_task_name ':' optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "no program type defined in program configuration."); yynerrs++;} +| PROGRAM RETAIN program_name optional_task_name ':' optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@5), locf(@6), "no program type defined in retentive program configuration."); yynerrs++;} +| PROGRAM NON_RETAIN program_name optional_task_name ':' optional_prog_conf_elements + {$$ = NULL; print_err_msg(locl(@5), locf(@6), "no program type defined in non-retentive program configuration."); yynerrs++;} +/* ERROR_CHECK_END */ +; + +// helper symbol for program_configuration // +optional_task_name: + // empty // + {$$ = NULL;} +| WITH task_name + {$$ = $2;} +/* ERROR_CHECK_BEGIN */ +| WITH error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no task name defined in optional task name of program configuration.");} + else {print_err_msg(locf(@2), locl(@2), "invalid task name in optional task name of program configuration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +// helper symbol for program_configuration // +optional_prog_conf_elements: + // empty // + {$$ = NULL;} +| '(' prog_conf_elements ')' + {$$ = $2;} +/* ERROR_CHECK_BEGIN */ +| '(' error ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid program configuration elements in program configuration."); yyerrok;} +| '(' prog_conf_elements error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of program configuration elements in program configuration."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +prog_conf_elements: + prog_conf_element + {$$ = new prog_conf_elements_c(locloc(@$)); $$->add_element($1);} +| prog_conf_elements ',' prog_conf_element + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| prog_conf_elements prog_conf_element + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in program configuration elements list."); yynerrs++;} +| prog_conf_elements ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for program configuration element in program configuration list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value for program configuration element in program configuration list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +prog_conf_element: + fb_task +| prog_cnxn +; + + +fb_task: + // fb_name WITH task_name +/* NOTE: The fb_name refers to funtion block variables + * that have been declared in a scope outside the one we are + * currently parsing, so we must accept them to be any_identifier! + */ + any_identifier WITH task_name + {$$ = new fb_task_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| any_identifier WITH error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no task name defined in function block configuration.");} + else {print_err_msg(locf(@3), locl(@3), "invalid task name in function block configuration."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +/* NOTE: + * The semantics of configuring a program are rather confusing, so here is + * my (Mario) understanding on the issue... + * + * A function/program may have as its input variables a simple variable + * (BYTE, WORD, etc...), an array (ARRAY [1 .. 3] OF BYTE, ...) , or a structure. + * Nevertheless, when calling this function from within a st or il language statement + * it is not possible to allocate a value to a single element of the array or structure + * typed input variable, as the accepted syntax is simply '(' variable_name ':=' variable ')' + * Notice how the variable_name does not include things such as 'a.elem1' or 'a[1]'! + * + * Nevertheless, when configuring a program from within a configuration, + * it becomes possible to allocate values to individual elements of the + * array or structured type input variable, as the syntax is now + * '(' symbolic_variable ':=' data_sink|prog_data_source ')' + * Notice how the symbolic_variable _does_ include things such as 'a.elem1' or 'a[1]'! + * + * Conclusion: Unlike other locations in the syntax where SENDTO appears, + * here it is not valid to replace symbolic_variable with any_identifier! + * Nevertheless, it is also not correct to leave symbolic_variable as it is, + * as we have defined it to only include previously declared variables, + * which is not the case in this situation. Here symbolic_variable is refering + * to variables that were defined within the scope of the program that is being + * called, and _not_ within the scope of the configuration that is calling the + * program, so the variables in question are not declared in the current scope! + * + * We therefore need to define a new symbolic_variable, that accepts any_identifier + * instead of previosuly declared variable names, to be used in the definition of + * prog_cnxn! + */ +prog_cnxn: + any_symbolic_variable ASSIGN prog_data_source + {$$ = new prog_cnxn_assign_c($1, $3, locloc(@$));} +| any_symbolic_variable SENDTO data_sink + {$$ = new prog_cnxn_sendto_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| any_symbolic_variable constant + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing between parameter and value in program configuration element."); yynerrs++;} +| any_symbolic_variable enumerated_value + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing between parameter and value in program configuration element."); yynerrs++;} +| any_symbolic_variable data_sink + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' or '=>' missing between parameter and variable in program configuration element."); yynerrs++;} +| any_symbolic_variable ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value or variable defined in program configuration assignment element.");} + else {print_err_msg(locf(@3), locl(@3), "invalid value or variable in program configuration assignment element."); yyclearin;} + yyerrok; + } +| any_symbolic_variable SENDTO error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no variable defined in program configuration sendto element.");} + else {print_err_msg(locf(@3), locl(@3), "invalid variable in program configuration sendto element."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +prog_data_source: + constant +| enumerated_value +| global_var_reference +| prev_declared_direct_variable +; + +data_sink: + global_var_reference +| prev_declared_direct_variable +; + +instance_specific_initializations: + VAR_CONFIG instance_specific_init_list END_VAR + {$$ = new instance_specific_initializations_c($2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| VAR_CONFIG END_VAR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no variable declared in configuration variable(s) initialization."); yynerrs++;} +| VAR_CONFIG error instance_specific_init_list END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unexpected token after 'VAR_CONFIG' in configuration variable(s) initialization."); yyerrok;} +| VAR_CONFIG instance_specific_init_list error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed configuration variable(s) initialization."); yyerrok;} +| VAR_CONFIG error END_VAR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in configuration variable(s) initialization."); yyerrok;} +/* ERROR_CHECK_END */ +; + +// helper symbol for instance_specific_initializations // +instance_specific_init_list: + instance_specific_init ';' + {$$ = new instance_specific_init_list_c(locloc(@$)); $$->add_element($1);} +| instance_specific_init_list instance_specific_init ';' + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| error ';' + {$$ = new instance_specific_init_list_c(locloc(@$)); print_err_msg(locf(@1), locl(@1), "invalid configuration variable initialization."); yyerrok;} +| instance_specific_init error + {$$ = new instance_specific_init_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at the end of configuration variable initialization."); yyerrok;} +| instance_specific_init_list instance_specific_init error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of configuration variable initialization."); yyerrok;} +| instance_specific_init_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid configuration variable initialization."); yyerrok;} +| instance_specific_init_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after configuration variable initialization."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +instance_specific_init: +// +// resource_name '.' program_name '.' {fb_name '.'} +// ((variable_name [location] ':' located_var_spec_init) | (fb_name ':' function_block_type_name ':=' structure_initialization)) +// +// prev_declared_resource_name '.' prev_declared_program_name '.' any_fb_name_list variable_name ':' located_var_spec_init +/* NOTE: variable_name has been changed to any_identifier (and not simply identifier) because the + * variables being referenced have been declared outside the scope currently being parsed! + */ +/* NOTE: program_name has not been changed to prev_declared_program_name because the + * programs being referenced have been declared outside the scope currently being parsed! + * The programs are only kept inside the scope of the resource in which they are defined. + */ + prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier ':' located_var_spec_init + {$$ = new instance_specific_init_c($1, $3, $5, $6, NULL, $8, locloc(@$));} +| prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier location ':' located_var_spec_init + {$$ = new instance_specific_init_c($1, $3, $5, $6, $7, $9, locloc(@$));} +| prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier ':' fb_initialization + {$5->add_element($6); $$ = new instance_specific_init_c($1, $3, $5, NULL, NULL, $8, locloc(@$));} +; + + +/* helper symbol for instance_specific_init */ +fb_initialization: + function_block_type_name ASSIGN structure_initialization + {$$ = new fb_initialization_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| function_block_type_name structure_initialization + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':=' missing between function block name and initialization in function block initialization."); yynerrs++;} +| function_block_type_name ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no initial value defined in function block initialization.");} + else {print_err_msg(locf(@3), locl(@3), "invalid initial value in function block initialization."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/***********************************/ +/* B 2.1 Instructions and Operands */ +/***********************************/ +/* helper symbol for many IL instructions, etc... */ +/* eat up any extra EOL tokens... */ + +eol_list: + EOL +| eol_list EOL +; + + + +instruction_list: + il_instruction + {$$ = new instruction_list_c(locloc(@$)); $$->add_element($1);} +| any_pragma eol_list + {$$ = new instruction_list_c(locloc(@$)); $$->add_element($1);} +| instruction_list il_instruction + {$$ = $1; $$->add_element($2);} +| instruction_list any_pragma + {$$ = $1; $$->add_element($2);} +; + + + +il_instruction: + il_incomplete_instruction eol_list + {$$ = new il_instruction_c(NULL, $1, locloc(@$));} +| label ':' il_incomplete_instruction eol_list + {$$ = new il_instruction_c($1, $3, locloc(@$));} +| label ':' eol_list + {$$ = new il_instruction_c($1, NULL, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| error eol_list + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid IL instruction."); yyerrok;} +| il_incomplete_instruction error + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing at the end of IL instruction."); yyerrok;} +| error ':' il_incomplete_instruction eol_list + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid label in IL instruction."); yyerrok;} +| label il_incomplete_instruction eol_list + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after label in IL instruction."); yynerrs++;} +| label ':' error eol_list + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid IL instruction."); yyerrok;} +| label ':' il_incomplete_instruction error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "EOL missing at the end of IL instruction."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* helper symbol for il_instruction */ +il_incomplete_instruction: + il_simple_operation +| il_expression +| il_jump_operation +| il_fb_call +| il_formal_funct_call +| il_return_operator +; + + +label: identifier; + + + +il_simple_operation: +// (il_simple_operator [il_operand]) | (function_name [il_operand_list]) + il_simple_operator + {$$ = new il_simple_operation_c($1, NULL, locloc(@$));} +/* + * Note: Bison is getting confused with the following rule, + * i.e. it is finding conflicts where there seemingly are really none. + * The rule was therefore replaced by the equivalent following + * two rules. + */ +/* +| il_simple_operator il_operand + {$$ = new il_simple_operation_c($1, $2, locloc(@$));} +*/ +| il_simple_operator_noclash il_operand + {$$ = new il_simple_operation_c($1, $2, locloc(@$));} +| il_simple_operator_clash il_operand + {$$ = new il_simple_operation_c($1, $2, locloc(@$));} +/* NOTE: the line + * | il_simple_operator + * already contains the 'NOT' operator, as well as all the + * expression operators ('MOD', 'AND', etc...), all of which + * may also be a function name! This means that these operators/functions, + * without any operands, could be reduced to either an operator or a + * function call. + * + * I (Mario) have chosen to reduce it to an operator. + * In order to do this, we must remove from the syntax that defines + * function calls all the functions whose names clash with the IL operators. + * + * The line + * | function_name + * has been replaced with the lines + * | function_name_no_clashes + * in order to include all possible function names except + * those whose names coincide with operators !! + */ +| function_name_no_clashes + {$$ = new il_function_call_c($1, NULL, locloc(@$));} +/* NOTE: the line + * | il_simple_operator il_operand + * already contains the 'NOT', 'MOD', etc. operators, followed by a single il_operand. + * However, this same code (MOD x) may also be reduced to a function call to the MOD + * function. This means that (MOD, AND,...) could be interpret as a function name + * or as an IL operator! This would lead us to a reduce/reduce conflict! + * + * I (Mario) have chosen to reduce it to an operand, rather than a function call. + * In order to do this, we must remove from the syntax that defines + * function calls all the functions whose names clash with the IL operators. + * + * The line + * | function_name il_operand_list + * has been replaced with the line + * | function_name_no_clashes il_operand_list + * in order to include all possible function names except + * for the function names which clash with expression and simple operators. + * + * Note that: + * this alternative syntax does not cover the possibility of + * the function 'NOT', 'MOD', etc... being called with more than one il_operand, + * in which case it is always a function call, and not an IL instruction. + * We therefore need to include an extra rule where the + * function_name_expression_clashes and function_name_simpleop_clashes + * are followed by a il_operand_list with __two__ or more il_operands!! + */ +| function_name_no_clashes il_operand_list + {$$ = new il_function_call_c($1, $2, locloc(@$));} +| il_simple_operator_clash il_operand_list2 + {$$ = new il_function_call_c(il_operator_c_2_identifier_c($1), $2, locloc(@$));} +; + + + +il_expression: +// il_expr_operator '(' [il_operand] EOL {EOL} [simple_instr_list] ')' +/* + * Note: Bison is getting confused with the use of il_expr_operator, + * i.e. it is finding conflicts where there seemingly are really none. + * il_expr_operator was therefore replaced by the equivalent + * il_expr_operator_noclash | il_expr_operator_clash. + */ + il_expr_operator_noclash '(' eol_list ')' + {$$ = new il_expression_c($1, NULL, NULL, locloc(@$));} +| il_expr_operator_noclash '(' il_operand eol_list ')' + {$$ = new il_expression_c($1, $3, NULL, locloc(@$));} +| il_expr_operator_noclash '(' eol_list simple_instr_list ')' + {$$ = new il_expression_c($1, NULL, $4, locloc(@$));} +| il_expr_operator_noclash '(' il_operand eol_list simple_instr_list ')' + {$$ = new il_expression_c($1, $3, $5, locloc(@$));} +| il_expr_operator_clash '(' eol_list ')' + {$$ = new il_expression_c($1, NULL, NULL, locloc(@$));} +| il_expr_operator_clash '(' il_operand eol_list ')' + {$$ = new il_expression_c($1, $3, NULL, locloc(@$));} +| il_expr_operator_clash '(' il_operand eol_list simple_instr_list ')' + {$$ = new il_expression_c($1, $3, $5, locloc(@$));} +| il_expr_operator_clash_eol_list simple_instr_list ')' + {$$ = new il_expression_c($1, NULL, $2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| il_expr_operator_noclash '(' eol_list error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of IL expression."); yyerrok;} +| il_expr_operator_noclash '(' il_operand eol_list error + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL expression."); yyerrok;} +| il_expr_operator_noclash '(' eol_list simple_instr_list error + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL expression."); yyerrok;} +| il_expr_operator_noclash '(' il_operand eol_list simple_instr_list error + {$$ = NULL; print_err_msg(locl(@5), locf(@6), "')' missing at the end of IL expression."); yyerrok;} +| il_expr_operator_clash '(' il_operand eol_list error + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL expression."); yyerrok;} +| il_expr_operator_clash '(' il_operand eol_list simple_instr_list error + {$$ = NULL; print_err_msg(locl(@5), locf(@6), "')' missing at the end of IL expression."); yyerrok;} +| il_expr_operator_clash_eol_list simple_instr_list error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of IL expression."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_jump_operation: + il_jump_operator label + {$$ = new il_jump_operation_c($1, $2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| il_jump_operator error + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid label defined in IL jump operation."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_fb_call: +// il_call_operator fb_name ['(' (EOL {EOL} [il_param_list]) | [il_operand_list] ')'] + il_call_operator prev_declared_fb_name + {$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));} +| il_call_operator prev_declared_fb_name '(' ')' + {$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));} +| il_call_operator prev_declared_fb_name '(' eol_list ')' + {$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));} +| il_call_operator prev_declared_fb_name '(' il_operand_list ')' + {$$ = new il_fb_call_c($1, $2, $4, NULL, locloc(@$));} +| il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')' + {$$ = new il_fb_call_c($1, $2, NULL, $5, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| il_call_operator error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call.");} + else {print_err_msg(locf(@2), locl(@2), "invalid function block name in IL function block call."); yyclearin;} + yyerrok; + } +| il_call_operator '(' ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} +| il_call_operator '(' eol_list ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} +| il_call_operator '(' il_operand_list ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} +| il_call_operator '(' eol_list il_param_list ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no function block name defined in IL function block call."); yynerrs++;} +| il_call_operator error '(' ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} +| il_call_operator error '(' eol_list ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} +| il_call_operator error '(' il_operand_list ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} +| il_call_operator error '(' eol_list il_param_list ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid function block name defined in IL function block call."); yyerrok;} +| il_call_operator prev_declared_fb_name ')' + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'(' missing after function block name defined in IL function block call."); yynerrs++;} +| il_call_operator prev_declared_fb_name il_operand_list ')' + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "'(' missing after function block name defined in IL function block call."); yynerrs++;} +| il_call_operator prev_declared_fb_name '(' error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of IL function block call."); yyerrok;} +| il_call_operator prev_declared_fb_name '(' eol_list error + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL function block call."); yyerrok;} +| il_call_operator prev_declared_fb_name '(' il_operand_list error + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of IL function block call."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* NOTE: Please read note above the definition of function_name_without_clashes */ +il_formal_funct_call: +// function_name '(' EOL {EOL} [il_param_list] ')' +/* function_name '(' eol_list ')' */ +/* NOTE: il_formal_funct_call is only used in the definition of + * - il_incomplete_instruction + * - il_simple_instruction + * In both of the above, il_expression also + * shows up as another option. This means that the functions whose + * names clash with expressions, followed by '(' eol_list ')', are + * already included. We must therefore leave them out in this + * definition in order to remove reduce/reduce conflicts. + * + * In summary: 'MOD' '(' eol_list ')', and all other functions whose + * names clash with expressions may be interpreted by the syntax by + * two different routes. I (Mario) chose to interpret them + * as operators, rather than as function calls! + * (AND MOD OR XOR ADD DIV EQ GT GE LT LE MUL NE SUB) + */ + function_name_no_clashes '(' eol_list ')' + {$$ = new il_formal_funct_call_c($1, NULL, locloc(@$));} +| function_name_simpleop_clashes '(' eol_list ')' + {$$ = new il_formal_funct_call_c($1, NULL, locloc(@$));} +/* | function_name '(' eol_list il_param_list ')' */ +/* For the above syntax, we no longer have two ways of interpreting the + * same syntax. The above is always a function call! + * However, some of the functions that we may be calling + * may have the same name as an IL operator. This means that + * flex will be parsing them and handing them over to bison as + * IL operator tokens, and not as function name tokens. + * (when parsing ST, flex no longer recognizes IL operators, + * so will always return the correct function name, unless that + * name also coincides with an operator used in ST -> XOR, OR, MOD, AND, NOT) + * + * We must therefore interpret the IL operators as function names! + */ +| function_name_no_clashes '(' eol_list il_param_list ')' + {$$ = new il_formal_funct_call_c($1, $4, locloc(@$));} +| function_name_simpleop_clashes '(' eol_list il_param_list ')' + {$$ = new il_formal_funct_call_c($1, $4, locloc(@$));} +/* The following line should read: + * + * | function_name_expression_clashes '(' eol_list il_param_list ')' + * + * but the function_name_expression_clashes had to be first reduced to + * an intermediary symbol in order to remove a reduce/reduce conflict. + * In essence, the syntax requires more than one look ahead token + * in order to be parsed. We resolve this by reducing a collection of + * symbols into a temporary symbol (il_expr_operator_clash_eol_list), that + * will later be replaced by the correct symbol. The correct symbol will + * now be determined by a single look ahead token, as all the common + * symbols have been reduced to the temporary symbol + * il_expr_operator_clash_eol_list ! + * + * Unfortunately, this work around results in the wrong symbol + * being created for the abstract syntax tree. + * We need to figure out which symbol was created, destroy it, + * and create the correct symbol for our case. + * This is a lot of work, so I put it in a function + * at the end of this file... il_operator_c_2_identifier_c() + */ +| il_expr_operator_clash_eol_list il_param_list ')' + {$$ = new il_formal_funct_call_c(il_operator_c_2_identifier_c($1), $2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| function_name_no_clashes '(' eol_list error ')' + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid parameter list defined in IL formal function call."); yyerrok;} +| function_name_simpleop_clashes '(' eol_list error ')' + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid parameter list defined in IL formal function call."); yyerrok;} +| il_expr_operator_clash_eol_list error ')' + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid parameter list defined in IL formal function call."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_expr_operator_clash_eol_list: + il_expr_operator_clash '(' eol_list + {$$ = $1;} +/* ERROR_CHECK_BEGIN */ +| il_expr_operator_clash '(' error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "EOL missing after '(' in IL instruction."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_operand: + variable +| enumerated_value +| constant +; + + +il_operand_list: + il_operand + {$$ = new il_operand_list_c(locloc(@$)); $$->add_element($1);} +| il_operand_list2 +; + + +/* List with 2 or more il_operands */ +il_operand_list2: + il_operand ',' il_operand + {$$ = new il_operand_list_c(locloc(@$)); $$->add_element($1); $$->add_element($3);} +| il_operand_list2 ',' il_operand + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| il_operand_list2 il_operand + {$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in IL operand list."); yynerrs++;} +| il_operand ',' error + {$$ = new il_operand_list_c(locloc(@$)); + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no operand defined in IL operand list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid operand name in IL operand list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +simple_instr_list: + il_simple_instruction + {$$ = new simple_instr_list_c(locloc(@$)); $$->add_element($1);} +| simple_instr_list il_simple_instruction + {$$ = $1; $$->add_element($2);} +; + + +il_simple_instruction: + il_simple_operation eol_list +| il_expression eol_list +| il_formal_funct_call eol_list +/* ERROR_CHECK_BEGIN */ +| il_expression error + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing after expression IL instruction."); yyerrok;} +| il_formal_funct_call error + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing after formal function call IL instruction."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* NOTE: the correct definition of il_param_list is + * il_param_list ::= {il_param_instruction} il_param_last_instruction + * + * where {...} denotes zero or many il_param_instruction's. + * + * We could do this by defining the following: + * il_param_list: il_param_instruction_list il_param_last_instruction; + * il_param_instruction_list : ** empty ** | il_param_instruction_list il_param_instruction; + * + * Unfortunately, the above leads to reduce/reduce conflicts. + * The chosen alternative (as follows) does not have any conflicts! + * il_param_list: il_param_last_instruction | il_param_instruction_list il_param_last_instruction; + * il_param_instruction_list : il_param_instruction_list | il_param_instruction_list il_param_instruction; + */ +il_param_list: + il_param_instruction_list il_param_last_instruction + {$$ = $1; $$->add_element($2);} +| il_param_last_instruction + {$$ = new il_param_list_c(locloc(@$)); $$->add_element($1);} +/* ERROR_CHECK_BEGIN */ +| il_param_instruction_list error + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid parameter assignment in parameter assignment list."); yyerrok;} +| il_param_last_instruction il_param_last_instruction + {$$ = 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++;} +| il_param_instruction_list il_param_last_instruction il_param_last_instruction + {$$ = $1; print_err_msg(locl(@2), locf(@3), "',' missing at the end of parameter assignment in parameter assignment list."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +/* Helper symbol for il_param_list */ +il_param_instruction_list: + il_param_instruction + {$$ = new il_param_list_c(locloc(@$)); $$->add_element($1);} +| il_param_instruction_list il_param_instruction + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| il_param_last_instruction il_param_instruction + {$$ = 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++;} +| il_param_instruction_list il_param_last_instruction il_param_instruction + {$$ = $1; print_err_msg(locl(@2), locf(@3), "',' missing at the end of parameter assignment in parameter assignment list."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +il_param_instruction: + il_param_assignment ',' eol_list +| il_param_out_assignment ',' eol_list +/* ERROR_CHECK_BEGIN */ +| il_param_assignment ',' error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "EOL missing at the end of parameter assignment in parameter assignment list."); yyerrok;} +| il_param_out_assignment ',' error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "EOL missing at the end of parameter out assignment in parameter assignment list."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_param_last_instruction: + il_param_assignment eol_list +| il_param_out_assignment eol_list +/* ERROR_CHECK_BEGIN */ +| il_param_assignment error + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing at the end of last parameter assignment in parameter assignment list."); yyerrok;} +| il_param_out_assignment error + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing at the end of last parameter out assignment in parameter assignment list."); yyerrok;} +/* ERROR_CHECK_END */ + +; + + +il_param_assignment: + il_assign_operator il_operand + {$$ = new il_param_assignment_c($1, $2, NULL, locloc(@$));} +| il_assign_operator '(' eol_list simple_instr_list ')' + {$$ = new il_param_assignment_c($1, NULL, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| error il_operand + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid operator in parameter assignment."); yyerrok;} +| error '(' eol_list simple_instr_list ')' + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid operator in parameter assignment."); yyerrok;} +| il_assign_operator error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no operand defined in parameter assignment.");} + else {print_err_msg(locf(@2), locl(@2), "invalid operand in parameter assignment."); yyclearin;} + yyerrok; + } +| il_assign_operator '(' eol_list ')' + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no instruction list defined in parameter assignment."); yynerrs++;} +| il_assign_operator '(' eol_list error ')' + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid instruction list defined in parameter assignment."); yyerrok;} +| il_assign_operator '(' eol_list simple_instr_list error + {$$ = NULL; print_err_msg(locl(@4), locf(@5), "')' missing at the end of instruction list defined in parameter assignment."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_param_out_assignment: + il_assign_out_operator variable + {$$ = new il_param_out_assignment_c($1, $2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| il_assign_out_operator error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no variable defined in IL operand list.");} + else {print_err_msg(locf(@2), locl(@2), "invalid variable in IL operand list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + +/*******************/ +/* B 2.2 Operators */ +/*******************/ +sendto_identifier: sendto_identifier_token {$$ = new identifier_c($1, locloc(@$));}; + + +/* NOTE: + * The spec includes the operator 'EQ ' + * Note that EQ is followed by a space. + * I am considering this a typo, and defining the operator + * as 'EQ' + * (Mario) + */ +LD_operator: LD {$$ = new LD_operator_c(locloc(@$));}; +LDN_operator: LDN {$$ = new LDN_operator_c(locloc(@$));}; +ST_operator: ST {$$ = new ST_operator_c(locloc(@$));}; +STN_operator: STN {$$ = new STN_operator_c(locloc(@$));}; +NOT_operator: NOT {$$ = new NOT_operator_c(locloc(@$));}; +S_operator: S {$$ = new S_operator_c(locloc(@$));}; +R_operator: R {$$ = new R_operator_c(locloc(@$));}; +S1_operator: S1 {$$ = new S1_operator_c(locloc(@$));}; +R1_operator: R1 {$$ = new R1_operator_c(locloc(@$));}; +CLK_operator: CLK {$$ = new CLK_operator_c(locloc(@$));}; +CU_operator: CU {$$ = new CU_operator_c(locloc(@$));}; +CD_operator: CD {$$ = new CD_operator_c(locloc(@$));}; +PV_operator: PV {$$ = new PV_operator_c(locloc(@$));}; +IN_operator: IN {$$ = new IN_operator_c(locloc(@$));}; +PT_operator: PT {$$ = new PT_operator_c(locloc(@$));}; +AND_operator: AND {$$ = new AND_operator_c(locloc(@$));}; +AND2_operator: AND2 {$$ = new AND_operator_c(locloc(@$));}; /* '&' in the source code! */ +OR_operator: OR {$$ = new OR_operator_c(locloc(@$));}; +XOR_operator: XOR {$$ = new XOR_operator_c(locloc(@$));}; +ANDN_operator: ANDN {$$ = new ANDN_operator_c(locloc(@$));}; +ANDN2_operator: ANDN2 {$$ = new ANDN_operator_c(locloc(@$));}; /* '&N' in the source code! */ +ORN_operator: ORN {$$ = new ORN_operator_c(locloc(@$));}; +XORN_operator: XORN {$$ = new XORN_operator_c(locloc(@$));}; +ADD_operator: ADD {$$ = new ADD_operator_c(locloc(@$));}; +SUB_operator: SUB {$$ = new SUB_operator_c(locloc(@$));}; +MUL_operator: MUL {$$ = new MUL_operator_c(locloc(@$));}; +DIV_operator: DIV {$$ = new DIV_operator_c(locloc(@$));}; +MOD_operator: MOD {$$ = new MOD_operator_c(locloc(@$));}; +GT_operator: GT {$$ = new GT_operator_c(locloc(@$));}; +GE_operator: GE {$$ = new GE_operator_c(locloc(@$));}; +EQ_operator: EQ {$$ = new EQ_operator_c(locloc(@$));}; +LT_operator: LT {$$ = new LT_operator_c(locloc(@$));}; +LE_operator: LE {$$ = new LE_operator_c(locloc(@$));}; +NE_operator: NE {$$ = new NE_operator_c(locloc(@$));}; +CAL_operator: CAL {$$ = new CAL_operator_c(locloc(@$));}; +CALC_operator: CALC {$$ = new CALC_operator_c(locloc(@$));}; +CALCN_operator: CALCN {$$ = new CALCN_operator_c(locloc(@$));}; +RET_operator: RET {$$ = new RET_operator_c(locloc(@$));}; +RETC_operator: RETC {$$ = new RETC_operator_c(locloc(@$));}; +RETCN_operator: RETCN {$$ = new RETCN_operator_c(locloc(@$));}; +JMP_operator: JMP {$$ = new JMP_operator_c(locloc(@$));}; +JMPC_operator: JMPC {$$ = new JMPC_operator_c(locloc(@$));}; +JMPCN_operator: JMPCN {$$ = new JMPCN_operator_c(locloc(@$));}; + + +il_simple_operator: + il_simple_operator_clash +| il_simple_operator_noclash +; + + +il_simple_operator_noclash: + LD_operator +| LDN_operator +| ST_operator +| STN_operator +| S_operator +| R_operator +| S1_operator +| R1_operator +| CLK_operator +| CU_operator +| CD_operator +| PV_operator +| IN_operator +| PT_operator +| il_expr_operator_noclash +; + + +il_simple_operator_clash: + il_simple_operator_clash1 +| il_simple_operator_clash2 +; + +il_simple_operator_clash1: + NOT_operator +; + +il_simple_operator_clash2: + il_expr_operator_clash +; + + +/* +il_expr_operator: + il_expr_operator_noclash +| il_expr_operator_clash +; +*/ + +il_expr_operator_clash: + AND_operator +| OR_operator +| XOR_operator +| ADD_operator +| SUB_operator +| MUL_operator +| DIV_operator +| MOD_operator +| GT_operator +| GE_operator +| EQ_operator +| LT_operator +| LE_operator +| NE_operator +; + + +il_expr_operator_noclash: + ANDN_operator +| ANDN2_operator /* string '&N' in source code! */ +| AND2_operator /* string '&' in source code! */ +| ORN_operator +| XORN_operator +; + + + + +il_assign_operator: +/* variable_name ASSIGN */ + any_identifier ASSIGN + {$$ = new il_assign_operator_c($1, locloc(@$));} +| en_identifier ASSIGN + {$$ = new il_assign_operator_c($1, locloc(@$));} +| S1_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +| R1_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +| CLK_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +| CU_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +| CD_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +| PV_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +| IN_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +| PT_operator ASSIGN + {$$ = new il_assign_operator_c(il_operator_c_2_identifier_c($1), locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| error ASSIGN + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid parameter defined in parameter assignment."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_assign_out_operator: +/* variable_name SENDTO */ +/* any_identifier SENDTO */ + sendto_identifier SENDTO + {$$ = new il_assign_out_operator_c(NULL, $1, locloc(@$));} +/* The following is not required, as the sendto_identifier_token returned by flex will + * also include the 'ENO' identifier. + * The resulting abstract syntax tree is identical with or without this following rule, + * as both the eno_identifier and the sendto_identifier are stored as + * an identifier_c !! + * + * To understand why we must even explicitly consider the use of ENO here, + * please read the comment above the definition of 'variable' in section B1.4 for details. + */ +/* +| eno_identifier SENDTO + {$$ = new il_assign_out_operator_c(NULL, $1, locloc(@$));} +*/ +/*| NOT variable_name SENDTO */ +| NOT sendto_identifier SENDTO + {$$ = new il_assign_out_operator_c(new not_paramassign_c(locloc(@1)), $2, locloc(@$));} +/* The following is not required, as the sendto_identifier_token returned by flex will + * also include the 'ENO' identifier. + * The resulting abstract syntax tree is identical with or without this following rule, + * as both the eno_identifier and the sendto_identifier are stored as + * an identifier_c !! + * + * To understand why we must even explicitly consider the use of ENO here, + * please read the comment above the definition of 'variable' in section B1.4 for details. + * + * NOTE: Removing the following rule also removes a shift/reduce conflict from the parser. + * This conflict is not really an error/ambiguity in the syntax, but rather + * due to the fact that more than a single look-ahead token would be required + * to correctly parse the syntax, something that bison does not support. + * + * The shift/reduce conflict arises because bison does not know whether + * to parse the 'NOT ENO' in the following code + * LD 1 + * funct_name ( + * NOT ENO => bool_var, + * EN := TRUE + * ) + * as either a il_param_assignment (wrong!) or an il_param_out_assignment.(correct). + * The '=>' delimiter (known as SEND_TO in this iec.y file) is a dead giveaway that + * it should be parsed as an il_param_out_assignment, but still, bison gets confused! + * Bison considers the possibility of reducing the 'NOT ENO' as an NOT_operator with + * the 'ENO' operand + * (NOT_operator -> il_simple_operator -> il_simple_operation -> il_simple_instruction -> + * -> simple_instr_list -> il_param_assignment) + * instead of reducing it to an il_param_out_operator. + * ( il_param_out_operator -> il_param_out_assignment) + * + * Note that the shift/reduce conflict only manifests itself in the il_formal_funct_call, + * where both the il_param_out_assignment and il_param_assignment are used! + * + * il_param_out_assignment --+--> il_param_instruction -> il_param_instruction_list --+ + * | | + * il_param_assignment --+ | + * | + * il_formal_funct_call <- il_param_list <-+ + * + */ +/* +| NOT eno_identifier SENDTO + {$$ = new il_assign_out_operator_c(new not_paramassign_c(locloc(@1)), $2, locloc(@$));} +*/ +/* ERROR_CHECK_BEGIN */ +| error SENDTO + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid parameter defined in parameter out assignment."); yyerrok;} +| NOT SENDTO + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no parameter defined in parameter out assignment."); yynerrs++;} +| NOT error SENDTO + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid parameter defined in parameter out assignment."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +il_call_operator: + CAL_operator +| CALC_operator +| CALCN_operator +; + + +il_return_operator: + RET_operator +| RETC_operator +| RETCN_operator +; + + +il_jump_operator: + JMP_operator +| JMPC_operator +| JMPCN_operator +; + + +/***********************/ +/* B 3.1 - Expressions */ +/***********************/ +expression: + xor_expression +| expression OR xor_expression + {$$ = new or_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| expression OR error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'OR' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'OR' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +xor_expression: + and_expression +| xor_expression XOR and_expression + {$$ = new xor_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| xor_expression XOR error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'XOR' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'XOR' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +and_expression: + comparison +| and_expression '&' comparison + {$$ = new and_expression_c($1, $3, locloc(@$));} +| and_expression AND comparison + {$$ = new and_expression_c($1, $3, locloc(@$));} +/* NOTE: The lexical parser never returns the token '&'. + * The '&' string is interpreted by the lexcial parser as the token + * AND2! + * This means that the first rule with '&' is actually not required, + * but we leave it in nevertheless just in case we later decide + * to remove the AND2 token... + */ +| and_expression AND2 comparison + {$$ = new and_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| and_expression '&' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '&' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '&' in ST expression."); yyclearin;} + yyerrok; + } +| and_expression AND error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'AND' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'AND' in ST expression."); yyclearin;} + yyerrok; + } +| and_expression AND2 error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '&' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '&' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +comparison: + equ_expression +| comparison '=' equ_expression + {$$ = new equ_expression_c($1, $3, locloc(@$));} +| comparison OPER_NE equ_expression + {$$ = new notequ_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| comparison '=' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '=' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '=' in ST expression."); yyclearin;} + yyerrok; + } +| comparison OPER_NE error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '<>' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '<>' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +equ_expression: + add_expression +| equ_expression '<' add_expression + {$$ = new lt_expression_c($1, $3, locloc(@$));} +| equ_expression '>' add_expression + {$$ = new gt_expression_c($1, $3, locloc(@$));} +| equ_expression OPER_LE add_expression + {$$ = new le_expression_c($1, $3, locloc(@$));} +| equ_expression OPER_GE add_expression + {$$ = new ge_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| equ_expression '<' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '<' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '<' in ST expression."); yyclearin;} + yyerrok; + } +| equ_expression '>' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '>' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '>' in ST expression."); yyclearin;} + yyerrok; + } +| equ_expression OPER_LE error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '<=' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '<=' in ST expression."); yyclearin;} + yyerrok; + } +| equ_expression OPER_GE error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '>=' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '>=' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* Not required... +comparison_operator: '<' | '>' | '>=' '<=' +*/ + +add_expression: + term +| add_expression '+' term + {$$ = new add_expression_c($1, $3, locloc(@$));} +| add_expression '-' term + {$$ = new sub_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| add_expression '+' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '+' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '+' in ST expression."); yyclearin;} + yyerrok; + } +| add_expression '-' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '-' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '-' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* Not required... +add_operator: '+' | '-' +*/ + +term: + power_expression +| term '*' power_expression + {$$ = new mul_expression_c($1, $3, locloc(@$));} +| term '/' power_expression + {$$ = new div_expression_c($1, $3, locloc(@$));} +| term MOD power_expression + {$$ = new mod_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| term '*' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '*' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '*' in ST expression."); yyclearin;} + yyerrok; + } +| term '/' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '/' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '/' in ST expression."); yyclearin;} + yyerrok; + } +| term MOD error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after 'MOD' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after 'MOD' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* Not required... +multiply_operator: '*' | '/' | 'MOD' +*/ + +power_expression: + unary_expression +| power_expression OPER_EXP unary_expression + {$$ = new power_expression_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| power_expression OPER_EXP error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after '**' in ST expression.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after '**' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +unary_expression: + non_negative_primary_expression +| '-' non_negative_primary_expression + {$$ = new neg_expression_c($2, locloc(@$));} +| NOT primary_expression + {$$ = new not_expression_c($2, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| '-' error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no expression defined after '-' in ST expression.");} + else {print_err_msg(locf(@2), locl(@2), "invalid expression after '-' in ST expression."); yyclearin;} + yyerrok; + } +| NOT error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no expression defined after 'NOT' in ST expression.");} + else {print_err_msg(locf(@2), locl(@2), "invalid expression after 'NOT' in ST expression."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* Not required... +unary_operator: '-' | 'NOT' +*/ + + +/* NOTE: using constant as a possible symbol for primary_expression + * leads to a reduce/reduce conflict. + * + * The text '-9' may be parsed as either a + * expression<-primary_expression<-constant<-signed_integer + * (i.e. the constant 9 negative) + * OR + * expression<-unary_expression<-constant<-integer + * (i.e. the constant 9, preceded by a unary negation) + * + * To remove the conflict, we only allow constants without + * a preceding '-' to be used in primary_expression + * (i.e. as a parameter to the unary negation operator) + */ +/* NOTE: We use enumerated_value_without_identifier instead of enumerated_value + * in order to remove a reduce/reduce conflict between reducing an + * identifier to a variable or an enumerated_value. + * + * This change follows the IEC specification. The specification seems to + * imply (by introducing syntax that allows to unambiguosly reference an + * enumerated value - enum_type#enum_value) that in case the same identifier is used + * for a variable and an enumerated value, then the variable shall be + * considered. + */ +non_negative_primary_expression: + non_negative_constant +//| enumerated_value_without_identifier +| enumerated_value +| variable +| '(' expression ')' + {$$ = $2;} +| function_invocation +/* ERROR_CHECK_BEGIN */ +| '(' expression error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of expression in ST expression."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +primary_expression: + constant +//| enumerated_value_without_identifier +| enumerated_value +| variable +| '(' expression ')' + {$$ = $2;} +| function_invocation +/* ERROR_CHECK_BEGIN */ +| '(' expression error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing at the end of expression in ST expression."); yyerrok;} +/* ERROR_CHECK_END */ +; + + + +/* intermediate helper symbol for primary_expression */ +/* NOTE: function_name includes the standard function name 'NOT' ! + * This introduces a reduce/reduce conflict, as NOT(var) + * may be parsed as either a function_invocation, or a + * unary_expression. + * + * I (Mario) have opted to remove the possible reduction + * to function invocation, which means replacing the rule + * function_name '(' param_assignment_list ')' + * with + * function_name_no_NOT_clashes '(' param_assignment_list ')' + * + * Notice how the new rule does not include the situation where + * the function NOT is called with more than one parameter, which + * the original rule does include! Callinf the NOT function with more + * than one argument is probably a semantic error anyway, so it + * doesn't make much sense to take it into account. + * + * Nevertheless, if we were to to it entirely correctly, + * leaving the semantic checks for the next compiler stage, + * this syntax parser would need to include such a possibility. + * + * We will leave this out for now. No need to complicate the syntax + * more than the specification does by contradicting itself, and + * letting names clash! + */ +function_invocation: +/* function_name '(' [param_assignment_list] ')' */ + function_name_no_NOT_clashes '(' param_assignment_formal_list ')' + {$$ = new function_invocation_c($1, $3, NULL, locloc(@$));} +| function_name_no_NOT_clashes '(' param_assignment_nonformal_list ')' + {$$ = new function_invocation_c($1, NULL, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| function_name_no_NOT_clashes param_assignment_formal_list ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function name in ST expression."); yynerrs++;} +| function_name_no_NOT_clashes '(' ')' + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no parameter defined in function invocation of ST expression."); yynerrs++;} +| function_name_no_NOT_clashes '(' error ')' + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid parameter(s) defined in function invocation of ST expression."); yyerrok;} +| function_name_no_NOT_clashes '(' param_assignment_formal_list error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of function invocation in ST expression."); yyerrok;} +| function_name_no_NOT_clashes '(' param_assignment_nonformal_list error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing at the end of function invocation in ST expression."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/********************/ +/* B 3.2 Statements */ +/********************/ +statement_list: + statement ';' + {$$ = new statement_list_c(locloc(@$)); $$->add_element($1);} +| any_pragma + {$$ = new statement_list_c(locloc(@$)); $$->add_element($1);} +| statement_list statement ';' + {$$ = $1; $$->add_element($2);} +| statement_list any_pragma + {$$ = $1; $$->add_element($2);} +/* ERROR_CHECK_BEGIN */ +| statement error + {$$ = new statement_list_c(locloc(@$)); print_err_msg(locl(@1), locf(@2), "';' missing at the end of statement in ST statement."); yyerrok;} +| statement_list statement error + {$$ = $1; print_err_msg(locl(@2), locf(@3), "';' missing at the end of statement in ST statement."); yyerrok;} +| statement_list error ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "invalid statement in ST statement."); yyerrok;} +| statement_list ';' + {$$ = $1; print_err_msg(locf(@2), locl(@2), "unexpected ';' after statement in ST statement."); yynerrs++;} +/* ERROR_CHECK_END */ +; + + +statement: + assignment_statement +| subprogram_control_statement +| selection_statement +| iteration_statement +; + + +/*********************************/ +/* B 3.2.1 Assignment Statements */ +/*********************************/ +assignment_statement: + variable ASSIGN expression + {$$ = new assignment_statement_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| error ASSIGN expression + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid variable before ':=' in ST assignment statement."); yyerrok;} +| variable ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined after ':=' in ST assignment statement.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression after ':=' in ST assignment statement."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + + + +/*****************************************/ +/* B 3.2.2 Subprogram Control Statements */ +/*****************************************/ +subprogram_control_statement: + fb_invocation +| return_statement +; + +return_statement: + RETURN {$$ = new return_statement_c(locloc(@$));} +; + + + +fb_invocation: + prev_declared_fb_name '(' ')' + {$$ = new fb_invocation_c($1, NULL, NULL, locloc(@$)); } +| prev_declared_fb_name '(' param_assignment_formal_list ')' + {$$ = new fb_invocation_c($1, $3, NULL, locloc(@$));} +| prev_declared_fb_name '(' param_assignment_nonformal_list ')' + {$$ = new fb_invocation_c($1, NULL, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| prev_declared_fb_name ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function block name in ST statement."); yynerrs++;} +| prev_declared_fb_name param_assignment_formal_list ')' + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function block name in ST statement."); yynerrs++;} +| prev_declared_fb_name '(' error ')' + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid parameter list in function block invocation in ST statement."); yyerrok;} +| prev_declared_fb_name '(' error + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "')' missing after parameter list of function block invocation in ST statement."); yyerrok;} +| prev_declared_fb_name '(' param_assignment_formal_list error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing after parameter list of function block invocation in ST statement."); yyerrok;} +| prev_declared_fb_name '(' param_assignment_nonformal_list error + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "')' missing after parameter list of function block invocation in ST statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* helper symbol for + * - fb_invocation + * - function_invocation + */ +param_assignment_formal_list: + param_assignment_formal + {$$ = new param_assignment_list_c(locloc(@$)); $$->add_element($1);} +| param_assignment_formal_list ',' param_assignment_formal + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| param_assignment_formal_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no parameter assignment defined in ST parameter assignment list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid parameter assignment in ST parameter assignment list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + +/* helper symbol for + * - fb_invocation + * - function_invocation + */ +param_assignment_nonformal_list: + param_assignment_nonformal + {$$ = new param_assignment_list_c(locloc(@$)); $$->add_element($1);} +| param_assignment_nonformal_list ',' param_assignment_nonformal + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| param_assignment_nonformal_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no parameter assignment defined in ST parameter assignment list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid parameter assignment in ST parameter assignment list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +/* NOTE: According to the IEC 61131-3 standard, there are two possible + * syntaxes for calling function blocks within ST. + * The formal method has the form: + * fb ( invar := x, inoutvar := var1, outvar => var2); + * The non-formal method has the form: + * fb (x, var1, var2); + * In the text of IEC 61131-3 (where the semantics are defined), + * it is obvious that mixing the two syntaxes is considered incorrect. + * The following should therefore be incorrect: + * fb ( invar := x, var1, var2); + * However, according to the syntax definition, as defined in IEC 61131-3, + * mixing the formal and non-formal methods of invocation is allowed. + * We have two alternatives: + * (a) implement the syntax here in iec.y according to the standard, + * and leave it to the semantic analyser stage to find this error + * (b) or implement the syntax in iec.y correctly, not allowing + * the mixing of formal and non-formal invocation syntaxes. + * Considering that this is a syntax issue, and not semantic issue, + * I (Mario) have decided to go with alternative (a). + * In other words, in iec.y we do not follow the syntax as defined in + * Annex B of the IEC 61131-3 standard, but rather implement + * the syntax also taking into account the textual part of the standard too. + */ +/* +param_assignment: + variable_name ASSIGN expression +*/ +param_assignment_nonformal: + expression +; + + +param_assignment_formal: + any_identifier ASSIGN expression + {$$ = new input_variable_param_assignment_c($1, $3, locloc(@$));} +| en_identifier ASSIGN expression + {$$ = new input_variable_param_assignment_c($1, $3, locloc(@$));} +/*| variable_name SENDTO variable */ +/*| any_identifier SENDTO variable */ +| sendto_identifier SENDTO variable + {$$ = new output_variable_param_assignment_c(NULL, $1, $3, locloc(@$));} +/* The following is not required, as the sendto_identifier_token returned by flex will + * also include the 'ENO' identifier. + * The resulting abstract syntax tree is identical with or without this following rule, + * as both the eno_identifier and the sendto_identifier are stored as + * an identifier_c !! + * + * To understand why we must even explicitly consider the use of ENO here, + * please read the comment above the definition of 'variable' in section B1.4 for details. + */ +/* +| eno_identifier SENDTO variable + {$$ = new output_variable_param_assignment_c(NULL, $1, $3, locloc(@$));} +*/ +/*| NOT variable_name SENDTO variable */ +/*| NOT any_identifier SENDTO variable*/ +| NOT sendto_identifier SENDTO variable + {$$ = new output_variable_param_assignment_c(new not_paramassign_c(locloc(@$)), $2, $4, locloc(@$));} +/* The following is not required, as the sendto_identifier_token returned by flex will + * also include the 'ENO' identifier. + * The resulting abstract syntax tree is identical with or without this following rule, + * as both the eno_identifier and the sendto_identifier are stored as + * an identifier_c !! + * + * To understand why we must even explicitly consider the use of ENO here, + * please read the comment above the definition of 'variable' in section B1.4 for details. + */ +/* +| NOT eno_identifier SENDTO variable + {$$ = new output_variable_param_assignment_c(new not_paramassign_c(locloc(@$)), $2, $4, locloc(@$));} +*/ +/* ERROR_CHECK_BEGIN */ +| any_identifier ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter assignment.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter assignment."); yyclearin;} + yyerrok; + } +| en_identifier ASSIGN error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter assignment.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter assignment."); yyclearin;} + yyerrok; + } +| sendto_identifier SENDTO error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter out assignment.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter out assignment."); yyclearin;} + yyerrok; + } +/* +| eno_identifier SENDTO error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no expression defined in ST formal parameter out assignment.");} + else {print_err_msg(locf(@3), locl(@3), "invalid expression in ST formal parameter out assignment."); yyclearin;} + yyerrok; + } +*/ +| NOT SENDTO variable + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no parameter name defined in ST formal parameter out negated assignment."); yynerrs++;} +| NOT error SENDTO variable + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid parameter name defined in ST formal parameter out negated assignment."); yyerrok;} +| NOT sendto_identifier SENDTO error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no expression defined in ST formal parameter out negated assignment.");} + else {print_err_msg(locf(@4), locl(@4), "invalid expression in ST formal parameter out negated assignment."); yyclearin;} + yyerrok; + } +/* +| NOT eno_identifier SENDTO error + {$$ = NULL; + if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no expression defined in ST formal parameter out negated assignment.");} + else {print_err_msg(locf(@4), locl(@4), "invalid expression in ST formal parameter out negated assignment."); yyclearin;} + yyerrok; + } +*/ +/* ERROR_CHECK_END */ +; + + + + + +/********************************/ +/* B 3.2.3 Selection Statements */ +/********************************/ +selection_statement: + if_statement +| case_statement +; + + +if_statement: + IF expression THEN statement_list elseif_statement_list END_IF + {$$ = new if_statement_c($2, $4, $5, NULL, locloc(@$));} +| IF expression THEN statement_list elseif_statement_list ELSE statement_list END_IF + {$$ = new if_statement_c($2, $4, $5, $7, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| IF THEN statement_list elseif_statement_list END_IF + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'IF' statement."); yynerrs++;} +| IF THEN statement_list elseif_statement_list ELSE statement_list END_IF + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'IF' statement."); yynerrs++;} +| IF error THEN statement_list elseif_statement_list END_IF + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'IF' statement."); yyerrok;} +| IF error THEN statement_list elseif_statement_list ELSE statement_list END_IF + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'IF' statement."); yyerrok;} +| IF expression error statement_list elseif_statement_list END_IF + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'THEN' after test expression in ST 'IF' statement."); yyerrok;} +| IF expression error statement_list elseif_statement_list ELSE statement_list END_IF + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'THEN' after test expression in ST 'IF' statement."); yyerrok;} +| IF expression THEN elseif_statement_list END_IF + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no statement defined after 'THEN' in ST 'IF' statement."); yynerrs++;} +| IF expression THEN elseif_statement_list ELSE statement_list END_IF + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no statement defined after 'THEN' in ST 'IF' statement."); yynerrs++;} +| IF expression THEN statement_list elseif_statement_list ELSE END_IF + {$$ = NULL; print_err_msg(locl(@6), locf(@7), "no statement defined after 'ELSE' in ST 'IF' statement."); yynerrs++;} +| IF expression THEN statement_list elseif_statement_list ELSE error END_IF + {$$ = NULL; print_err_msg(locf(@7), locl(@7), "invalid statement defined after 'ELSE' in ST 'IF' statement."); yynerrs++; yyerrok;} +| IF expression error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed 'IF' statement in ST."); yyerrok;} +| IF expression THEN statement_list elseif_statement_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'IF' statement in ST."); yynerrs++;} +| IF expression THEN statement_list elseif_statement_list ELSE statement_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'IF' statement in ST."); yynerrs++;} +| IF error END_IF + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'IF' statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* helper symbol for if_statement */ +elseif_statement_list: + /* empty */ + {$$ = new elseif_statement_list_c(locloc(@$));} +| elseif_statement_list elseif_statement + {$$ = $1; $$->add_element($2);} +; + +/* helper symbol for elseif_statement_list */ +elseif_statement: + ELSIF expression THEN statement_list + {$$ = new elseif_statement_c($2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| ELSIF THEN statement_list + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined for 'ELSEIF' statement in ST 'IF' statement."); yynerrs++;} +| ELSIF error THEN statement_list + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for 'ELSEIF' statement in ST 'IF' statement."); yyerrok;} +| ELSIF expression error statement_list + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'THEN' after test expression in 'ELSEIF' statement of ST 'IF' statement."); yyerrok;} +| ELSIF expression THEN error + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid statement list in 'ELSEIF' statement of ST 'IF' statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +case_statement: + CASE expression OF case_element_list END_CASE + {$$ = new case_statement_c($2, $4, NULL, locloc(@$));} +| CASE expression OF case_element_list ELSE statement_list END_CASE + {$$ = new case_statement_c($2, $4, $6, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| CASE OF case_element_list END_CASE + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'CASE' statement."); yynerrs++;} +| CASE OF case_element_list ELSE statement_list END_CASE + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'CASE' statement."); yynerrs++;} +| CASE error OF case_element_list END_CASE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'CASE' statement."); yyerrok;} +| CASE error OF case_element_list ELSE statement_list END_CASE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'CASE' statement."); yyerrok;} +| CASE expression error case_element_list END_CASE + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'OF' after test expression in ST 'CASE' statement."); yyerrok;} +| CASE expression error case_element_list ELSE statement_list END_CASE + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'OF' after test expression in ST 'CASE' statement."); yyerrok;} +| CASE expression OF END_CASE + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no case element(s) defined after 'OF' in ST 'CASE' statement."); yynerrs++;} +| CASE expression OF ELSE statement_list END_CASE + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no case element(s) defined after 'OF' in ST 'CASE' statement."); yynerrs++;} +| CASE expression OF error END_CASE + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid case element(s) defined after 'OF' in ST 'CASE' statement."); yyerrok;} +| CASE expression OF error ELSE statement_list END_CASE + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid case element(s) defined after 'OF' in ST 'CASE' statement."); yyerrok;} +| CASE expression OF case_element_list ELSE END_CASE + {$$ = NULL; print_err_msg(locl(@5), locf(@6), "no statement defined after 'ELSE' in ST 'CASE' statement."); yynerrs++;} +| CASE expression OF case_element_list ELSE error END_CASE + {$$ = NULL; print_err_msg(locf(@6), locl(@6), "invalid statement defined after 'ELSE' in ST 'CASE' statement."); yyerrok;} +| CASE expression error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed 'CASE' statement in ST."); yyerrok;} +| CASE expression OF case_element_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'CASE' statement in ST."); yynerrs++;} +| CASE expression OF case_element_list ELSE statement_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@3), "unclosed 'CASE' statement in ST."); yynerrs++;} +| CASE error END_CASE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'CASE' statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +/* helper symbol for case_statement */ +case_element_list: + case_element + {$$ = new case_element_list_c(locloc(@$)); $$->add_element($1);} +| case_element_list case_element + {$$ = $1; $$->add_element($2);} +; + + +case_element: + case_list ':' statement_list + {$$ = new case_element_c($1, $3, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| case_list statement_list + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after case list in ST 'CASE' statement."); yynerrs++;} +| case_list ':' error + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid statement in case element of ST 'CASE' statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +case_list: + case_list_element + {$$ = new case_list_c(locloc(@$)); $$->add_element($1);} +| case_list ',' case_list_element + {$$ = $1; $$->add_element($3);} +/* ERROR_CHECK_BEGIN */ +| case_list ',' error + {$$ = $1; + if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no case defined in case list of ST parameter assignment list.");} + else {print_err_msg(locf(@3), locl(@3), "invalid case in case list of ST parameter assignment list."); yyclearin;} + yyerrok; + } +/* ERROR_CHECK_END */ +; + + +case_list_element: + signed_integer +| subrange +| enumerated_value +; + + + + + +/********************************/ +/* B 3.2.4 Iteration Statements */ +/********************************/ +iteration_statement: + for_statement +| while_statement +| repeat_statement +| exit_statement +; + + +for_statement: + FOR control_variable ASSIGN expression TO expression BY expression DO statement_list END_FOR + {$$ = new for_statement_c($2, $4, $6, $8, $10, locloc(@$));} +| FOR control_variable ASSIGN expression TO expression DO statement_list END_FOR + {$$ = new for_statement_c($2, $4, $6, NULL, $8, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| FOR ASSIGN expression TO expression BY expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no control variable defined in ST 'FOR' statement."); yynerrs++;} +| FOR ASSIGN expression TO expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no control variable defined in ST 'FOR' statement."); yynerrs++;} +| FOR error ASSIGN expression TO expression BY expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid control variable defined for ST 'FOR' statement."); yyerrok;} +| FOR error ASSIGN expression TO expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid control variable defined for ST 'FOR' statement."); yyerrok;} +| FOR control_variable expression TO expression BY expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':=' missing between control variable and start expression in ST 'FOR' statement."); yynerrs++;} +| FOR control_variable expression TO expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':=' missing between control variable and start expression in ST 'FOR' statement."); yynerrs++;} +| FOR control_variable error expression TO expression BY expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting ':=' between control variable and start expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable error expression TO expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting ':=' between control variable and start expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN TO expression BY expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no start expression defined in ST 'FOR' statement."); yynerrs++;} +| FOR control_variable ASSIGN TO expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no start expression defined in ST 'FOR' statement."); yynerrs++;} +| FOR control_variable ASSIGN error TO expression BY expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid start expression defined in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN error TO expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid start expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN expression error expression BY expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@5), locl(@5), "expecting 'TO' between start expression and end expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN expression error expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@5), locl(@5), "expecting 'TO' between start expression and end expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN expression TO expression error expression DO statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@7), locl(@7), "expecting 'BY' between end expression and step expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN expression TO expression BY expression error statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@9), locl(@9), "expecting 'DO' after step expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN expression TO expression error statement_list END_FOR + {$$ = NULL; print_err_msg(locf(@7), locl(@7), "expecting 'DO' after end expression in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN expression TO expression BY expression DO END_FOR + {$$ = NULL; print_err_msg(locl(@9), locf(@10), "no statement(s) defined after 'DO' in ST 'FOR' statement."); yynerrs++;} +| FOR control_variable ASSIGN expression TO expression DO END_FOR + {$$ = NULL; print_err_msg(locl(@7), locf(@8), "no statement(s) defined after 'DO' in ST 'FOR' statement."); yynerrs++;} +| FOR control_variable ASSIGN expression TO expression BY expression DO error END_FOR + {$$ = NULL; print_err_msg(locf(@10), locl(@10), "invalid statement(s) defined after 'DO' in ST 'FOR' statement."); yyerrok;} +| FOR control_variable ASSIGN expression TO expression DO error END_FOR + {$$ = NULL; print_err_msg(locf(@8), locl(@8), "invalid statement(s) defined after 'DO' in ST 'FOR' statement."); yyerrok;} +| FOR control_variable error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yyerrok;} +| FOR control_variable ASSIGN expression error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yyerrok;} +| FOR control_variable ASSIGN expression TO expression DO statement_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yynerrs++;} +| FOR control_variable ASSIGN expression TO expression BY expression error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yyerrok;} +| FOR control_variable ASSIGN expression TO expression BY expression DO statement_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'FOR' statement in ST."); yynerrs++;} +| FOR error END_FOR + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'FOR' statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + +/* The spec has the syntax + * control_variable: identifier; + * but then defines the semantics of control_variable + * (Section 3.3.2.4) as being of an integer type + * (e.g., SINT, INT, or DINT). + * + * Obviously this presuposes that the control_variable + * must have been declared in some VAR .. END_VAR + * We must therefore change the syntax to read + * control_variable: prev_declared_variable_name; + * + * If we don't, then the correct use of any previosuly declared + * variable would result in an incorrect syntax error +*/ +control_variable: + prev_declared_variable_name + {$$ = new symbolic_variable_c($1,locloc(@$));}; +// control_variable: identifier {$$ = $1;}; + +/* Integrated directly into for_statement */ +/* +for_list: + expression TO expression [BY expression] +; +*/ + + +while_statement: + WHILE expression DO statement_list END_WHILE + {$$ = new while_statement_c($2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| WHILE DO statement_list END_WHILE + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no test expression defined in ST 'WHILE' statement."); yynerrs++;} +| WHILE error DO statement_list END_WHILE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid test expression defined for ST 'WHILE' statement."); yyerrok;} +| WHILE expression error statement_list END_WHILE + {$$ = NULL; print_err_msg(locf(@3), locl(@3), "expecting 'DO' after test expression in ST 'WHILE' statement."); yyerrok;} +| WHILE expression DO END_WHILE + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no statement(s) defined after 'DO' in ST 'WHILE' statement."); yynerrs++;} +| WHILE expression DO error END_WHILE + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid statement(s) defined after 'DO' in ST 'WHILE' statement."); yyerrok;} +| WHILE expression error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'WHILE' statement in ST."); yyerrok;} +| WHILE expression DO statement_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'WHILE' statement in ST."); yynerrs++;} +| WHILE error END_WHILE + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'WHILE' statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +repeat_statement: + REPEAT statement_list UNTIL expression END_REPEAT + {$$ = new repeat_statement_c($2, $4, locloc(@$));} +/* ERROR_CHECK_BEGIN */ +| REPEAT UNTIL expression END_REPEAT + {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no statement(s) defined after 'REPEAT' in ST 'REPEAT' statement."); yynerrs++;} +| REPEAT error UNTIL expression END_REPEAT + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid statement(s) defined after 'REPEAT' for ST 'REPEAT' statement."); yyerrok;} +| REPEAT statement_list UNTIL END_REPEAT + {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no test expression defined after 'UNTIL' in ST 'REPEAT' statement.");} +| REPEAT statement_list UNTIL error END_REPEAT + {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid test expression defined after 'UNTIL' in ST 'REPEAT' statement."); yyerrok;} +| REPEAT statement_list END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'REPEAT' statement in ST."); yynerrs++;} +| REPEAT statement_list UNTIL expression error END_OF_INPUT + {$$ = NULL; print_err_msg(locf(@1), locl(@1), "unclosed 'REPEAT' statement in ST."); yyerrok;} +| REPEAT error END_REPEAT + {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in ST 'REPEAT' statement."); yyerrok;} +/* ERROR_CHECK_END */ +; + + +exit_statement: + EXIT {$$ = new exit_statement_c(locloc(@$));} +; + + + + + +%% + +#include /* required for printf() */ +#include +#include "../util/symtable.hh" + +/* variables defined in code generated by flex... */ +extern FILE *yyin; +extern int yylineno; +extern tracking_t* current_tracking; + + + + +/*************************************************************************************************/ +/* NOTE: These variables are really parameters we would like the stage2__ function to pass */ +/* to the yyparse() function. However, the yyparse() function is created automatically */ +/* by bison, so we cannot add parameters to this function. The only other */ +/* option is to use global variables! yuck! */ +/*************************************************************************************************/ + +/* A global flag used to tell the parser if overloaded funtions should be allowed. + * The IEC 61131-3 standard allows overloaded funtions in the standard library, + * but disallows them in user code... + * + * In essence, a parameter we would like to pass to the yyparse() function but + * have to do it using a global variable, as the yyparse() prototype is fixed by bison. + */ +bool allow_function_overloading = false; + +/* | [var1_list ','] variable_name '..' */ +/* NOTE: This is an extension to the standard!!! */ +/* In order to be able to handle extensible standard functions + * (i.e. standard functions that may have a variable number of + * input parameters, such as AND(word#33, word#44, word#55, word#66), + * we have extended the acceptable syntax to allow var_name '..' + * in an input variable declaration. + * + * This allows us to parse the declaration of standard + * extensible functions and load their interface definition + * into the abstract syntax tree just like we do to other + * user defined functions. + * This has the advantage that we can later do semantic + * checking of calls to functions (be it a standard or user defined + * function) in (almost) exactly the same way. + * + * Of course, we have a flag that disables this syntax when parsing user + * written code, so we only allow this extra syntax while parsing the + * 'header' file that declares all the standard IEC 61131-3 functions. + */ +bool allow_extensible_function_parameters = false; + +/* A global flag used to tell the parser whether to include the full variable location + * when printing out error messages... + */ +bool full_token_loc; + +/* A pointer to the root of the parsing tree that will be generated + * by bison. + */ +symbol_c *tree_root; + + + +/* The following function is called automatically by bison whenever it comes across + * an error. Unfortunately it calls this function before executing the code that handles + * the error itself, so we cannot print out the correct line numbers of the error location + * over here. + * Our solution is to store the current error message in a global variable, and have all + * error action handlers call the function print_err_msg() after setting the location + * (line number) variable correctly. + */ +const char *current_error_msg; +void yyerror (const char *error_msg) { + current_error_msg = error_msg; +/* fprintf(stderr, "error %d: %s\n", yynerrs // global variable //, error_msg); */ +/* print_include_stack(); */ +} + + +/* ERROR_CHECK_BEGIN */ +bool is_current_syntax_token() { + switch (yychar) { + case ';': + case ',': + case ')': + case ']': + case '+': + case '*': + case '-': + case '/': + case '<': + case '>': + case '=': + case '&': + case OR: + case XOR: + case AND: + case AND2: + case OPER_NE: + case OPER_LE: + case OPER_GE: + case MOD: + case OPER_EXP: + case NOT: + return true; + default: + return false; + } +} +/* ERROR_CHECK_END */ + + +void print_err_msg(int first_line, + int first_column, + const char *first_filename, + long int first_order, + int last_line, + int last_column, + const char *last_filename, + long int last_order, + const char *additional_error_msg) { + + const char *unknown_file = ""; + if (first_filename == NULL) first_filename = unknown_file; + if ( last_filename == NULL) last_filename = unknown_file; + + if (full_token_loc) { + if (first_filename == last_filename) + fprintf(stderr, "%s:%d-%d..%d-%d: error : %s\n", first_filename, first_line, first_column, last_line, last_column, additional_error_msg); + else + 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); + } else { + fprintf(stderr, "%s:%d: error : %s\n", first_filename, first_line, additional_error_msg); + } + //fprintf(stderr, "error %d: %s\n", yynerrs /* a global variable */, additional_error_msg); + print_include_stack(); + //fprintf(stderr, "%s(%d-%d): %s\n", current_filename, first_line, last_line, current_error_msg); +} + + + +/* If function overloading is on, we allow several functions with the same name. + * + * However, to support standard functions, we also allow functions named + * AND, MOD, NOT, OR, XOR, ADD, ... + */ +/* +identifier_c *token_2_identifier_c(char *value, ) { + identifier_c tmp = new identifier_c(value, locloc(@$)); + if (!allow_function_overloading) { + fprintf(stderr, "Function overloading not allowed. Invalid identifier %s\n", ((token_c *)($$))->value); + ERROR; + } + } +} +*/ + +/* convert between an il_operator to a function name */ +/* This a kludge! + * It is required because our language requires more than one + * look ahead token, and bison only works with one! + */ +#define op_2_str(op, str) {\ + op ## _operator_c *ptr = dynamic_cast(il_operator); \ + if (ptr != NULL) name = str; \ +} + +/* NOTE: this code is very ugly and un-eficient, but I (Mario) have many + * more things to worry about right now, so just let it be... + */ +symbol_c *il_operator_c_2_identifier_c(symbol_c *il_operator) { + const char *name = NULL; + identifier_c *res; + + op_2_str(NOT, "NOT"); + + op_2_str(AND, "AND"); + op_2_str(OR, "OR"); + op_2_str(XOR, "XOR"); + op_2_str(ADD, "ADD"); + op_2_str(SUB, "SUB"); + op_2_str(MUL, "MUL"); + op_2_str(DIV, "DIV"); + op_2_str(MOD, "MOD"); + op_2_str(GT, "GT"); + op_2_str(GE, "GE"); + op_2_str(EQ, "EQ"); + op_2_str(LT, "LT"); + op_2_str(LE, "LE"); + op_2_str(NE, "NE"); + + op_2_str(LD, "LD"); + op_2_str(LDN, "LDN"); + op_2_str(ST, "ST"); + op_2_str(STN, "STN"); + + op_2_str(S, "S"); + op_2_str(R, "R"); + op_2_str(S1, "S1"); + op_2_str(R1, "R1"); + + op_2_str(CLK, "CLK"); + op_2_str(CU, "CU"); + op_2_str(CD, "CD"); + op_2_str(PV, "PV"); + op_2_str(IN, "IN"); + op_2_str(PT, "PT"); + + op_2_str(ANDN, "ANDN"); + op_2_str(ORN, "ORN"); + op_2_str(XORN, "XORN"); + + op_2_str(ADD, "ADD"); + op_2_str(SUB, "SUB"); + op_2_str(MUL, "MUL"); + op_2_str(DIV, "DIV"); + + op_2_str(GT, "GT"); + op_2_str(GE, "GE"); + op_2_str(EQ, "EQ"); + op_2_str(LT, "LT"); + op_2_str(LE, "LE"); + op_2_str(NE, "NE"); + + op_2_str(CAL, "CAL"); + op_2_str(CALC, "CALC"); + op_2_str(CALCN, "CALCN"); + op_2_str(RET, "RET"); + op_2_str(RETC, "RETC"); + op_2_str(RETCN, "RETCN"); + op_2_str(JMP, "JMP"); + op_2_str(JMPC, "JMPC"); + op_2_str(JMPCN, "JMPCN"); + + if (name == NULL) + ERROR; + + res = new identifier_c(strdup(name), + il_operator->first_line, + il_operator->first_column, + il_operator->first_file, + il_operator->first_order, + il_operator->last_line, + il_operator->last_column, + il_operator->last_file, + il_operator->last_order + ); + free(il_operator); + return res; +} + + +#include "standard_function_names.c" + +const char *standard_function_block_names[] = { +// 2.5.2.3.1 Bistable elements +// Table 34 - Standard bistable function blocks +"SR","RS", +// 2.5.2.3.2 Edge detection +// Table 35 - Standard edge detection function blocks +"R_TRIG","F_TRIG", +// 2.5.2.3.3 Counters +// Table 36 - Standard counter function blocks +"CTU","CTU_DINT","CTU_LINT","CTU_UDINT","CTU_ULINT", +"CTD","CTD_DINT","CTD_LINT","CTD_UDINT","CTD_ULINT", +"CTUD","CTUD_DINT","CTUD_LINT","CTUD_ULINT", +// 2.5.2.3.4 Timers +// Table 37 - Standard timer function blocks +"TP","TON","TOF", +/* end of array marker! Do not remove! */ +NULL +}; + + +#define LIBFILE "ieclib.txt" +#define DEF_LIBFILENAME LIBDIRECTORY "/" LIBFILE + +extern const char *INCLUDE_DIRECTORIES[]; + + + +int stage2__(const char *filename, + const char *includedir, /* Include directory, where included files will be searched for... */ + symbol_c **tree_root_ref, + bool full_token_loc_ /* error messages specify full token location */ + ) { + + FILE *in_file = NULL, *lib_file = NULL; + char *libfilename = NULL; + + if((in_file = fopen(filename, "r")) == NULL) { + char *errmsg = strdup2("Error opening main file ", filename); + perror(errmsg); + free(errmsg); + return -1; + } + + if (includedir != NULL) { + INCLUDE_DIRECTORIES[0] = includedir; + } + if ((libfilename = strdup3(INCLUDE_DIRECTORIES[0], "/", LIBFILE)) == NULL) { + fprintf (stderr, "Out of memory. Bailing out!\n"); + return -1; + } + + if((lib_file = fopen(libfilename, "r")) == NULL) { + char *errmsg = strdup2("Error opening library file ", libfilename); + perror(errmsg); + free(errmsg); + } + + if (lib_file == NULL) { + /* we give up... */ + free(libfilename); + fclose(in_file); + return -1; + } + + /* first parse the standard library file... */ + /* + #if YYDEBUG + yydebug = 1; + #endif + */ + yyin = lib_file; + allow_function_overloading = true; + allow_extensible_function_parameters = true; + full_token_loc = full_token_loc_; + current_filename = libfilename; + current_tracking = GetNewTracking(yyin); + if (yyparse() != 0) + ERROR; + + if (yynerrs > 0) { + fprintf (stderr, "\nFound %d error(s) in %s. Bailing out!\n", yynerrs /* global variable */, libfilename); + ERROR; + } + free(libfilename); + fclose(lib_file); + + /* if by any chance the library is not complete, we + * now add the missing reserved keywords to the list!!! + */ + for(int i = 0; standard_function_block_names[i] != NULL; i++) + if (library_element_symtable.find_value(standard_function_block_names[i]) == + library_element_symtable.end_value()) + library_element_symtable.insert(standard_function_block_names[i], standard_function_block_name_token); + + + /* now parse the input file... */ + #if YYDEBUG + yydebug = 1; + #endif + yyin = in_file; + allow_function_overloading = false; + allow_extensible_function_parameters = false; + full_token_loc = full_token_loc_; + current_filename = filename; + current_tracking = GetNewTracking(yyin); + {int res; + if ((res = yyparse()) != 0) { + fprintf (stderr, "\nParsing failed because of too many consecutive syntax errors. Bailing out!\n"); + exit(EXIT_FAILURE); + } + } + + if (yynerrs > 0) { + fprintf (stderr, "\nFound %d error(s). Bailing out!\n", yynerrs /* global variable */); + exit(EXIT_FAILURE); + } + + if (tree_root_ref != NULL) + *tree_root_ref = tree_root; + + fclose(in_file); + return 0; +} + + +