--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/stage1_2/iec.y Wed Jan 31 15:32:38 2007 +0100
@@ -0,0 +1,5422 @@
+/*
+ * (c) 2003 Mario de Sousa
+ *
+ * Offered to the public under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2 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.
+ *
+ * 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 IL and ST 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. 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 <string.h> /* 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.y.hh"
+
+/* file with the declarations of symbol tables... */
+#include "../util/symtable.hh"
+
+
+/* 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 <elem> in list_c * <list>
+ * execute the code <code>
+ */
+#define FOR_EACH_ELEMENT(elem, list, code) { \
+ symbol_c *elem; \
+ for(int i = 0; i < list->n; i++) { \
+ elem = list->elements[i]; \
+ code; \
+ } \
+}
+
+
+/* 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);
+
+
+/*********************************/
+/* The global symbol tables... */
+/*********************************/
+/* NOTE: declared static because they are not accessed
+ * directly by the lexical parser (flex), but rather
+ * through the function get_identifier_token()
+ */
+/* A symbol table to store all the library elements */
+/* e.g.: <function_name , function_decl>
+ * <fb_name , fb_decl>
+ * <type_name , type_decl>
+ * <program_name , program_decl>
+ * <configuration_name , configuration_decl>
+ */
+static symtable_c<int, BOGUS_TOKEN_ID> library_element_symtable;
+
+/* A symbol table to store the declared variables of
+ * the function currently being parsed...
+ */
+static symtable_c<int, BOGUS_TOKEN_ID> variable_name_symtable;
+
+
+/*************************/
+/* global variables... */
+/*************************/
+static symbol_c *tree_root = NULL;
+
+/* The name of the file currently being parsed...
+ * Note that flex accesses and updates this global variable
+ * apropriately whenever it comes across an (*#include <filename> *)
+ * directive...
+ */
+const char *current_filename = NULL;
+
+/* 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...
+ */
+bool allow_function_overloading = false;
+
+
+/************************/
+/* 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);
+
+/* print an error message */
+void print_err_msg(const char *filename, int lineno, const char *additional_error_msg);
+
+
+/************************/
+/* forward declarations */
+/************************/
+/* The functions declared here are defined in iec.flex... */
+void print_include_stack(void);
+
+
+%}
+
+
+
+%union {
+ symbol_c *leaf;
+ list_c *list;
+ char *ID; /* token value */
+ struct {
+ symbol_c *first;
+ symbol_c *second;
+ } double_symbol; /* used by il_simple_operator_clash_il_operand */
+}
+
+
+
+
+
+
+/*****************************/
+/* Prelimenary constructs... */
+/*****************************/
+%type <leaf> start
+
+%type <leaf> any_identifier
+
+%token <ID> prev_declared_variable_name_token
+%token <ID> prev_declared_fb_name_token
+%type <leaf> prev_declared_variable_name
+%type <leaf> prev_declared_fb_name
+
+%token <ID> prev_declared_simple_type_name_token
+%token <ID> prev_declared_subrange_type_name_token
+%token <ID> prev_declared_enumerated_type_name_token
+%token <ID> prev_declared_array_type_name_token
+%token <ID> prev_declared_structure_type_name_token
+%token <ID> prev_declared_string_type_name_token
+
+%type <leaf> prev_declared_simple_type_name
+%type <leaf> prev_declared_subrange_type_name
+%type <leaf> prev_declared_enumerated_type_name
+%type <leaf> prev_declared_array_type_name
+%type <leaf> prev_declared_structure_type_name
+%type <leaf> prev_declared_string_type_name
+
+%token <ID> prev_declared_derived_function_name_token
+%token <ID> prev_declared_derived_function_block_name_token
+%token <ID> prev_declared_program_type_name_token
+%type <leaf> prev_declared_derived_function_name
+%type <leaf> prev_declared_derived_function_block_name
+%type <leaf> prev_declared_program_type_name
+
+
+/* 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
+
+
+/* The pragmas... */
+%token <ID> pragma_token
+%type <leaf> pragma
+
+
+/* Where do these tokens belong ?? */
+/* TODO: get the syntax parser to handle these tokens... */
+%token EN
+%token ENO
+
+
+
+/***************************/
+/* B 0 - Programming Model */
+/***************************/
+%type <list> library
+%type <leaf> library_element_declaration
+
+
+/*******************************************/
+/* B 1.1 - Letters, digits and identifiers */
+/*******************************************/
+/* Done totally within flex...
+ letter
+ digit
+ octal_digit
+ hex_digit
+*/
+%token <ID> identifier_token
+%type <leaf> identifier
+
+
+/*********************/
+/* B 1.2 - Constants */
+/*********************/
+%type <leaf> constant
+/* a helper symbol for expression */
+%type <leaf> non_negative_constant
+
+
+/******************************/
+/* B 1.2.1 - Numeric Literals */
+/******************************/
+/* Done totally within flex...
+ bit
+*/
+%type <leaf> numeric_literal
+/* helper symbol for non_negative_constant */
+%type <leaf> non_negative_numeric_literal
+%type <leaf> integer_literal
+%type <leaf> signed_integer
+/* a helper symbol for non_negative_constant */
+%type <leaf> non_negative_signed_integer
+%token <ID> integer_token
+%type <leaf> integer
+%token <ID> binary_integer_token
+%type <leaf> binary_integer
+%token <ID> octal_integer_token
+%type <leaf> octal_integer
+%token <ID> hex_integer_token
+%type <leaf> hex_integer
+%token <ID> real_token
+%type <leaf> real
+%type <leaf> signed_real
+/* helper symbol for non_negative_real_literal */
+%type <leaf> non_negative_signed_real
+%type <leaf> real_literal
+/* helper symbol for non_negative_numeric_literal */
+%type <leaf> non_negative_real_literal
+// %type <leaf> exponent
+%type <leaf> bit_string_literal
+%type <leaf> boolean_literal
+
+%token FALSE
+%token TRUE
+
+
+/*******************************/
+/* B 1.2.2 - Character Strings */
+/*******************************/
+%token <ID> single_byte_character_string_token
+%token <ID> double_byte_character_string_token
+
+%type <leaf> character_string
+%type <leaf> single_byte_character_string
+%type <leaf> double_byte_character_string
+
+
+/***************************/
+/* B 1.2.3 - Time Literals */
+/***************************/
+%type <leaf> time_literal
+
+
+/************************/
+/* B 1.2.3.1 - Duration */
+/************************/
+%type <leaf> duration
+%type <leaf> interval
+%type <leaf> days
+%type <leaf> fixed_point
+%type <leaf> hours
+%type <leaf> minutes
+%type <leaf> seconds
+%type <leaf> milliseconds
+
+%type <leaf> integer_d
+%type <leaf> integer_h
+%type <leaf> integer_m
+%type <leaf> integer_s
+%type <leaf> integer_ms
+%type <leaf> fixed_point_d
+%type <leaf> fixed_point_h
+%type <leaf> fixed_point_m
+%type <leaf> fixed_point_s
+%type <leaf> fixed_point_ms
+
+%token <ID> fixed_point_token
+%token <ID> fixed_point_d_token
+%token <ID> integer_d_token
+%token <ID> fixed_point_h_token
+%token <ID> integer_h_token
+%token <ID> fixed_point_m_token
+%token <ID> integer_m_token
+%token <ID> fixed_point_s_token
+%token <ID> integer_s_token
+%token <ID> fixed_point_ms_token
+%token <ID> integer_ms_token
+
+%token TIME
+%token T_SHARP
+
+
+/************************************/
+/* B 1.2.3.2 - Time of day and Date */
+/************************************/
+%type <leaf> time_of_day
+%type <leaf> daytime
+%type <leaf> day_hour
+%type <leaf> day_minute
+%type <leaf> day_second
+%type <leaf> date
+%type <leaf> date_literal
+%type <leaf> year
+%type <leaf> month
+%type <leaf> day
+%type <leaf> 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 <leaf> data_type_name
+%type <leaf> 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 <leaf> elementary_type_name
+%type <leaf> numeric_type_name
+%type <leaf> integer_type_name
+%type <leaf> signed_integer_type_name
+%type <leaf> unsigned_integer_type_name
+%type <leaf> real_type_name
+%type <leaf> date_type_name
+%type <leaf> bit_string_type_name
+/* helper symbol to concentrate the instantiation
+ * of STRING and WSTRING into a single location
+ */
+%type <leaf> 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
+
+
+/********************************/
+/* B 1.3.2 - Generic data types */
+/********************************/
+/* Strangely, the following symbol does seem to be required! */
+// %type <leaf> 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 <leaf> derived_type_name
+%type <leaf> single_element_type_name
+// %type <leaf> simple_type_name
+// %type <leaf> subrange_type_name
+// %type <leaf> enumerated_type_name
+// %type <leaf> array_type_name
+// %type <leaf> structure_type_name
+
+%type <leaf> data_type_declaration
+/* helper symbol for data_type_declaration */
+%type <list> type_declaration_list
+%type <leaf> type_declaration
+%type <leaf> single_element_type_declaration
+
+%type <leaf> simple_type_declaration
+%type <leaf> simple_spec_init
+%type <leaf> simple_specification
+
+%type <leaf> subrange_type_declaration
+%type <leaf> subrange_spec_init
+%type <leaf> subrange_specification
+%type <leaf> subrange
+
+%type <leaf> enumerated_type_declaration
+%type <leaf> enumerated_spec_init
+%type <leaf> enumerated_specification
+/* helper symbol for enumerated_value */
+%type <list> enumerated_value_list
+%type <leaf> enumerated_value
+
+%type <leaf> array_type_declaration
+%type <leaf> array_spec_init
+%type <leaf> array_specification
+/* helper symbol for array_specification */
+%type <list> array_subrange_list
+%type <leaf> array_initialization
+/* helper symbol for array_initialization */
+%type <list> array_initial_elements_list
+%type <leaf> array_initial_elements
+%type <leaf> array_initial_element
+
+%type <leaf> structure_type_declaration
+%type <leaf> structure_specification
+%type <leaf> initialized_structure
+%type <leaf> structure_declaration
+/* helper symbol for structure_declaration */
+%type <list> structure_element_declaration_list
+%type <leaf> structure_element_declaration
+%type <leaf> structure_element_name
+%type <leaf> structure_initialization
+/* helper symbol for structure_initialization */
+%type <list> structure_element_initialization_list
+%type <leaf> structure_element_initialization
+
+//%type <leaf> string_type_name
+%type <leaf> string_type_declaration
+/* helper symbol for string_type_declaration */
+%type <leaf> string_type_declaration_size
+/* helper symbol for string_type_declaration */
+%type <leaf> 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 <leaf> variable
+%type <leaf> symbolic_variable
+/* helper symbol for prog_cnxn */
+%type <leaf> any_symbolic_variable
+%type <leaf> variable_name
+
+
+
+
+/********************************************/
+/* B.1.4.1 Directly Represented Variables */
+/********************************************/
+/* Done totally within flex...
+ location_prefix
+ size_prefix
+*/
+%token <ID> direct_variable_token
+%type <leaf> direct_variable
+
+
+/*************************************/
+/* B.1.4.2 Multi-element Variables */
+/*************************************/
+%type <leaf> multi_element_variable
+/* helper symbol for any_symbolic_variable */
+%type <leaf> any_multi_element_variable
+%type <leaf> array_variable
+/* helper symbol for any_symbolic_variable */
+%type <leaf> any_array_variable
+%type <leaf> subscripted_variable
+/* helper symbol for any_symbolic_variable */
+%type <leaf> any_subscripted_variable
+%type <list> subscript_list
+%type <leaf> subscript
+%type <leaf> structured_variable
+/* helper symbol for any_symbolic_variable */
+%type <leaf> any_structured_variable
+%type <leaf> record_variable
+/* helper symbol for any_symbolic_variable */
+%type <leaf> any_record_variable
+%type <leaf> field_selector
+
+
+/******************************************/
+/* B 1.4.3 - Declaration & Initialisation */
+/******************************************/
+%type <leaf> input_declarations
+/* helper symbol for input_declarations */
+%type <list> input_declaration_list
+%type <leaf> input_declaration
+%type <leaf> edge_declaration
+%type <leaf> var_init_decl
+%type <leaf> var1_init_decl
+%type <list> var1_list
+%type <leaf> array_var_init_decl
+%type <leaf> structured_var_init_decl
+%type <leaf> fb_name_decl
+/* helper symbol for fb_name_decl */
+%type <list> fb_name_list_with_colon
+/* helper symbol for fb_name_list_with_colon */
+%type <list> var1_list_with_colon
+// %type <list> fb_name_list
+// %type <leaf> fb_name
+%type <leaf> output_declarations
+%type <leaf> input_output_declarations
+/* helper symbol for input_output_declarations */
+%type <list> var_declaration_list
+%type <leaf> var_declaration
+%type <leaf> temp_var_decl
+%type <leaf> var1_declaration
+%type <leaf> array_var_declaration
+%type <leaf> structured_var_declaration
+%type <leaf> var_declarations
+%type <leaf> retentive_var_declarations
+%type <leaf> located_var_declarations
+/* helper symbol for located_var_declarations */
+%type <list> located_var_decl_list
+%type <leaf> located_var_decl
+%type <leaf> external_var_declarations
+/* helper symbol for external_var_declarations */
+%type <list> external_declaration_list
+%type <leaf> external_declaration
+%type <leaf> global_var_name
+%type <leaf> global_var_declarations
+/* helper symbol for global_var_declarations */
+%type <list> global_var_decl_list
+%type <leaf> global_var_decl
+%type <leaf> global_var_spec
+%type <leaf> located_var_spec_init
+%type <leaf> location
+%type <list> global_var_list
+%type <leaf> string_var_declaration
+%type <leaf> single_byte_string_var_declaration
+%type <leaf> single_byte_string_spec
+%type <leaf> double_byte_string_var_declaration
+%type <leaf> double_byte_string_spec
+%type <leaf> incompl_located_var_declarations
+/* helper symbol for incompl_located_var_declarations */
+%type <list> incompl_located_var_decl_list
+%type <leaf> incompl_located_var_decl
+%type <leaf> incompl_location
+%type <leaf> var_spec
+/* helper symbol for var_spec */
+%type <leaf> string_spec
+/* intermediate helper symbol for:
+ * - non_retentive_var_decls
+ * - output_declarations
+ */
+%type <list> var_init_decl_list
+
+%token <ID> 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 <leaf> function_name
+/* helper symbol for IL language */
+%type <leaf> function_name_no_clashes
+%type <leaf> function_name_simpleop_clashes
+//%type <leaf> function_name_expression_clashes
+/* helper symbols for ST language */
+//%type <leaf> function_name_NOT_clashes
+%type <leaf> function_name_no_NOT_clashes
+
+//%type <leaf> standard_function_name
+/* helper symbols for IL language */
+%type <leaf> standard_function_name_no_clashes
+%type <leaf> standard_function_name_simpleop_clashes
+%type <leaf> standard_function_name_expression_clashes
+/* helper symbols for ST language */
+%type <leaf> standard_function_name_NOT_clashes
+%type <leaf> standard_function_name_no_NOT_clashes
+
+%type <leaf> derived_function_name
+%type <leaf> function_declaration
+/* helper symbol for function_declaration */
+%type <leaf> function_name_declaration
+%type <leaf> io_var_declarations
+%type <leaf> function_var_decls
+%type <leaf> function_body
+%type <leaf> var2_init_decl
+/* intermediate helper symbol for function_declaration */
+%type <list> io_OR_function_var_declarations_list
+/* intermediate helper symbol for function_var_decls */
+%type <list> var2_init_decl_list
+
+%token <ID> standard_function_name_token
+
+%token FUNCTION
+%token END_FUNCTION
+%token CONSTANT
+
+
+/*****************************/
+/* B 1.5.2 - Function Blocks */
+/*****************************/
+%type <leaf> function_block_type_name
+%type <leaf> standard_function_block_name
+%type <leaf> derived_function_block_name
+%type <leaf> function_block_declaration
+%type <leaf> other_var_declarations
+%type <leaf> temp_var_decls
+%type <leaf> non_retentive_var_decls
+%type <leaf> function_block_body
+/* intermediate helper symbol for function_declaration */
+%type <list> io_OR_other_var_declarations_list
+/* intermediate helper symbol for temp_var_decls */
+%type <list> temp_var_decls_list
+
+%token <ID> 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 <leaf> program_type_name
+%type <leaf> program_declaration
+/* helper symbol for program_declaration */
+%type <list> program_var_declarations_list
+
+%token PROGRAM
+%token END_PROGRAM
+
+
+/********************************************/
+/* B 1.6 Sequential Function Chart elements */
+/********************************************/
+/* TODO */
+/*
+%type <list> sequential_function_chart
+%type <leaf> sfc_network
+%type <leaf> initial_step
+%type <leaf> step
+%type <leaf> action_association_list
+%type <leaf> step_name
+%type <leaf> action_association
+/* helper symbol for action_association *
+%type <list> indicator_name_list
+%type <leaf> action_name
+%type <leaf> action_qualifier
+%type <leaf> timed_qualifier
+%type <leaf> action_time
+%type <leaf> indicator_name
+%type <leaf> transition
+%type <leaf> steps
+%type <list> step_name_list
+%type <leaf> transition_condition
+%type <leaf> action
+*/
+
+%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 <leaf> configuration_name
+%type <leaf> resource_type_name
+%type <leaf> configuration_declaration
+// helper symbol for
+// - configuration_declaration
+// - resource_declaration
+//
+%type <leaf> optional_global_var_declarations
+// helper symbol for configuration_declaration
+%type <leaf> optional_access_declarations
+// helper symbol for configuration_declaration
+%type <leaf> optional_instance_specific_initializations
+// helper symbol for configuration_declaration
+%type <list> resource_declaration_list
+%type <leaf> resource_declaration
+%type <leaf> single_resource_declaration
+// helper symbol for single_resource_declaration
+%type <list> task_configuration_list
+// helper symbol for single_resource_declaration
+%type <list> program_configuration_list
+%type <leaf> resource_name
+// %type <leaf> access_declarations
+// helper symbol for access_declarations
+// %type <leaf> access_declaration_list
+// %type <leaf> access_declaration
+// %type <leaf> access_path
+// helper symbol for access_path
+%type <list> any_fb_name_list
+%type <leaf> global_var_reference
+// %type <leaf> access_name
+%type <leaf> program_output_reference
+%type <leaf> program_name
+// %type <leaf> direction
+%type <leaf> task_configuration
+%type <leaf> task_name
+%type <leaf> task_initialization
+%type <leaf> data_source
+%type <leaf> program_configuration
+// helper symbol for program_configuration
+%type <leaf> optional_task_name
+// helper symbol for program_configuration
+%type <leaf> optional_prog_conf_elements
+%type <list> prog_conf_elements
+%type <leaf> prog_conf_element
+%type <leaf> fb_task
+%type <leaf> prog_cnxn
+%type <leaf> prog_data_source
+%type <leaf> data_sink
+%type <leaf> instance_specific_initializations
+// helper symbol for instance_specific_initializations
+%type <list> instance_specific_init_list
+%type <leaf> instance_specific_init
+// helper symbol for instance_specific_init
+%type <leaf> fb_initialization
+
+%type <leaf> prev_declared_global_var_name
+%token <ID> prev_declared_global_var_name_token
+
+%type <leaf> prev_declared_program_name
+%token <ID> prev_declared_program_name_token
+
+%type <leaf> prev_declared_resource_name
+%token <ID> prev_declared_resource_name_token
+
+%token <ID> prev_declared_configuration_name_token
+
+// %type <leaf> prev_declared_task_name
+// %token <ID> 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 <list> instruction_list
+%type <leaf> il_instruction
+%type <leaf> il_incomplete_instruction
+%type <leaf> label
+%type <leaf> il_simple_operation
+// helper symbol for il_simple_operation
+%type <double_symbol> il_simple_operator_clash_il_operand
+%type <leaf> il_expression
+%type <leaf> il_jump_operation
+%type <leaf> il_fb_call
+%type <leaf> il_formal_funct_call
+// helper symbol for il_formal_funct_call
+%type <leaf> il_expr_operator_clash_eol_list
+%type <leaf> il_operand
+%type <list> il_operand_list
+%type <list> simple_instr_list
+%type <leaf> il_simple_instruction
+%type <list> il_param_list
+%type <list> il_param_instruction_list
+%type <leaf> il_param_instruction
+%type <leaf> il_param_last_instruction
+%type <leaf> il_param_assignment
+%type <leaf> il_param_out_assignment
+
+%token EOL
+
+
+/*******************/
+/* B 2.2 Operators */
+/*******************/
+%token <ID> sendto_identifier_token
+%type <leaf> sendto_identifier
+
+%type <leaf> LD_operator
+%type <leaf> LDN_operator
+%type <leaf> ST_operator
+%type <leaf> STN_operator
+%type <leaf> NOT_operator
+%type <leaf> S_operator
+%type <leaf> R_operator
+%type <leaf> S1_operator
+%type <leaf> R1_operator
+%type <leaf> CLK_operator
+%type <leaf> CU_operator
+%type <leaf> CD_operator
+%type <leaf> PV_operator
+%type <leaf> IN_operator
+%type <leaf> PT_operator
+%type <leaf> AND_operator
+%type <leaf> AND2_operator
+%type <leaf> OR_operator
+%type <leaf> XOR_operator
+%type <leaf> ANDN_operator
+%type <leaf> ANDN2_operator
+%type <leaf> ORN_operator
+%type <leaf> XORN_operator
+%type <leaf> ADD_operator
+%type <leaf> SUB_operator
+%type <leaf> MUL_operator
+%type <leaf> DIV_operator
+%type <leaf> MOD_operator
+%type <leaf> GT_operator
+%type <leaf> GE_operator
+%type <leaf> EQ_operator
+%type <leaf> LT_operator
+%type <leaf> LE_operator
+%type <leaf> NE_operator
+%type <leaf> CAL_operator
+%type <leaf> CALC_operator
+%type <leaf> CALCN_operator
+%type <leaf> RET_operator
+%type <leaf> RETC_operator
+%type <leaf> RETCN_operator
+%type <leaf> JMP_operator
+%type <leaf> JMPC_operator
+%type <leaf> JMPCN_operator
+
+%type <leaf> il_simple_operator
+%type <leaf> il_simple_operator_clash
+%type <leaf> il_simple_operator_clash1
+%type <leaf> il_simple_operator_clash2
+%type <leaf> il_simple_operator_noclash
+
+//%type <leaf> il_expr_operator
+%type <leaf> il_expr_operator_clash
+%type <leaf> il_expr_operator_noclash
+
+%type <leaf> il_assign_operator
+%type <leaf> il_assign_out_operator
+%type <leaf> il_call_operator
+%type <leaf> il_return_operator
+%type <leaf> 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 <leaf> expression
+%type <leaf> xor_expression
+%type <leaf> and_expression
+%type <leaf> comparison
+%type <leaf> equ_expression
+// %type <leaf> comparison_operator
+%type <leaf> add_expression
+// %type <leaf> add_operator
+%type <leaf> term
+// %type <leaf> multiply_operator
+%type <leaf> power_expression
+%type <leaf> unary_expression
+// %type <leaf> unary_operator
+%type <leaf> primary_expression
+/* intermediate helper symbol for primary_expression */
+%type <leaf> 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 <list> statement_list
+%type <leaf> statement
+
+
+
+/*********************************/
+/* B 3.2.1 Assignment Statements */
+/*********************************/
+%type <leaf> assignment_statement
+%token ASSIGN /* ":=" */
+
+
+/*****************************************/
+/* B 3.2.2 Subprogram Control Statements */
+/*****************************************/
+%type <leaf> subprogram_control_statement
+%type <leaf> return_statement
+%type <leaf> fb_invocation
+%type <leaf> param_assignment
+/* helper symbol for fb_invocation */
+%type <list> param_assignment_list
+
+%token ASSIGN
+%token SENDTO /* "=>" */
+%token RETURN
+
+
+/********************************/
+/* B 3.2.3 Selection Statements */
+/********************************/
+%type <leaf> selection_statement
+%type <leaf> if_statement
+%type <leaf> case_statement
+%type <leaf> case_element
+%type <list> case_list
+%type <leaf> case_list_element
+/* helper symbol for if_statement */
+%type <list> elseif_statement_list
+/* helper symbol for elseif_statement_list */
+%type <leaf> elseif_statement
+/* helper symbol for case_statement */
+%type <list> 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 <leaf> iteration_statement
+%type <leaf> for_statement
+%type <leaf> control_variable
+%type <leaf> while_statement
+%type <leaf> repeat_statement
+%type <leaf> exit_statement
+/* Integrated directly into for_statement */
+// %type <leaf> 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
+
+%%
+
+
+
+
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+/********************************************************/
+
+
+
+
+
+/*****************************/
+/* Prelimenary constructs... */
+/*****************************/
+start:
+ library {$$ = $1;}
+;
+
+/* the pragmas... */
+pragma:
+ pragma_token {$$ = new pragma_c($1);}
+
+
+
+/* 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);};
+prev_declared_fb_name: prev_declared_fb_name_token {$$ = new identifier_c($1);};
+
+prev_declared_simple_type_name: prev_declared_simple_type_name_token {$$ = new identifier_c($1);};
+prev_declared_subrange_type_name: prev_declared_subrange_type_name_token {$$ = new identifier_c($1);};
+prev_declared_enumerated_type_name: prev_declared_enumerated_type_name_token {$$ = new identifier_c($1);};
+prev_declared_array_type_name: prev_declared_array_type_name_token {$$ = new identifier_c($1);};
+prev_declared_structure_type_name: prev_declared_structure_type_name_token {$$ = new identifier_c($1);};
+prev_declared_string_type_name: prev_declared_string_type_name_token {$$ = new identifier_c($1);};
+
+prev_declared_derived_function_name: prev_declared_derived_function_name_token {$$ = new identifier_c($1);};
+prev_declared_derived_function_block_name: prev_declared_derived_function_block_name_token {$$ = new identifier_c($1);};
+prev_declared_program_type_name: prev_declared_program_type_name_token {$$ = new identifier_c($1);};
+
+
+
+
+
+/***************************/
+/* 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 error
+ {$$ = NULL;
+ print_err_msg(current_filename, @2.last_line, "unknown error.");
+ /* yychar */
+ yyerrok;
+ }
+;
+
+
+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...
+ * BUT, the lexical parser will interpret these names as tokens (keywords).
+ * To allow these names to be used as function names, variable names, etc...,
+ * I (Mario) have augmented the definition of identifier to also include the tokens
+ * that are not explicitly defined as keywords in the spec!!
+ *
+ *
+ *
+ *
+ * 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);}
+/* Make sure that all tokens (names) not defined as keywords are included here...
+ * I (Mario) have already done this, but if any changes are made to this file,
+ * this list MUST be kept consistent!!
+ */
+/**/
+| PRIORITY {$$ = new identifier_c(strdup("PRIORITY"));}
+| SINGLE {$$ = new identifier_c(strdup("SINGLE"));}
+| INTERVAL {$$ = new identifier_c(strdup("INTERVAL"));}
+/**/
+| LD_operator {$$ = il_operator_c_2_identifier_c($1);}
+| LDN_operator {$$ = il_operator_c_2_identifier_c($1);}
+| ST_operator {$$ = il_operator_c_2_identifier_c($1);}
+| STN_operator {$$ = il_operator_c_2_identifier_c($1);}
+| S_operator {$$ = il_operator_c_2_identifier_c($1);}
+| R_operator {$$ = il_operator_c_2_identifier_c($1);}
+| S1_operator {$$ = il_operator_c_2_identifier_c($1);}
+| R1_operator {$$ = il_operator_c_2_identifier_c($1);}
+| CLK_operator {$$ = il_operator_c_2_identifier_c($1);}
+| CU_operator {$$ = il_operator_c_2_identifier_c($1);}
+| CD_operator {$$ = il_operator_c_2_identifier_c($1);}
+| PV_operator {$$ = il_operator_c_2_identifier_c($1);}
+| IN_operator {$$ = il_operator_c_2_identifier_c($1);}
+| PT_operator {$$ = il_operator_c_2_identifier_c($1);}
+| ANDN_operator {$$ = il_operator_c_2_identifier_c($1);}
+/* NOTE: ANDN2_operator corresponds to the string '&N' in the source code!
+ * This is __not__ a valid name, so it is omitted from this list!!
+ *| ANDN2_operator {$$ = il_operator_c_2_identifier_c($1);}
+ */
+/* NOTE: 'AND' is a keyword, so should not appear on this list... */
+| ORN_operator {$$ = il_operator_c_2_identifier_c($1);}
+| XORN_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);}
+| 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);}
+| CAL_operator {$$ = il_operator_c_2_identifier_c($1);}
+| CALC_operator {$$ = il_operator_c_2_identifier_c($1);}
+| CALCN_operator {$$ = il_operator_c_2_identifier_c($1);}
+| RET_operator {$$ = il_operator_c_2_identifier_c($1);}
+| RETC_operator {$$ = il_operator_c_2_identifier_c($1);}
+| RETCN_operator {$$ = il_operator_c_2_identifier_c($1);}
+| JMP_operator {$$ = il_operator_c_2_identifier_c($1);}
+| JMPC_operator {$$ = il_operator_c_2_identifier_c($1);}
+| JMPCN_operator {$$ = il_operator_c_2_identifier_c($1);}
+/**/
+| L {$$ = new identifier_c(strdup("L"));}
+| D {$$ = new identifier_c(strdup("D"));}
+| SD {$$ = new identifier_c(strdup("SD"));}
+| DS {$$ = new identifier_c(strdup("DS"));}
+| SL {$$ = new identifier_c(strdup("SL"));}
+| N {$$ = new identifier_c(strdup("N"));}
+/* NOTE: the following two clash with the R and S IL operators.
+ * It will have to be handled when we include parsing of SFC...
+ */
+/*
+| R {$$ = new identifier_c(strdup("R"));}
+| S {$$ = new identifier_c(strdup("S"));}
+*/
+| P {$$ = new identifier_c(strdup("P"));}
+
+;
+
+/*********************/
+/* B 1.2 - Constants */
+/*********************/
+constant:
+ numeric_literal
+| character_string
+| time_literal
+| bit_string_literal
+| boolean_literal
+/* 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
+ * either 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
+;
+
+/* a helper symbol for expression */
+/* A constant without any preceding '-', but may
+ * include a preceding '+' !
+ */
+non_negative_constant:
+ non_negative_numeric_literal
+| character_string
+| time_literal
+| bit_string_literal
+| boolean_literal
+| non_negative_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, intger '.' 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);}
+| fixed_point_token {$$ = new real_c($1);}
+;
+
+integer: integer_token {$$ = new integer_c($1);};
+binary_integer: binary_integer_token {$$ = new binary_integer_c($1);};
+octal_integer: octal_integer_token {$$ = new octal_integer_c($1);};
+hex_integer: hex_integer_token {$$ = new hex_integer_c($1);};
+
+numeric_literal:
+ integer_literal
+| real_literal
+;
+
+/* helper symbol for non_negative_constant */
+non_negative_numeric_literal:
+ integer_literal
+| non_negative_real_literal
+;
+
+
+integer_literal:
+ integer_type_name '#' signed_integer
+ {$$ = new integer_literal_c($1, $3);}
+| integer_type_name '#' binary_integer
+ {$$ = new integer_literal_c($1, $3);}
+| integer_type_name '#' octal_integer
+ {$$ = new integer_literal_c($1, $3);}
+| integer_type_name '#' hex_integer
+ {$$ = new integer_literal_c($1, $3);}
+/* NOTE: see note in the definition of constant for reason
+ * why signed_integer, binary_integer, octal_integer
+ * and hex_integer are missing here!
+ */
+;
+
+signed_integer:
+ integer
+| '+' integer {$$ = $2;}
+| '-' integer {$$ = new neg_expression_c($2);}
+;
+
+/* a helper symbol for non_negative_constant */
+/* A integer without any preceding '-', but may
+ * include a preceding '+' !
+ */
+non_negative_signed_integer:
+ integer
+| '+' integer {$$ = $2;}
+;
+
+
+real_literal:
+ signed_real
+| real_type_name '#' signed_real
+ {$$ = new real_literal_c($1, $3);}
+;
+
+/* helper symbol for non_negative_numeric_literal */
+non_negative_real_literal:
+ non_negative_signed_real
+| real_type_name '#' signed_real
+ {$$ = new real_literal_c($1, $3);}
+;
+
+signed_real:
+ real
+| '+' real {$$ = $2;}
+| '-' real {$$ = new neg_expression_c($2);}
+;
+
+/* helper symbol for non_negative_real_literal */
+non_negative_signed_real:
+ real
+| '+' real {$$ = $2;}
+;
+
+
+bit_string_literal:
+ bit_string_type_name '#' integer /* i.e. unsigned_integer */
+ {$$ = new bit_string_literal_c($1, $3);}
+| bit_string_type_name '#' binary_integer
+ {$$ = new bit_string_literal_c($1, $3);}
+| bit_string_type_name '#' octal_integer
+ {$$ = new bit_string_literal_c($1, $3);}
+| bit_string_type_name '#' hex_integer
+ {$$ = new bit_string_literal_c($1, $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!
+ */
+;
+
+
+boolean_literal:
+ TRUE {$$ = new boolean_literal_c(new bool_type_name_c(),
+ new boolean_true_c());}
+| FALSE {$$ = new boolean_literal_c(new bool_type_name_c(),
+ new boolean_false_c());}
+/*
+| 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);};
+
+double_byte_character_string: double_byte_character_string_token
+ {$$ = new double_byte_character_string_c($1);};
+
+
+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(NULL, $3);}
+| TIME '#' '-' interval
+ {$$ = new duration_c(new neg_time_c(), $4);}
+| T_SHARP interval
+ {$$ = new duration_c(NULL, $2);}
+| T_SHARP '-' interval
+ {$$ = new duration_c(new neg_time_c(), $3);}
+;
+
+
+interval:
+ days
+| hours
+| minutes
+| seconds
+| milliseconds
+;
+
+integer_d: integer_d_token {$$ = new integer_c($1);};
+integer_h: integer_h_token {$$ = new integer_c($1);};
+integer_m: integer_m_token {$$ = new integer_c($1);};
+integer_s: integer_s_token {$$ = new integer_c($1);};
+integer_ms: integer_ms_token {$$ = new integer_c($1);};
+
+fixed_point_d:
+ fixed_point_d_token
+ {$$ = new fixed_point_c($1);}
+| integer_d
+;
+
+fixed_point_h:
+ fixed_point_h_token
+ {$$ = new fixed_point_c($1);}
+| integer_h
+;
+
+fixed_point_m:
+ fixed_point_m_token
+ {$$ = new fixed_point_c($1);}
+| integer_m
+;
+
+fixed_point_s:
+ fixed_point_s_token
+ {$$ = new fixed_point_c($1);}
+| integer_s
+;
+
+fixed_point_ms:
+ fixed_point_ms_token
+ {$$ = new fixed_point_c($1);}
+| integer_ms
+;
+
+
+fixed_point:
+ fixed_point_token
+ {$$ = new fixed_point_c($1);}
+| integer
+;
+
+
+days:
+/* fixed_point ('d') */
+ fixed_point_d
+ {$$ = new days_c($1, NULL);}
+/*| integer ('d') ['_'] hours */
+| integer_d hours
+ {$$ = new days_c($1, $2);}
+| integer_d '_' hours
+ {$$ = new days_c($1, $3);}
+;
+
+
+hours:
+/* fixed_point ('h') */
+ fixed_point_h
+ {$$ = new hours_c($1, NULL);}
+/*| integer ('h') ['_'] minutes */
+| integer_h minutes
+ {$$ = new hours_c($1, $2);}
+| integer_h '_' minutes
+ {$$ = new hours_c($1, $3);}
+;
+
+minutes:
+/* fixed_point ('m') */
+ fixed_point_m
+ {$$ = new minutes_c($1, NULL);}
+/*| integer ('m') ['_'] seconds */
+| integer_m seconds
+ {$$ = new minutes_c($1, $2);}
+| integer_m '_' seconds
+ {$$ = new minutes_c($1, $3);}
+;
+
+seconds:
+/* fixed_point ('s') */
+ fixed_point_s
+ {$$ = new seconds_c($1, NULL);}
+/*| integer ('s') ['_'] milliseconds */
+| integer_s milliseconds
+ {$$ = new seconds_c($1, $2);}
+| integer_s '_' milliseconds
+ {$$ = new seconds_c($1, $3);}
+;
+
+milliseconds:
+/* fixed_point ('ms') */
+ fixed_point_ms
+ {$$ = new milliseconds_c($1);}
+;
+
+
+
+/************************************/
+/* B 1.2.3.2 - Time of day and Date */
+/************************************/
+time_of_day:
+ TIME_OF_DAY '#' daytime
+ {$$ = new time_of_day_c($3);}
+;
+
+
+daytime:
+ day_hour ':' day_minute ':' day_second
+ {$$ = new daytime_c($1, $3, $5);}
+;
+
+
+day_hour: integer;
+day_minute: integer;
+day_second: fixed_point;
+
+
+date:
+ DATE '#' date_literal
+ {$$ = new date_c($3);}
+| D_SHARP date_literal
+ {$$ = new date_c($2);}
+;
+
+
+date_literal:
+ year '-' month '-' day
+ {$$ = new date_literal_c($1, $3, $5);}
+;
+
+
+year: integer;
+month: integer;
+day: integer;
+
+
+date_and_time:
+ DATE_AND_TIME '#' date_literal '-' daytime
+ {$$ = new date_and_time_c($3, $5);}
+;
+
+
+
+
+
+
+/**********************/
+/* 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 */
+/***********************************/
+elementary_type_name:
+ numeric_type_name
+| date_type_name
+| bit_string_type_name
+| elementary_string_type_name
+| TIME {$$ = new time_type_name_c();}
+| BOOL {$$ = new bool_type_name_c();}
+/* 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.
+ */
+;
+
+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();}
+| INT {$$ = new int_type_name_c();}
+| DINT {$$ = new dint_type_name_c();}
+| LINT {$$ = new lint_type_name_c();}
+;
+
+unsigned_integer_type_name:
+ USINT {$$ = new usint_type_name_c();}
+| UINT {$$ = new uint_type_name_c();}
+| UDINT {$$ = new udint_type_name_c();}
+| ULINT {$$ = new ulint_type_name_c();}
+;
+
+real_type_name:
+ REAL {$$ = new real_type_name_c();}
+| LREAL {$$ = new lreal_type_name_c();}
+;
+
+date_type_name:
+ DATE {$$ = new date_type_name_c();}
+| TIME_OF_DAY {$$ = new tod_type_name_c();}
+| TOD {$$ = new tod_type_name_c();}
+| DATE_AND_TIME {$$ = new dt_type_name_c();}
+| DT {$$ = new dt_type_name_c();}
+;
+
+
+bit_string_type_name:
+ BYTE {$$ = new byte_type_name_c();}
+| WORD {$$ = new word_type_name_c();}
+| DWORD {$$ = new dword_type_name_c();}
+| LWORD {$$ = new lword_type_name_c();}
+/* 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();}
+| WSTRING {$$ = new wstring_type_name_c();}
+;
+
+
+
+/********************************/
+/* B 1.3.2 - Generic data types */
+/********************************/
+/* Strangely, the following symbol does 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 {$$ = $1;}
+| prev_declared_structure_type_name {$$ = $1;}
+| prev_declared_string_type_name {$$ = $1;}
+;
+
+single_element_type_name:
+ prev_declared_simple_type_name {$$ = $1;}
+/* 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 {$$ = $1;}
+| prev_declared_subrange_type_name {$$ = $1;}
+| prev_declared_enumerated_type_name {$$ = $1;}
+;
+
+/* 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);}
+;
+
+/* helper symbol for data_type_declaration */
+type_declaration_list:
+ type_declaration ';'
+ {$$ = new type_declaration_list_c(); $$->add_element($1);}
+| type_declaration_list type_declaration ';'
+ {$$ = $1; $$->add_element($2);}
+;
+
+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);
+ library_element_symtable.insert($1, prev_declared_simple_type_name_token);
+ }
+;
+
+
+simple_spec_init:
+ simple_specification
+ /* The following line was changed 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);}
+| prev_declared_simple_type_name ASSIGN constant
+ {$$ = new simple_spec_init_c($1, $3);}
+;
+
+/* 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);}
+| prev_declared_simple_type_name
+ {$$ = new simple_spec_init_c($1, NULL);}
+;
+
+
+subrange_type_declaration:
+/* subrange_type_name ':' subrange_spec_init */
+ identifier ':' subrange_spec_init
+ {$$ = new subrange_type_declaration_c($1, $3);
+ library_element_symtable.insert($1, prev_declared_subrange_type_name_token);
+ }
+;
+
+subrange_spec_init:
+ subrange_specification
+ {$$ = new subrange_spec_init_c($1, NULL);}
+| subrange_specification ASSIGN signed_integer
+ {$$ = new subrange_spec_init_c($1, $3);}
+;
+
+subrange_specification:
+ integer_type_name '(' subrange')'
+ {$$ = new subrange_specification_c($1, $3);}
+| prev_declared_subrange_type_name {$$ = $1;}
+;
+
+
+subrange:
+ signed_integer DOTDOT signed_integer
+ {$$ = new subrange_c($1, $3);}
+;
+
+enumerated_type_declaration:
+/* enumerated_type_name ':' enumerated_spec_init */
+ identifier ':' enumerated_spec_init
+ {$$ = new enumerated_type_declaration_c($1, $3);
+ library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);
+ }
+;
+
+
+enumerated_spec_init:
+ enumerated_specification
+ {$$ = new enumerated_spec_init_c($1, NULL);}
+| enumerated_specification ASSIGN enumerated_value
+ {$$ = new enumerated_spec_init_c($1, $3);}
+;
+
+enumerated_specification:
+ '(' enumerated_value_list ')'
+ {$$ = $2;}
+| prev_declared_enumerated_type_name {$$ = $1;}
+;
+
+/* helper symbol for enumerated_specification */
+enumerated_value_list:
+ enumerated_value
+ {$$ = new enumerated_value_list_c(); $$->add_element($1);}
+| enumerated_value_list ',' enumerated_value
+ {$$ = $1; $$->add_element($3);}
+;
+
+
+enumerated_value:
+ identifier
+ {$$ = $1;}
+| prev_declared_enumerated_type_name '#' any_identifier
+ {$$ = new enumerated_value_c($1, $3);}
+;
+
+
+
+array_type_declaration:
+/* array_type_name ':' array_spec_init */
+ identifier ':' array_spec_init
+ {$$ = new array_type_declaration_c($1, $3);
+ library_element_symtable.insert($1, prev_declared_array_type_name_token);
+ }
+;
+
+array_spec_init:
+ array_specification
+ {$$ = new array_spec_init_c($1, NULL);}
+| array_specification ASSIGN array_initialization
+ {$$ = new array_spec_init_c($1, $3);}
+;
+
+
+array_specification:
+ prev_declared_array_type_name
+ {$$ = $1;}
+| ARRAY '[' array_subrange_list ']' OF non_generic_type_name
+ {$$ = new array_specification_c($3, $6);}
+;
+
+/* helper symbol for array_specification */
+array_subrange_list:
+ subrange
+ {$$ = new array_subrange_list_c(); $$->add_element($1);}
+| array_subrange_list ',' subrange
+ {$$ = $1; $$->add_element($1);}
+;
+
+
+array_initialization:
+ '[' array_initial_elements_list ']'
+ {$$ = $2;}
+;
+
+
+/* helper symbol for array_initialization */
+array_initial_elements_list:
+ array_initial_elements
+ {$$ = new array_initial_elements_list_c(); $$->add_element($1);}
+| array_initial_elements_list ',' array_initial_elements
+ {$$ = $1; $$->add_element($3);}
+;
+
+
+array_initial_elements:
+ array_initial_element
+| integer '(' ')'
+| integer '(' array_initial_element ')'
+ {$$ = new array_initial_elements_c($1, $3);}
+;
+
+
+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);
+ library_element_symtable.insert($1, prev_declared_structure_type_name_token);
+ }
+;
+
+
+structure_specification:
+ structure_declaration
+| initialized_structure
+;
+
+
+initialized_structure:
+ prev_declared_structure_type_name
+ {$$ = new initialized_structure_c($1, NULL);}
+| prev_declared_structure_type_name ASSIGN structure_initialization
+ {$$ = new initialized_structure_c($1, $3);}
+;
+
+
+structure_declaration:
+ STRUCT structure_element_declaration_list END_STRUCT
+ {$$ = $2;}
+;
+
+/* helper symbol for structure_declaration */
+structure_element_declaration_list:
+ structure_element_declaration ';'
+ {$$ = new structure_element_declaration_list_c(); $$->add_element($1);}
+| structure_element_declaration_list structure_element_declaration ';'
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+structure_element_declaration:
+ structure_element_name ':' simple_spec_init
+ {$$ = new structure_element_declaration_c($1, $3);}
+| structure_element_name ':' subrange_spec_init
+ {$$ = new structure_element_declaration_c($1, $3);}
+| structure_element_name ':' enumerated_spec_init
+ {$$ = new structure_element_declaration_c($1, $3);}
+| structure_element_name ':' array_spec_init
+ {$$ = new structure_element_declaration_c($1, $3);}
+| structure_element_name ':' initialized_structure
+ {$$ = new structure_element_declaration_c($1, $3);}
+;
+
+
+structure_element_name: any_identifier;
+
+
+structure_initialization:
+ '(' structure_element_initialization_list ')'
+ {$$ = $2;}
+;
+
+/* helper symbol for structure_initialization */
+structure_element_initialization_list:
+ structure_element_initialization
+ {$$ = new structure_element_initialization_list_c(); $$->add_element($1);}
+| structure_element_initialization_list ',' structure_element_initialization
+ {$$ = $1; $$->add_element($3);}
+;
+
+
+structure_element_initialization:
+ structure_element_name ASSIGN constant
+ {$$ = new structure_element_initialization_c($1, $3);}
+| structure_element_name ASSIGN enumerated_value
+ {$$ = new structure_element_initialization_c($1, $3);}
+| structure_element_name ASSIGN array_initialization
+ {$$ = new structure_element_initialization_c($1, $3);}
+| structure_element_name ASSIGN structure_initialization
+ {$$ = new structure_element_initialization_c($1, $3);}
+;
+
+/* 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);
+ 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 '[' <size> ']'
+ * 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 */
+/*********************/
+variable:
+ symbolic_variable
+| direct_variable
+;
+
+
+symbolic_variable:
+/* NOTE: To be entirely correct, variable_name should be replacemed by
+ * prev_declared_variable_name | prev_declared_fb_name | prev_declared_global_var_name
+ */
+ prev_declared_variable_name
+ {$$ = new symbolic_variable_c($1);}
+| prev_declared_fb_name
+ {$$ = new symbolic_variable_c($1);}
+| prev_declared_global_var_name
+ {$$ = new symbolic_variable_c($1);}
+| multi_element_variable
+;
+
+
+/* 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);}
+| any_multi_element_variable
+;
+
+
+/* for yet undeclared variable names ! */
+variable_name: identifier;
+
+
+
+
+
+/********************************************/
+/* B.1.4.1 Directly Represented Variables */
+/********************************************/
+direct_variable: direct_variable_token {$$ = new direct_variable_c($1);};
+
+
+
+
+/*************************************/
+/* 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);}
+;
+
+/* please see note above any_symbolic_variable */
+any_array_variable:
+ any_subscripted_variable '[' subscript_list ']'
+ {$$ = new array_variable_c($1, $3);}
+;
+
+
+subscripted_variable:
+ symbolic_variable
+;
+
+
+/* please see note above any_symbolic_variable */
+any_subscripted_variable:
+ any_symbolic_variable
+;
+
+
+subscript_list:
+ subscript
+ {$$ = new subscript_list_c(); $$->add_element($1);}
+| subscript_list ',' subscript
+ {$$ = $1; $$->add_element($3);}
+;
+
+
+subscript: expression;
+
+
+structured_variable:
+ record_variable '.' field_selector
+ {$$ = new structured_variable_c($1, $3);}
+;
+
+
+/* please see note above any_symbolic_variable */
+any_structured_variable:
+ any_record_variable '.' field_selector
+ {$$ = new structured_variable_c($1, $3);}
+;
+
+
+
+record_variable:
+ symbolic_variable
+;
+
+
+/* please see note above any_symbolic_variable */
+any_record_variable:
+ any_symbolic_variable
+;
+
+
+field_selector: any_identifier;
+
+
+
+
+
+
+/******************************************/
+/* B 1.4.3 - Declaration & Initialisation */
+/******************************************/
+input_declarations:
+ VAR_INPUT input_declaration_list END_VAR
+ {$$ = new input_declarations_c(NULL, $2);}
+| VAR_INPUT RETAIN input_declaration_list END_VAR
+ {$$ = new input_declarations_c(new retain_option_c(), $3);}
+| VAR_INPUT NON_RETAIN input_declaration_list END_VAR
+ {$$ = new input_declarations_c(new non_retain_option_c(), $3);}
+;
+
+/* helper symbol for input_declarations */
+input_declaration_list:
+ input_declaration ';'
+ {$$ = new input_declaration_list_c(); $$->add_element($1);}
+| input_declaration_list input_declaration ';'
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+input_declaration:
+ var_init_decl
+| edge_declaration
+;
+
+
+edge_declaration:
+ var1_list ':' BOOL R_EDGE
+ {$$ = new edge_declaration_c(new raising_edge_option_c(), $1);}
+| var1_list ':' BOOL F_EDGE
+ {$$ = new edge_declaration_c(new falling_edge_option_c(), $1);}
+;
+
+
+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);}
+| var1_list ':' subrange_spec_init
+ {$$ = new var1_init_decl_c($1, $3);}
+| var1_list ':' enumerated_spec_init
+ {$$ = new var1_init_decl_c($1, $3);}
+;
+
+
+var1_list:
+ variable_name
+ {$$ = new var1_list_c(); $$->add_element($1);
+ variable_name_symtable.insert($1, prev_declared_variable_name_token);
+ }
+ | var1_list ',' variable_name
+ {$$ = $1; $$->add_element($3);
+ variable_name_symtable.insert($3, prev_declared_variable_name_token);
+ }
+;
+
+
+
+array_var_init_decl:
+ var1_list ':' array_spec_init
+ {$$ = new array_var_init_decl_c($1, $3);}
+;
+
+
+structured_var_init_decl:
+ var1_list ':' initialized_structure
+ {$$ = new structured_var_init_decl_c($1, $3);}
+;
+
+
+/* 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);}
+/*| 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);}
+;
+
+
+
+/* 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();
+ /* 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_init_decl_list END_VAR
+ {$$ = new output_declarations_c(NULL, $2);}
+| VAR_OUTPUT RETAIN var_init_decl_list END_VAR
+ {$$ = new output_declarations_c(new retain_option_c(), $3);}
+| VAR_OUTPUT NON_RETAIN var_init_decl_list END_VAR
+ {$$ = new output_declarations_c(new non_retain_option_c(), $3);}
+;
+
+
+
+input_output_declarations:
+ VAR_IN_OUT var_declaration_list END_VAR
+ {$$ = new input_output_declarations_c($2);}
+;
+
+
+
+/* helper symbol for input_output_declarations */
+var_declaration_list:
+ var_declaration ';'
+ {$$ = new var_declaration_list_c(); $$->add_element($1);}
+| var_declaration_list var_declaration ';'
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+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);}
+| var1_list ':' subrange_specification
+ {$$ = new var1_init_decl_c($1, $3);}
+| var1_list ':' enumerated_specification
+ {$$ = new var1_init_decl_c($1, $3);}
+;
+
+
+
+array_var_declaration:
+ var1_list ':' array_specification
+ {$$ = new array_var_declaration_c($1, $3);}
+;
+
+structured_var_declaration:
+ var1_list ':' prev_declared_structure_type_name
+ {$$ = new structured_var_declaration_c($1, $3);}
+;
+
+
+var_declarations:
+ VAR var_init_decl_list END_VAR
+ {$$ = new var_declarations_c(NULL, $2);}
+| VAR CONSTANT var_init_decl_list END_VAR
+ {$$ = new var_declarations_c(new constant_option_c(), $3);}
+;
+
+
+retentive_var_declarations:
+ VAR RETAIN var_init_decl_list END_VAR
+ {$$ = new retentive_var_declarations_c($3);}
+;
+
+
+located_var_declarations:
+ VAR located_var_decl_list END_VAR
+ {$$ = new located_var_declarations_c(NULL, $2);}
+| VAR CONSTANT located_var_decl_list END_VAR
+ {$$ = new located_var_declarations_c(new constant_option_c(), $3);}
+| VAR RETAIN located_var_decl_list END_VAR
+ {$$ = new located_var_declarations_c(new retain_option_c(), $3);}
+| VAR NON_RETAIN located_var_decl_list END_VAR
+ {$$ = new located_var_declarations_c(new non_retain_option_c(), $3);}
+;
+
+
+/* helper symbol for located_var_declarations */
+located_var_decl_list:
+ located_var_decl ';'
+ {$$ = new located_var_decl_list_c(); $$->add_element($1);}
+| located_var_decl_list located_var_decl ';'
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+located_var_decl:
+ variable_name location ':' located_var_spec_init
+ {$$ = new located_var_decl_c($1, $2, $4);
+ variable_name_symtable.insert($1, prev_declared_variable_name_token);
+ }
+| location ':' located_var_spec_init
+ {$$ = new located_var_decl_c(NULL, $1, $3);}
+;
+
+
+
+
+external_var_declarations:
+ VAR_EXTERNAL external_declaration_list END_VAR
+ {$$ = new external_var_declarations_c(NULL, $2);}
+| VAR_EXTERNAL CONSTANT external_declaration_list END_VAR
+ {$$ = new external_var_declarations_c(new constant_option_c(), $3);}
+;
+
+/* helper symbol for external_var_declarations */
+external_declaration_list:
+ external_declaration ';'
+ {$$ = new external_declaration_list_c(); $$->add_element($1);}
+| external_declaration_list external_declaration';'
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+external_declaration:
+ global_var_name ':' simple_specification
+ {$$ = new external_declaration_c($1, $3);
+ variable_name_symtable.insert($1, prev_declared_variable_name_token);
+ }
+| global_var_name ':' subrange_specification
+ {$$ = new external_declaration_c($1, $3);
+ variable_name_symtable.insert($1, prev_declared_variable_name_token);
+ }
+| global_var_name ':' enumerated_specification
+ {$$ = new external_declaration_c($1, $3);
+ variable_name_symtable.insert($1, prev_declared_variable_name_token);
+ }
+| global_var_name ':' array_specification
+ {$$ = new external_declaration_c($1, $3);
+ variable_name_symtable.insert($1, prev_declared_variable_name_token);
+ }
+| global_var_name ':' prev_declared_structure_type_name
+ {$$ = new external_declaration_c($1, $3);
+ variable_name_symtable.insert($1, prev_declared_variable_name_token);
+ }
+| global_var_name ':' function_block_type_name
+ {$$ = new external_declaration_c($1, $3);
+ variable_name_symtable.insert($1, prev_declared_fb_name_token);
+ }
+;
+
+
+global_var_name: identifier;
+
+
+global_var_declarations:
+ VAR_GLOBAL global_var_decl_list END_VAR
+ {$$ = new global_var_declarations_c(NULL, $2);}
+| VAR_GLOBAL CONSTANT global_var_decl_list END_VAR
+ {$$ = new global_var_declarations_c(new constant_option_c(), $3);}
+| VAR_GLOBAL RETAIN global_var_decl_list END_VAR
+ {$$ = new global_var_declarations_c(new retain_option_c(), $3);}
+;
+
+
+/* helper symbol for global_var_declarations */
+global_var_decl_list:
+ global_var_decl ';'
+ {$$ = new global_var_decl_list_c(); $$->add_element($1);}
+| global_var_decl_list global_var_decl ';'
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+global_var_decl:
+ global_var_spec ':'
+ {$$ = new global_var_decl_c($1, NULL);}
+| global_var_spec ':' located_var_spec_init
+ {$$ = new global_var_decl_c($1, $3);}
+| global_var_spec ':' function_block_type_name
+ {$$ = new global_var_decl_c($1, $3);}
+;
+
+
+global_var_spec:
+ global_var_list {$$ = $1;}
+| location
+| global_var_name location
+ {$$ = new global_var_spec_c($1, $2);
+ 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
+ {$$ = new location_c($2);}
+;
+
+
+
+global_var_list:
+ global_var_name
+ {$$ = new global_var_list_c(); $$->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);
+ }
+;
+
+
+
+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);}
+;
+
+/* 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($3, NULL);}
+/*
+| STRING ASSIGN single_byte_character_string
+ {$$ = new single_byte_string_spec_c(NULL, $3);}
+*/
+| STRING '[' integer ']' ASSIGN single_byte_character_string
+ {$$ = new single_byte_string_spec_c($3, $6);}
+;
+
+
+double_byte_string_var_declaration:
+ var1_list ':' double_byte_string_spec
+ {$$ = new double_byte_string_var_declaration_c($1, $3);}
+;
+
+double_byte_string_spec:
+/* WSTRING
+ {$$ = new double_byte_string_spec_c(NULL, NULL);}
+*/
+ WSTRING '[' integer ']'
+ {$$ = new double_byte_string_spec_c($3, NULL);}
+/*
+| WSTRING ASSIGN double_byte_character_string
+ {$$ = new double_byte_string_spec_c(NULL, $3);}
+*/
+| WSTRING '[' integer ']' ASSIGN double_byte_character_string
+ {$$ = new double_byte_string_spec_c($3, $6);}
+;
+
+
+
+incompl_located_var_declarations:
+ VAR incompl_located_var_decl_list END_VAR
+ {$$ = new incompl_located_var_declarations_c(NULL, $2);}
+| VAR RETAIN incompl_located_var_decl_list END_VAR
+ {$$ = new incompl_located_var_declarations_c(new retain_option_c(), $3);}
+| VAR NON_RETAIN incompl_located_var_decl_list END_VAR
+ {$$ = new incompl_located_var_declarations_c(new non_retain_option_c(), $3);}
+;
+
+/* helper symbol for incompl_located_var_declarations */
+incompl_located_var_decl_list:
+ incompl_located_var_decl ';'
+ {$$ = new incompl_located_var_decl_list_c(); $$->add_element($1);}
+| incompl_located_var_decl_list incompl_located_var_decl ';'
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+incompl_located_var_decl:
+ variable_name incompl_location ':' var_spec
+ {$$ = new incompl_located_var_decl_c($1, $2, $4);}
+;
+
+
+incompl_location:
+ AT incompl_location_token
+ {$$ = new incompl_location_c($2);}
+;
+
+
+var_spec:
+ simple_specification
+| subrange_specification
+| enumerated_specification
+| array_specification
+| prev_declared_structure_type_name
+| string_spec
+;
+
+
+/* helper symbol for var_spec */
+/* NOTE: The constructs
+ *
+ * STRING
+ * and
+ * WSTRING
+ *
+ * were removed as they are already contained
+ * within a simple_specification.
+ */
+string_spec:
+/* STRING
+ {$$ = new single_byte_string_spec_c(NULL, NULL);}
+*/
+ STRING '[' integer ']'
+ {$$ = new single_byte_string_spec_c($3, NULL);}
+/*
+| WSTRING
+ {$$ = new double_byte_string_spec_c(NULL, NULL);}
+*/
+| WSTRING '[' integer ']'
+ {$$ = new double_byte_string_spec_c($3, NULL);}
+;
+
+
+
+
+/* intermediate helper symbol for:
+ * - non_retentive_var_decls
+ * - output_declarations
+ * - var_declarations
+ */
+var_init_decl_list:
+ var_init_decl ';'
+ {$$ = new var_init_decl_list_c(); $$->add_element($1);}
+| var_init_decl_list var_init_decl ';'
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+
+
+/***********************/
+/* B 1.5.1 - Functions */
+/***********************/
+/* 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;
+
+/*
+function_name:
+ prev_declared_derived_function_name
+| standard_function_name
+;
+*/
+
+/* 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);}
+;
+
+
+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"));}
+;
+
+/* 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_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 (not(allow_function_overloading))
+ ERROR;
+ }
+;
+
+
+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);
+ variable_name_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);
+ variable_name_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);
+ }
+ }
+;
+
+/* 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);
+ }
+;
+
+
+
+/* intermediate helper symbol for function_declaration */
+io_OR_function_var_declarations_list:
+ /* empty */
+ {$$ = new var_declarations_list_c();}
+| 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);}
+;
+
+
+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(), $3);}
+| VAR var2_init_decl_list END_VAR
+ {$$ = new function_var_decls_c(NULL, $2);}
+;
+
+/* intermediate helper symbol for function_var_decls */
+var2_init_decl_list:
+ var2_init_decl ';'
+ {$$ = new var2_init_decl_list_c(); $$->add_element($1);}
+| var2_init_decl_list var2_init_decl ';'
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+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);};
+
+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);
+ 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();
+ }
+;
+
+
+
+/* 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:
+ /* empty */
+ {$$ = new var_declarations_list_c();}
+| 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);}
+;
+
+/* 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);}
+;
+
+
+/* intermediate helper symbol for temp_var_decls */
+temp_var_decls_list:
+ temp_var_decl ';'
+ {$$ = new temp_var_decls_list_c(); $$->add_element($1);}
+| temp_var_decls_list temp_var_decl ';'
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+non_retentive_var_decls:
+ VAR NON_RETAIN var_init_decl_list END_VAR
+ {$$ = new non_retentive_var_decls_c($3);}
+;
+
+
+
+function_block_body:
+ statement_list {$$ = $1;}
+| instruction_list {$$ = $1;}
+/*
+| sequential_function_chart
+| ladder_diagram
+| function_block_diagram
+| <other languages>
+*/
+;
+
+
+
+
+/**********************/
+/* 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);
+ 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();
+ }
+;
+
+
+/* helper symbol for program_declaration */
+/*
+ * NOTE: we re-use the var_declarations_list_c
+ */
+program_var_declarations_list:
+ /* empty */
+ {$$ = new var_declarations_list_c();}
+| 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);}
+*/
+;
+
+
+/* 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 */
+/********************************************/
+/* TODO ... */
+
+/*
+sequential_function_chart:
+ sfc_network
+| sequential_function_chart sfc_network
+;
+
+sfc_network:
+ initial_step
+| sfc_network step
+| sfc_network transition
+| sfc_network action
+;
+
+initial_step:
+ INITIAL_STEP step_name ':' action_association_list END_STEP
+;
+
+step:
+ STEP step_name ':' action_association_list END_STEP
+;
+
+/* helper symbol for:
+ * - initial_step
+ * - step
+ *
+action_association_list:
+ /* empty *
+| action_association_list action_association ';'
+;
+
+step_name: identifier;
+
+action_association:
+ action_name '(' action_qualifier indicator_name_list ')'
+;
+
+/* helper symbol for action_association *
+indicator_name_list:
+ /* empty *
+| indicator_name_list ',' indicator_name
+;
+
+action_name: identifier;
+
+action_qualifier:
+ /* empty *
+| N
+| R
+| S
+| P
+| timed_qualifier ',' action_time
+;
+
+timed_qualifier:
+ L
+| D
+| SD
+| DS
+| SL
+;
+
+action_time:
+ duration
+| variable_name
+;
+
+indicator_name: variable_name;
+
+transition:
+ TRANSITION FROM steps TO steps transition_condition END_TRANSITION
+| TRANSITION transition_name FROM steps TO steps transition_condition END_TRANSITION
+| TRANSITION '(' PRIORITY ASSIGN integer ')' FROM steps TO steps transition_condition END_TRANSITION
+| TRANSITION transition_name '(' PRIORITY ASSIGN integer ')' FROM steps TO steps transition_condition END_TRANSITION
+;
+
+transition_name: identifier;
+
+steps:
+ step_name
+| '(' step_name_list ')'
+;
+
+
+step_name_list:
+ step_name ',' step_name
+| step_name_list ',' step_name
+;
+
+
+transition_condition:
+ ':' simple_instruction_list
+| ASSIGN expression ';'
+| ':' fbd_network
+| ':' rung
+;
+
+action:
+ ACTION action_name ':' function_block_body END_ACTION
+;
+*/
+
+/********************************/
+/* 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_delcared_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);};
+prev_declared_resource_name: prev_declared_resource_name_token {$$ = new identifier_c($1);};
+prev_declared_program_name: prev_declared_program_name_token {$$ = new identifier_c($1);};
+// prev_declared_task_name: prev_declared_task_name_token {$$ = new identifier_c($1);};
+
+
+
+
+
+
+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();}
+ optional_access_declarations
+ optional_instance_specific_initializations
+ END_CONFIGURATION
+ {$$ = new configuration_declaration_c($2, $3, $4, $6, $7);
+ library_element_symtable.insert($2, prev_declared_configuration_name_token);
+ variable_name_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);
+ library_element_symtable.insert($2, prev_declared_configuration_name_token);
+ variable_name_symtable.pop();
+ }
+| CONFIGURATION error END_CONFIGURATION
+ {$$ = NULL;
+ print_err_msg(current_filename, @2.last_line, "error in configuration declaration.");
+ /* yychar */
+ yyerrok;
+ }
+;
+
+// 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(); $$->add_element($1);}
+| resource_declaration_list resource_declaration
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+resource_declaration:
+ RESOURCE {variable_name_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);
+ variable_name_symtable.pop();
+ variable_name_symtable.insert($3, prev_declared_resource_name_token);
+ }
+;
+
+
+single_resource_declaration:
+ task_configuration_list program_configuration_list
+ {$$ = new single_resource_declaration_c($1, $2);}
+;
+
+
+// helper symbol for single_resource_declaration //
+task_configuration_list:
+ // empty
+ {$$ = new task_configuration_list_c();}
+| task_configuration_list task_configuration ';'
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+// helper symbol for single_resource_declaration //
+program_configuration_list:
+ program_configuration ';'
+ {$$ = new program_configuration_list_c(); $$->add_element($1);}
+| program_configuration_list program_configuration ';'
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+resource_name: identifier;
+
+/*
+access_declarations:
+ VAR_ACCESS access_declaration_list END_VAR
+ {$$ = NULL;}
+;
+
+// helper symbol for access_declarations //
+access_declaration_list:
+ access_declaration ';'
+| access_declaration_list access_declaration ';'
+;
+
+
+access_declaration:
+ access_name ':' access_path ':' non_generic_type_name
+| access_name ':' access_path ':' non_generic_type_name direction
+;
+
+
+access_path:
+ direct_variable
+| prev_delcared_resource_name '.' direct_variable
+| any_fb_name_list symbolic_variable
+| prev_delcared_resource_name '.' any_fb_name_list symbolic_variable
+| prev_delcared_program_name '.' any_fb_name_list symbolic_variable
+| prev_delcared_resource_name '.' prev_delcared_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();}
+//| 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);}
+| prev_declared_global_var_name '.' structure_element_name
+ {$$ = new global_var_reference_c(NULL, $1, $3);}
+| prev_declared_resource_name '.' prev_declared_global_var_name
+ {$$ = new global_var_reference_c($1, $3, NULL);}
+| prev_declared_resource_name '.' prev_declared_global_var_name '.' structure_element_name
+ {$$ = new global_var_reference_c($1, $3, $5);}
+;
+
+
+//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);}
+;
+
+program_name: identifier;
+
+/*
+direction:
+ READ_WRITE
+ {$$ = NULL;}
+| READ_ONLY
+ {$$ = NULL;}
+;
+*/
+
+task_configuration:
+ TASK task_name task_initialization
+ {$$ = new task_configuration_c($2, $3);}
+;
+
+/* NOTE: The specification does nopt 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 ')' //
+ '(' PRIORITY ASSIGN integer ')'
+ {$$ = new task_initialization_c(NULL, NULL, $4);}
+| '(' SINGLE ASSIGN data_source ',' PRIORITY ASSIGN integer ')'
+ {$$ = new task_initialization_c($4, NULL, $8);}
+| '(' INTERVAL ASSIGN data_source ',' PRIORITY ASSIGN integer ')'
+ {$$ = new task_initialization_c(NULL, $4, $8);}
+| '(' SINGLE ASSIGN data_source ',' INTERVAL ASSIGN data_source ',' PRIORITY ASSIGN integer ')'
+ {$$ = new task_initialization_c($4, $8, $12);}
+;
+
+data_source:
+ constant
+| global_var_reference
+| program_output_reference
+| 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);
+ 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(), $3, $4, $6, $7);
+ 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(), $3, $4, $6, $7);
+ variable_name_symtable.insert($3, prev_declared_program_name_token);
+ }
+;
+
+// helper symbol for program_configuration //
+optional_task_name:
+ // empty //
+ {$$ = NULL;}
+| WITH task_name
+ {$$ = $2;}
+;
+
+// helper symbol for program_configuration //
+optional_prog_conf_elements:
+ // empty //
+ {$$ = NULL;}
+| '(' prog_conf_elements ')'
+ {$$ = $2;}
+;
+
+
+prog_conf_elements:
+ prog_conf_element
+ {$$ = new prog_conf_elements_c(); $$->add_element($1);}
+| prog_conf_elements ',' prog_conf_element
+ {$$ = $1; $$->add_element($3);}
+;
+
+
+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);}
+;
+
+
+/* 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);}
+| any_symbolic_variable SENDTO data_sink
+ {$$ = new prog_cnxn_sendto_c($1, $3);}
+;
+
+prog_data_source:
+ constant
+| enumerated_value
+| global_var_reference
+| direct_variable
+;
+
+data_sink:
+ global_var_reference
+| direct_variable
+;
+
+instance_specific_initializations:
+ VAR_CONFIG instance_specific_init_list END_VAR
+ {$$ = new instance_specific_initializations_c($2);}
+;
+
+// helper symbol for instance_specific_initializations //
+instance_specific_init_list:
+ instance_specific_init ';'
+ {$$ = new instance_specific_init_list_c(); $$->add_element($1);}
+| instance_specific_init_list instance_specific_init ';'
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+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);}
+| 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);}
+| 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);}
+;
+
+
+/* helper symbol for instance_specific_init */
+fb_initialization:
+ function_block_type_name ASSIGN structure_initialization
+ {$$ = new fb_initialization_c($1, $3);}
+;
+
+/***********************************/
+/* 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
+;
+
+/*
+eol_list:
+ '\n'
+| eol_list '\n'
+;
+*/
+
+instruction_list:
+ il_instruction
+ {$$ = new instruction_list_c(); $$->add_element($1);}
+| instruction_list il_instruction
+ {$$ = $1; $$->add_element($2);}
+| instruction_list pragma
+ {$$ = $1; $$->add_element($2);}
+| instruction_list error
+ {$$ = $1;
+ print_err_msg(current_filename, @2.last_line, "error in IL instruction.");
+ /* yychar */
+ yyerrok;
+ }
+;
+
+
+
+il_instruction:
+ il_incomplete_instruction eol_list
+ {$$ = new il_instruction_c(NULL, $1);}
+| label ':' il_incomplete_instruction eol_list
+ {$$ = new il_instruction_c($1, $3);}
+;
+
+
+/* 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
+ {$$ = new il_simple_operation_c($1, NULL);}
+| il_simple_operator_noclash il_operand
+ {$$ = new il_simple_operation_c($1, $2);}
+| il_simple_operator_clash_il_operand
+ {$$ = new il_simple_operation_c($1.first, $1.second);}
+/* 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.
+ *
+ * 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);}
+/* NOTE: the line
+ * | il_simple_operator il_operand
+ * already contains the 'NOT', 'MOD', etc. operators, followed by a single il_operand,
+ * which may also be reduced to a function name with an operand_list of a single
+ * il_operand! This would lead us to a reduce/reduce conflict!
+ *
+ * I (Mario) have chosen to reduce it to an operand, rather than a function call.
+ *
+ * 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!
+ * 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);}
+| il_simple_operator_clash_il_operand ',' il_operand_list
+ {list_c *list = new il_operand_list_c();
+ list->add_element($1.second);
+ FOR_EACH_ELEMENT(elem, $3, {list->add_element(elem);})
+ $$ = new il_function_call_c(il_operator_c_2_identifier_c($1.first), list);
+ }
+;
+
+
+
+il_simple_operator_clash_il_operand:
+ il_simple_operator_clash il_operand
+ {$$.first = $1; $$.second = $2;}
+;
+
+
+
+il_expression:
+ il_expr_operator_noclash '(' eol_list ')'
+ {$$ = new il_expression_c($1, NULL, NULL);}
+| il_expr_operator_noclash '(' il_operand eol_list ')'
+ {$$ = new il_expression_c($1, $3, NULL);}
+| il_expr_operator_noclash '(' eol_list simple_instr_list ')'
+ {$$ = new il_expression_c($1, NULL, $4);}
+| il_expr_operator_noclash '(' il_operand eol_list simple_instr_list ')'
+ {$$ = new il_expression_c($1, $3, $5);}
+/*
+*/
+| il_expr_operator_clash '(' eol_list ')'
+ {$$ = new il_expression_c($1, NULL, NULL);}
+| il_expr_operator_clash '(' il_operand eol_list ')'
+ {$$ = new il_expression_c($1, $3, NULL);}
+| il_expr_operator_clash '(' il_operand eol_list simple_instr_list ')'
+ {$$ = new il_expression_c($1, $3, $5);}
+/*
+*/
+| il_expr_operator_clash_eol_list simple_instr_list ')'
+ {$$ = new il_expression_c($1, NULL, $2);}
+;
+
+
+il_jump_operation:
+ il_jump_operator label
+ {$$ = new il_jump_operation_c($1, $2);}
+;
+
+
+il_fb_call:
+ il_call_operator prev_declared_fb_name
+ {$$ = new il_fb_call_c($1, $2, NULL, NULL);}
+| il_call_operator prev_declared_fb_name '(' ')'
+ {$$ = new il_fb_call_c($1, $2, NULL, NULL);}
+| il_call_operator prev_declared_fb_name '(' eol_list ')'
+ {$$ = new il_fb_call_c($1, $2, NULL, NULL);}
+| il_call_operator prev_declared_fb_name '(' il_operand_list ')'
+ {$$ = new il_fb_call_c($1, $2, $4, NULL);}
+| il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')'
+ {$$ = new il_fb_call_c($1, $2, NULL, $5);}
+;
+
+
+/* NOTE: Please read note above the definition of function_name_without_clashes */
+il_formal_funct_call:
+/* 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!
+ */
+ function_name_no_clashes '(' eol_list ')'
+ {$$ = new il_formal_funct_call_c($1, NULL);}
+| function_name_simpleop_clashes '(' eol_list ')'
+ {$$ = new il_formal_funct_call_c($1, NULL);}
+/* | function_name '(' eol_list il_param_list ')' */
+| function_name_no_clashes '(' eol_list il_param_list ')'
+ {$$ = new il_formal_funct_call_c($1, $4);}
+| function_name_simpleop_clashes '(' eol_list il_param_list ')'
+ {$$ = new il_formal_funct_call_c($1, $4);}
+/* 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);}
+;
+
+
+il_expr_operator_clash_eol_list:
+ il_expr_operator_clash '(' eol_list
+ {$$ = $1;}
+;
+
+
+il_operand:
+ variable
+| enumerated_value
+| constant
+;
+
+
+il_operand_list:
+ il_operand
+ {$$ = new il_operand_list_c(); $$->add_element($1);}
+| il_operand_list ',' il_operand
+ {$$ = $1; $$->add_element($3);}
+;
+
+
+simple_instr_list:
+ il_simple_instruction
+ {$$ = new simple_instr_list_c(); $$->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
+;
+
+
+/* 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(); $$->add_element($1);}
+;
+
+
+/* Helper symbol for il_param_list */
+il_param_instruction_list:
+ il_param_instruction
+ {$$ = new il_param_list_c(); $$->add_element($1);}
+| il_param_instruction_list il_param_instruction
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+il_param_instruction:
+ il_param_assignment ',' eol_list
+| il_param_out_assignment ',' eol_list
+;
+
+
+il_param_last_instruction:
+ il_param_assignment eol_list
+| il_param_out_assignment eol_list
+;
+
+
+il_param_assignment:
+ il_assign_operator il_operand
+ {$$ = new il_param_assignment_c($1, $2, NULL);}
+| il_assign_operator '(' eol_list simple_instr_list ')'
+ {$$ = new il_param_assignment_c($1, NULL, $4);}
+;
+
+
+il_param_out_assignment:
+ il_assign_out_operator variable
+ {$$ = new il_param_out_assignment_c($1, $2);}
+;
+
+
+
+/*******************/
+/* B 2.2 Operators */
+/*******************/
+sendto_identifier: sendto_identifier_token {$$ = new identifier_c($1);};
+
+
+/* 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();};
+LDN_operator: LDN {$$ = new LDN_operator_c();};
+ST_operator: ST {$$ = new ST_operator_c();};
+STN_operator: STN {$$ = new STN_operator_c();};
+NOT_operator: NOT {$$ = new NOT_operator_c();};
+S_operator: S {$$ = new S_operator_c();};
+R_operator: R {$$ = new R_operator_c();};
+S1_operator: S1 {$$ = new S1_operator_c();};
+R1_operator: R1 {$$ = new R1_operator_c();};
+CLK_operator: CLK {$$ = new CLK_operator_c();};
+CU_operator: CU {$$ = new CU_operator_c();};
+CD_operator: CD {$$ = new CD_operator_c();};
+PV_operator: PV {$$ = new PV_operator_c();};
+IN_operator: IN {$$ = new IN_operator_c();};
+PT_operator: PT {$$ = new PT_operator_c();};
+AND_operator: AND {$$ = new AND_operator_c();};
+AND2_operator: AND2 {$$ = new AND_operator_c();}; /* '&' in the source code! */
+OR_operator: OR {$$ = new OR_operator_c();};
+XOR_operator: XOR {$$ = new XOR_operator_c();};
+ANDN_operator: ANDN {$$ = new ANDN_operator_c();};
+ANDN2_operator: ANDN2 {$$ = new ANDN_operator_c();}; /* '&N' in the source code! */
+ORN_operator: ORN {$$ = new ORN_operator_c();};
+XORN_operator: XORN {$$ = new XORN_operator_c();};
+ADD_operator: ADD {$$ = new ADD_operator_c();};
+SUB_operator: SUB {$$ = new SUB_operator_c();};
+MUL_operator: MUL {$$ = new MUL_operator_c();};
+DIV_operator: DIV {$$ = new DIV_operator_c();};
+MOD_operator: MOD {$$ = new MOD_operator_c();};
+GT_operator: GT {$$ = new GT_operator_c();};
+GE_operator: GE {$$ = new GE_operator_c();};
+EQ_operator: EQ {$$ = new EQ_operator_c();};
+LT_operator: LT {$$ = new LT_operator_c();};
+LE_operator: LE {$$ = new LE_operator_c();};
+NE_operator: NE {$$ = new NE_operator_c();};
+CAL_operator: CAL {$$ = new CAL_operator_c();};
+CALC_operator: CALC {$$ = new CALC_operator_c();};
+CALCN_operator: CALCN {$$ = new CALCN_operator_c();};
+RET_operator: RET {$$ = new RET_operator_c();};
+RETC_operator: RETC {$$ = new RETC_operator_c();};
+RETCN_operator: RETCN {$$ = new RETCN_operator_c();};
+JMP_operator: JMP {$$ = new JMP_operator_c();};
+JMPC_operator: JMPC {$$ = new JMPC_operator_c();};
+JMPCN_operator: JMPCN {$$ = new JMPCN_operator_c();};
+
+/*
+ MAY CONFLICT WITH STANDARD FUNCTION NAMES!!!
+
+NOT_operator: NOT {new NOT_operator_c();};
+
+AND_operator: AND {new AND_operator_c();};
+OR_operator: OR {new OR_operator_c();};
+XOR_operator: XOR {new XOR_operator_c();};
+
+ADD_operator: ADD {new ADD_operator_c();};
+SUB_operator: SUB {new SUB_operator_c();};
+MUL_operator: MUL {new MUL_operator_c();};
+DIV_operator: DIV {new DIV_operator_c();};
+MOD_operator: MOD {new MOD_operator_c();};
+
+GT_operator: GT {new GT_operator_c();};
+GE_operator: GE {new GE_operator_c();};
+EQ_operator: EQ {new EQ_operator_c();};
+LT_operator: LT {new LT_operator_c();};
+LE_operator: LE {new LE_operator_c();};
+NE_operator: NE {new NE_operator_c();};
+*/
+
+
+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
+;
+
+
+il_assign_out_operator:
+/* variable_name SENDTO */
+/* any_identifier SENDTO */
+ sendto_identifier SENDTO
+ {$$ = new il_assign_out_operator_c(NULL, $1);}
+/*| NOT variable_name SENDTO */
+| NOT sendto_identifier SENDTO
+ {$$ = new il_assign_out_operator_c(new not_paramassign_c(), $2);}
+;
+
+
+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);}
+;
+
+xor_expression:
+ and_expression
+| xor_expression XOR and_expression
+ {$$ = new xor_expression_c($1, $3);}
+;
+
+and_expression:
+ comparison
+| and_expression '&' comparison
+ {$$ = new and_expression_c($1, $3);}
+| and_expression AND comparison
+ {$$ = new and_expression_c($1, $3);}
+/* 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 theh AND2 token...
+ */
+| and_expression AND2 comparison
+ {$$ = new and_expression_c($1, $3);}
+;
+
+comparison:
+ equ_expression
+| comparison '=' equ_expression
+ {$$ = new equ_expression_c($1, $3);}
+| comparison OPER_NE equ_expression
+ {$$ = new notequ_expression_c($1, $3);}
+;
+
+equ_expression:
+ add_expression
+| equ_expression '<' add_expression
+ {$$ = new lt_expression_c($1, $3);}
+| equ_expression '>' add_expression
+ {$$ = new gt_expression_c($1, $3);}
+| equ_expression OPER_LE add_expression
+ {$$ = new le_expression_c($1, $3);}
+| equ_expression OPER_GE add_expression
+ {$$ = new ge_expression_c($1, $3);}
+;
+
+/* Not required...
+comparison_operator: '<' | '>' | '>=' '<='
+*/
+
+add_expression:
+ term
+| add_expression '+' term
+ {$$ = new add_expression_c($1, $3);}
+| add_expression '-' term
+ {$$ = new sub_expression_c($1, $3);}
+;
+
+/* Not required...
+add_operator: '+' | '-'
+*/
+
+term:
+ power_expression
+| term '*' power_expression
+ {$$ = new mul_expression_c($1, $3);}
+| term '/' power_expression
+ {$$ = new div_expression_c($1, $3);}
+| term MOD power_expression
+ {$$ = new mod_expression_c($1, $3);}
+;
+
+/* Not required...
+multiply_operator: '*' | '/' | 'MOD'
+*/
+
+power_expression:
+ unary_expression
+| power_expression OPER_EXP unary_expression
+ {$$ = new power_expression_c($1, $3);}
+;
+
+
+unary_expression:
+ primary_expression
+| '-' primary_expression
+ {$$ = new neg_expression_c($2);}
+| NOT primary_expression
+ {$$ = new not_expression_c($2);}
+;
+
+/* 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 conlfict, we only allow constants without
+ * a preceding '-' to be used in primary_expression
+ */
+primary_expression:
+/* constant */
+ non_negative_constant
+| enumerated_value
+| variable
+| '(' expression ')'
+ {$$ = $2;}
+| function_invocation
+;
+
+
+/* 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_list ')'
+ {$$ = new function_invocation_c($1, $3);}
+;
+
+
+/********************/
+/* B 3.2 Statements */
+/********************/
+statement_list:
+ /* empty */
+ {$$ = new statement_list_c();}
+| statement_list statement ';'
+ {$$ = $1; $$->add_element($2);}
+| statement_list pragma
+ {$$ = $1; $$->add_element($2);}
+| statement_list error ';'
+ {$$ = $1;
+ print_err_msg(current_filename, @2.last_line, "error in statement.");
+ /* yychar */
+ yyerrok;
+ }
+;
+
+
+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);}
+;
+
+
+
+
+/*****************************************/
+/* B 3.2.2 Subprogram Control Statements */
+/*****************************************/
+subprogram_control_statement:
+ fb_invocation
+| return_statement
+;
+
+
+return_statement:
+ RETURN {$$ = new return_statement_c();}
+;
+
+
+
+fb_invocation:
+ prev_declared_fb_name '(' ')'
+ {$$ = new fb_invocation_c($1, NULL); }
+| prev_declared_fb_name '(' param_assignment_list ')'
+ {$$ = new fb_invocation_c($1, $3);}
+;
+
+
+/* helper symbol for
+ * - fb_invocation
+ * - function_invocation
+ */
+param_assignment_list:
+ param_assignment
+ {$$ = new param_assignment_list_c(); $$->add_element($1);}
+| param_assignment_list ',' param_assignment
+ {$$ = $1; $$->add_element($3);}
+;
+
+
+
+param_assignment:
+/* variable_name ASSIGN expression */
+ any_identifier ASSIGN expression
+ {$$ = new input_variable_param_assignment_c($1, $3);}
+| expression
+/*| variable_name SENDTO variable */
+/*| any_identifier SENDTO variable */
+| sendto_identifier SENDTO variable
+ {$$ = new output_variable_param_assignment_c(NULL,$1, $3);}
+/*| variable_name SENDTO variable */
+/*| NOT any_identifier SENDTO variable*/
+| NOT sendto_identifier SENDTO variable
+ {$$ = new output_variable_param_assignment_c(new not_paramassign_c(),$2, $4);}
+;
+
+
+
+
+
+/********************************/
+/* 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);}
+| IF expression THEN statement_list elseif_statement_list ELSE statement_list END_IF
+ {$$ = new if_statement_c($2, $4, $5, $7);}
+;
+
+/* helper symbol for if_statement */
+elseif_statement_list:
+ /* empty */
+ {$$ = new elseif_statement_list_c();}
+| 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);}
+;
+
+
+case_statement:
+ CASE expression OF case_element_list END_CASE
+ {$$ = new case_statement_c($2, $4, NULL);}
+| CASE expression OF case_element_list ELSE statement_list END_CASE
+ {$$ = new case_statement_c($2, $4, $6);}
+;
+
+
+/* helper symbol for case_statement */
+case_element_list:
+ case_element
+ {$$ = new case_element_list_c(); $$->add_element($1);}
+| case_element_list case_element
+ {$$ = $1; $$->add_element($2);}
+;
+
+
+case_element:
+ case_list ':' statement_list
+ {$$ = new case_element_c($1, $3);}
+;
+
+
+case_list:
+ case_list_element
+ {$$ = new case_list_c(); $$->add_element($1);}
+| case_list ',' case_list_element
+ {$$ = $1; $$->add_element($3);}
+;
+
+
+case_list_element:
+ signed_integer
+| enumerated_value
+| subrange
+;
+
+
+
+
+
+/********************************/
+/* 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);}
+| FOR control_variable ASSIGN expression TO expression DO statement_list END_FOR
+ {$$ = new for_statement_c($2, $4, $6, NULL, $8);}
+;
+
+/* 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
+ * construct, so I (Mario) changed the syntax to read
+ * control_variable: prev_declared_variable_name;
+*/
+control_variable: prev_declared_variable_name {$$ = $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);}
+;
+
+
+repeat_statement:
+ REPEAT statement_list UNTIL expression END_REPEAT
+ {$$ = new repeat_statement_c($2, $4);}
+;
+
+
+exit_statement:
+ EXIT {$$ = new exit_statement_c();}
+;
+
+
+
+
+
+%%
+
+#include <stdio.h> /* required for printf() */
+#include <errno.h>
+#include "../util/symtable.hh"
+
+/* variables defined in code generated by flex... */
+extern FILE *yyin;
+extern int yylineno;
+
+/* 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();
+}
+
+
+void print_err_msg(const char *filename, int lineno, const char *additional_error_msg) {
+ fprintf(stderr, "error %d: %s\n", yynerrs, additional_error_msg);
+ print_include_stack();
+ fprintf(stderr, "%s:%d: %s\n", filename, lineno, current_error_msg);
+}
+
+/* Function only called from within flex!
+ *
+ * search for a symbol in either of the two symbol tables
+ * declared above, and return the token id of the first
+ * symbol found.
+ * Searches first in the variables, and only if not found
+ * does it continue searching in the library elements
+ */
+int get_identifier_token(const char *identifier_str) {
+// std::cout << "get_identifier_token(" << identifier_str << "): \n";
+ int token_id;
+
+ if ((token_id = variable_name_symtable.find_value(identifier_str)) == variable_name_symtable.end_value())
+ if ((token_id = library_element_symtable.find_value(identifier_str)) == library_element_symtable.end_value())
+ return identifier_token;
+ return token_id;
+}
+
+
+
+/* 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<op ## _operator_c *>(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;
+
+ 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;
+
+ free(il_operator);
+ return new identifier_c(strdup(name));
+}
+
+
+
+
+/*
+ * Join two strings together. Allocate space with malloc(3).
+ */
+static char *strdup2(const char *a, const char *b) {
+ char *res = (char *)malloc(strlen(a) + strlen(b) + 1);
+
+ if (!res)
+ return NULL;
+ return strcat(strcpy(res, a), b); /* safe, actually */
+}
+
+/*
+ * Join three strings together. Allocate space with malloc(3).
+ */
+static char *strdup3(const char *a, const char *b, const char *c) {
+ char *res = (char *)malloc(strlen(a) + strlen(b) + strlen(c) + 1);
+
+ if (!res)
+ return NULL;
+ return strcat(strcat(strcpy(res, a), b), c); /* safe, actually */
+}
+
+
+
+
+const char *standard_function_names[] = {
+// 2.5.1.5.1 Type conversion functions
+/*
+ *_TO_**
+ TRUNC
+ *_BCD_TO_**
+ **_TO_BCD_*
+ (REAL or LREAL to SINT, INT, DINT or LINT)
+*/
+"TRUNC",
+"TIME_TO_REAL",
+// 2.5.1.5.2 Numerical functions
+// Table 23 - Standard functions of one numeric variable
+"ABS","SQRT","LN","LOG","EXP","SIN","COS","TAN","ASIN","ACOS","ATAN",
+// Table 24 - Standard arithmetic functions
+"ADD","MUL","SUB","DIV","MOD"/* See note (a) */,"EXPT","MOVE",
+// 2.5.1.5.3 Bit string functions
+// Table 25 - Standard bit shift functions
+"SHL","SHR","ROR","ROL",
+// 2.5.1.5.4 Selection and comparison functions
+// Table 26 - Standard bitwise Boolean functions
+"AND","OR","XOR","NOT",
+// Table 27 - Standard selection functions
+"SEL","MAX","MIN","LIMIT","MUX",
+// Table 28 - Standard comparison functions
+"GT","GE","EQ","LE","LT","NE",
+// 2.5.1.5.5 Character string functions
+// Table 29 - Standard character string functions
+"LEN","LEFT","RIGHT","MID","CONCAT","INSERT","DELETE","REPLACE","FIND",
+// 2.5.1.5.6 Functions of time data types
+// Table 30 - Functions of time data types
+"ADD_TIME","ADD_TOD_TIME","ADD_DT_TIME","SUB_TIME","SUB_DATE_DATE",
+"SUB_TOD_TIME","SUB_TOD_TOD","SUB_DT_TIME","SUB_DT_DT","MULTIME",
+"DIVTIME","CONCAT_DATE_TOD",
+// 2.5.1.5.7 Functions of enumerated data types
+// Table 31 - Functions of enumerated data types
+// "SEL", /* already above! We cannot have duplicates! */
+// "MUX", /* already above! We cannot have duplicates! */
+// "EQ", /* already above! We cannot have duplicates! */
+// "NE", /* already above! We cannot have duplicates! */
+
+/* end of array marker! Do not remove! */
+NULL
+
+/* Note (a):
+ * This function has a name equal to a reserved keyword.
+ * This means that adding it here is irrelevant because the
+ * lexical parser will consider it the XXX token before
+ * it interprets it as an identifier and looks it up
+ * in the library elements symbol table.
+ */
+};
+
+
+
+
+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_LINT","CTU_UDINT","CTU_ULINT",
+"CTD","CTD_DINT","CTD_LINT","CTD_UDINT",
+"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
+
+int stage1_2(const char *filename, const char *includedir, symbol_c **tree_root_ref) {
+ 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) {
+ if ((libfilename = strdup3(includedir, "/", 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 try again... */
+ if ((libfilename = strdup(DEF_LIBFILENAME)) == 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... */
+ yyin = lib_file;
+ yylineno = 1;
+ allow_function_overloading = true;
+ current_filename = libfilename;
+ 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_names[i] != NULL; i++)
+ if (library_element_symtable.find_value(standard_function_names[i]) ==
+ library_element_symtable.end_value())
+ library_element_symtable.insert(standard_function_names[i], standard_function_name_token);
+
+ 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);
+
+#if YYDEBUG
+ yydebug = 1;
+#endif
+
+ /* now parse the input file... */
+ yyin = in_file;
+ yylineno = 1;
+ allow_function_overloading = false;
+ current_filename = filename;
+ if (yyparse() != 0)
+ 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;
+}
+
+
+