diff -r 000000000000 -r fb772792efd1 stage1_2/iec.y --- /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 /* 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 in list_c * + * execute the code + */ +#define FOR_EACH_ELEMENT(elem, list, code) { \ + symbol_c *elem; \ + for(int i = 0; i < list->n; i++) { \ + elem = list->elements[i]; \ + code; \ + } \ +} + + +/* 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.: + * + * + * + * + */ +static symtable_c library_element_symtable; + +/* A symbol table to store the declared variables of + * the function currently being parsed... + */ +static symtable_c 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 *) + * 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 start + +%type any_identifier + +%token prev_declared_variable_name_token +%token prev_declared_fb_name_token +%type prev_declared_variable_name +%type prev_declared_fb_name + +%token prev_declared_simple_type_name_token +%token prev_declared_subrange_type_name_token +%token prev_declared_enumerated_type_name_token +%token prev_declared_array_type_name_token +%token prev_declared_structure_type_name_token +%token prev_declared_string_type_name_token + +%type prev_declared_simple_type_name +%type prev_declared_subrange_type_name +%type prev_declared_enumerated_type_name +%type prev_declared_array_type_name +%type prev_declared_structure_type_name +%type prev_declared_string_type_name + +%token prev_declared_derived_function_name_token +%token prev_declared_derived_function_block_name_token +%token prev_declared_program_type_name_token +%type prev_declared_derived_function_name +%type prev_declared_derived_function_block_name +%type prev_declared_program_type_name + + +/* 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 pragma_token +%type pragma + + +/* Where do these tokens belong ?? */ +/* TODO: get the syntax parser to handle these tokens... */ +%token EN +%token ENO + + + +/***************************/ +/* B 0 - Programming Model */ +/***************************/ +%type library +%type library_element_declaration + + +/*******************************************/ +/* B 1.1 - Letters, digits and identifiers */ +/*******************************************/ +/* Done totally within flex... + letter + digit + octal_digit + hex_digit +*/ +%token identifier_token +%type identifier + + +/*********************/ +/* B 1.2 - Constants */ +/*********************/ +%type constant +/* a helper symbol for expression */ +%type non_negative_constant + + +/******************************/ +/* B 1.2.1 - Numeric Literals */ +/******************************/ +/* Done totally within flex... + bit +*/ +%type numeric_literal +/* helper symbol for non_negative_constant */ +%type non_negative_numeric_literal +%type integer_literal +%type signed_integer +/* a helper symbol for non_negative_constant */ +%type non_negative_signed_integer +%token integer_token +%type integer +%token binary_integer_token +%type binary_integer +%token octal_integer_token +%type octal_integer +%token hex_integer_token +%type hex_integer +%token real_token +%type real +%type signed_real +/* helper symbol for non_negative_real_literal */ +%type non_negative_signed_real +%type real_literal +/* helper symbol for non_negative_numeric_literal */ +%type non_negative_real_literal +// %type exponent +%type bit_string_literal +%type boolean_literal + +%token FALSE +%token TRUE + + +/*******************************/ +/* B 1.2.2 - Character Strings */ +/*******************************/ +%token single_byte_character_string_token +%token double_byte_character_string_token + +%type character_string +%type single_byte_character_string +%type double_byte_character_string + + +/***************************/ +/* B 1.2.3 - Time Literals */ +/***************************/ +%type time_literal + + +/************************/ +/* B 1.2.3.1 - Duration */ +/************************/ +%type duration +%type interval +%type days +%type fixed_point +%type hours +%type minutes +%type seconds +%type milliseconds + +%type integer_d +%type integer_h +%type integer_m +%type integer_s +%type integer_ms +%type fixed_point_d +%type fixed_point_h +%type fixed_point_m +%type fixed_point_s +%type fixed_point_ms + +%token fixed_point_token +%token fixed_point_d_token +%token integer_d_token +%token fixed_point_h_token +%token integer_h_token +%token fixed_point_m_token +%token integer_m_token +%token fixed_point_s_token +%token integer_s_token +%token fixed_point_ms_token +%token integer_ms_token + +%token TIME +%token T_SHARP + + +/************************************/ +/* B 1.2.3.2 - Time of day and Date */ +/************************************/ +%type time_of_day +%type daytime +%type day_hour +%type day_minute +%type day_second +%type date +%type date_literal +%type year +%type month +%type day +%type date_and_time + +%token TIME_OF_DAY +%token DATE +%token D_SHARP +%token DATE_AND_TIME + + +/**********************/ +/* B 1.3 - Data Types */ +/**********************/ +/* Strangely, the following symbol does seem to be required! */ +// %type data_type_name +%type non_generic_type_name + + +/***********************************/ +/* B 1.3.1 - Elementary Data Types */ +/***********************************/ +/* NOTES: + * + * - To make the definition of bit_string_literal more + * concise, it is useful to use an extra non-terminal + * symbol (i.e. a grouping or construct) that groups the + * following elements (BYTE, WORD, DWORD, LWORD). + * Note that the definition of bit_string_type_name + * (according to the spec) includes the above elements + * and an extra BOOL. + * We could use an extra construct with the first four + * elements to be used solely in the definition of + * bit_string_literal, but with the objective of not + * having to replicate the actions (if we ever need + * to change them, they would need to be changed in both + * bit_string_type_name and the extra grouping), we + * have re-defined bit_string_type_name as only including + * the first four elements. + * In order to have our parser implement the specification + * correctly we have augmented every occurence of + * bit_string_type_name in other rules with the BOOL + * token. Since bit_string_type_name only appears in + * the rule for elementary_type_name, this does not + * seem to be a big concession to make! + * + * - We have added a helper symbol to concentrate the + * instantiation of STRING and WSTRING into a single + * location (elementary_string_type_name). + * These two elements show up in several other rules, + * but we want to create the equivalent abstract syntax + * in a single location of this file, in order to make + * possible future changes easier to edit... + */ +%type elementary_type_name +%type numeric_type_name +%type integer_type_name +%type signed_integer_type_name +%type unsigned_integer_type_name +%type real_type_name +%type date_type_name +%type bit_string_type_name +/* helper symbol to concentrate the instantiation + * of STRING and WSTRING into a single location + */ +%type elementary_string_type_name + +%token BYTE +%token WORD +%token DWORD +%token LWORD + +%token LREAL +%token REAL + +%token SINT +%token INT +%token DINT +%token LINT + +%token USINT +%token UINT +%token UDINT +%token ULINT + +%token WSTRING +%token STRING +%token BOOL + +%token TIME +%token DATE +%token DATE_AND_TIME +%token DT +%token TIME_OF_DAY +%token TOD + + +/********************************/ +/* B 1.3.2 - Generic data types */ +/********************************/ +/* Strangely, the following symbol does seem to be required! */ +// %type generic_type_name + +/* The following tokens do not seem to be used either + * but we declare them so they become reserved words... + */ +%token ANY +%token ANY_DERIVED +%token ANY_ELEMENTARY +%token ANY_MAGNITUDE +%token ANY_NUM +%token ANY_REAL +%token ANY_INT +%token ANY_BIT +%token ANY_STRING +%token ANY_DATE + + +/********************************/ +/* B 1.3.3 - Derived data types */ +/********************************/ +%type derived_type_name +%type single_element_type_name +// %type simple_type_name +// %type subrange_type_name +// %type enumerated_type_name +// %type array_type_name +// %type structure_type_name + +%type data_type_declaration +/* helper symbol for data_type_declaration */ +%type type_declaration_list +%type type_declaration +%type single_element_type_declaration + +%type simple_type_declaration +%type simple_spec_init +%type simple_specification + +%type subrange_type_declaration +%type subrange_spec_init +%type subrange_specification +%type subrange + +%type enumerated_type_declaration +%type enumerated_spec_init +%type enumerated_specification +/* helper symbol for enumerated_value */ +%type enumerated_value_list +%type enumerated_value + +%type array_type_declaration +%type array_spec_init +%type array_specification +/* helper symbol for array_specification */ +%type array_subrange_list +%type array_initialization +/* helper symbol for array_initialization */ +%type array_initial_elements_list +%type array_initial_elements +%type array_initial_element + +%type structure_type_declaration +%type structure_specification +%type initialized_structure +%type structure_declaration +/* helper symbol for structure_declaration */ +%type structure_element_declaration_list +%type structure_element_declaration +%type structure_element_name +%type structure_initialization +/* helper symbol for structure_initialization */ +%type structure_element_initialization_list +%type structure_element_initialization + +//%type string_type_name +%type string_type_declaration +/* helper symbol for string_type_declaration */ +%type string_type_declaration_size +/* helper symbol for string_type_declaration */ +%type string_type_declaration_init + +%token ASSIGN +%token DOTDOT /* ".." */ +%token TYPE +%token END_TYPE +%token ARRAY +%token OF +%token STRUCT +%token END_STRUCT + + + +/*********************/ +/* B 1.4 - Variables */ +/*********************/ +%type variable +%type symbolic_variable +/* helper symbol for prog_cnxn */ +%type any_symbolic_variable +%type variable_name + + + + +/********************************************/ +/* B.1.4.1 Directly Represented Variables */ +/********************************************/ +/* Done totally within flex... + location_prefix + size_prefix +*/ +%token direct_variable_token +%type direct_variable + + +/*************************************/ +/* B.1.4.2 Multi-element Variables */ +/*************************************/ +%type multi_element_variable +/* helper symbol for any_symbolic_variable */ +%type any_multi_element_variable +%type array_variable +/* helper symbol for any_symbolic_variable */ +%type any_array_variable +%type subscripted_variable +/* helper symbol for any_symbolic_variable */ +%type any_subscripted_variable +%type subscript_list +%type subscript +%type structured_variable +/* helper symbol for any_symbolic_variable */ +%type any_structured_variable +%type record_variable +/* helper symbol for any_symbolic_variable */ +%type any_record_variable +%type field_selector + + +/******************************************/ +/* B 1.4.3 - Declaration & Initialisation */ +/******************************************/ +%type input_declarations +/* helper symbol for input_declarations */ +%type input_declaration_list +%type input_declaration +%type edge_declaration +%type var_init_decl +%type var1_init_decl +%type var1_list +%type array_var_init_decl +%type structured_var_init_decl +%type fb_name_decl +/* helper symbol for fb_name_decl */ +%type fb_name_list_with_colon +/* helper symbol for fb_name_list_with_colon */ +%type var1_list_with_colon +// %type fb_name_list +// %type fb_name +%type output_declarations +%type input_output_declarations +/* helper symbol for input_output_declarations */ +%type var_declaration_list +%type var_declaration +%type temp_var_decl +%type var1_declaration +%type array_var_declaration +%type structured_var_declaration +%type var_declarations +%type retentive_var_declarations +%type located_var_declarations +/* helper symbol for located_var_declarations */ +%type located_var_decl_list +%type located_var_decl +%type external_var_declarations +/* helper symbol for external_var_declarations */ +%type external_declaration_list +%type external_declaration +%type global_var_name +%type global_var_declarations +/* helper symbol for global_var_declarations */ +%type global_var_decl_list +%type global_var_decl +%type global_var_spec +%type located_var_spec_init +%type location +%type global_var_list +%type string_var_declaration +%type single_byte_string_var_declaration +%type single_byte_string_spec +%type double_byte_string_var_declaration +%type double_byte_string_spec +%type incompl_located_var_declarations +/* helper symbol for incompl_located_var_declarations */ +%type incompl_located_var_decl_list +%type incompl_located_var_decl +%type incompl_location +%type var_spec +/* helper symbol for var_spec */ +%type string_spec +/* intermediate helper symbol for: + * - non_retentive_var_decls + * - output_declarations + */ +%type var_init_decl_list + +%token incompl_location_token + +%token VAR_INPUT +%token VAR_OUTPUT +%token VAR_IN_OUT +%token VAR_EXTERNAL +%token VAR_GLOBAL +%token END_VAR +%token RETAIN +%token NON_RETAIN +%token R_EDGE +%token F_EDGE +%token AT + + +/***********************/ +/* B 1.5.1 - Functions */ +/***********************/ +//%type function_name +/* helper symbol for IL language */ +%type function_name_no_clashes +%type function_name_simpleop_clashes +//%type function_name_expression_clashes +/* helper symbols for ST language */ +//%type function_name_NOT_clashes +%type function_name_no_NOT_clashes + +//%type standard_function_name +/* helper symbols for IL language */ +%type standard_function_name_no_clashes +%type standard_function_name_simpleop_clashes +%type standard_function_name_expression_clashes +/* helper symbols for ST language */ +%type standard_function_name_NOT_clashes +%type standard_function_name_no_NOT_clashes + +%type derived_function_name +%type function_declaration +/* helper symbol for function_declaration */ +%type function_name_declaration +%type io_var_declarations +%type function_var_decls +%type function_body +%type var2_init_decl +/* intermediate helper symbol for function_declaration */ +%type io_OR_function_var_declarations_list +/* intermediate helper symbol for function_var_decls */ +%type var2_init_decl_list + +%token standard_function_name_token + +%token FUNCTION +%token END_FUNCTION +%token CONSTANT + + +/*****************************/ +/* B 1.5.2 - Function Blocks */ +/*****************************/ +%type function_block_type_name +%type standard_function_block_name +%type derived_function_block_name +%type function_block_declaration +%type other_var_declarations +%type temp_var_decls +%type non_retentive_var_decls +%type function_block_body +/* intermediate helper symbol for function_declaration */ +%type io_OR_other_var_declarations_list +/* intermediate helper symbol for temp_var_decls */ +%type temp_var_decls_list + +%token standard_function_block_name_token + +%token FUNCTION_BLOCK +%token END_FUNCTION_BLOCK +%token VAR_TEMP +%token END_VAR +%token VAR +%token NON_RETAIN +%token END_VAR + + +/**********************/ +/* B 1.5.3 - Programs */ +/**********************/ +%type program_type_name +%type program_declaration +/* helper symbol for program_declaration */ +%type program_var_declarations_list + +%token PROGRAM +%token END_PROGRAM + + +/********************************************/ +/* B 1.6 Sequential Function Chart elements */ +/********************************************/ +/* TODO */ +/* +%type sequential_function_chart +%type sfc_network +%type initial_step +%type step +%type action_association_list +%type step_name +%type action_association +/* helper symbol for action_association * +%type indicator_name_list +%type action_name +%type action_qualifier +%type timed_qualifier +%type action_time +%type indicator_name +%type transition +%type steps +%type step_name_list +%type transition_condition +%type 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 configuration_name +%type resource_type_name +%type configuration_declaration +// helper symbol for +// - configuration_declaration +// - resource_declaration +// +%type optional_global_var_declarations +// helper symbol for configuration_declaration +%type optional_access_declarations +// helper symbol for configuration_declaration +%type optional_instance_specific_initializations +// helper symbol for configuration_declaration +%type resource_declaration_list +%type resource_declaration +%type single_resource_declaration +// helper symbol for single_resource_declaration +%type task_configuration_list +// helper symbol for single_resource_declaration +%type program_configuration_list +%type resource_name +// %type access_declarations +// helper symbol for access_declarations +// %type access_declaration_list +// %type access_declaration +// %type access_path +// helper symbol for access_path +%type any_fb_name_list +%type global_var_reference +// %type access_name +%type program_output_reference +%type program_name +// %type direction +%type task_configuration +%type task_name +%type task_initialization +%type data_source +%type program_configuration +// helper symbol for program_configuration +%type optional_task_name +// helper symbol for program_configuration +%type optional_prog_conf_elements +%type prog_conf_elements +%type prog_conf_element +%type fb_task +%type prog_cnxn +%type prog_data_source +%type data_sink +%type instance_specific_initializations +// helper symbol for instance_specific_initializations +%type instance_specific_init_list +%type instance_specific_init +// helper symbol for instance_specific_init +%type fb_initialization + +%type prev_declared_global_var_name +%token prev_declared_global_var_name_token + +%type prev_declared_program_name +%token prev_declared_program_name_token + +%type prev_declared_resource_name +%token prev_declared_resource_name_token + +%token prev_declared_configuration_name_token + +// %type prev_declared_task_name +// %token prev_declared_task_name_token + +%token CONFIGURATION +%token END_CONFIGURATION +%token TASK +%token RESOURCE +%token ON +%token END_RESOURCE +%token VAR_CONFIG +%token VAR_ACCESS +%token END_VAR +%token WITH +%token PROGRAM +%token RETAIN +%token NON_RETAIN +%token PRIORITY +%token SINGLE +%token INTERVAL +%token READ_WRITE +%token READ_ONLY + + +/***********************************/ +/* B 2.1 Instructions and Operands */ +/***********************************/ +%type instruction_list +%type il_instruction +%type il_incomplete_instruction +%type label +%type il_simple_operation +// helper symbol for il_simple_operation +%type il_simple_operator_clash_il_operand +%type il_expression +%type il_jump_operation +%type il_fb_call +%type il_formal_funct_call +// helper symbol for il_formal_funct_call +%type il_expr_operator_clash_eol_list +%type il_operand +%type il_operand_list +%type simple_instr_list +%type il_simple_instruction +%type il_param_list +%type il_param_instruction_list +%type il_param_instruction +%type il_param_last_instruction +%type il_param_assignment +%type il_param_out_assignment + +%token EOL + + +/*******************/ +/* B 2.2 Operators */ +/*******************/ +%token sendto_identifier_token +%type sendto_identifier + +%type LD_operator +%type LDN_operator +%type ST_operator +%type STN_operator +%type NOT_operator +%type S_operator +%type R_operator +%type S1_operator +%type R1_operator +%type CLK_operator +%type CU_operator +%type CD_operator +%type PV_operator +%type IN_operator +%type PT_operator +%type AND_operator +%type AND2_operator +%type OR_operator +%type XOR_operator +%type ANDN_operator +%type ANDN2_operator +%type ORN_operator +%type XORN_operator +%type ADD_operator +%type SUB_operator +%type MUL_operator +%type DIV_operator +%type MOD_operator +%type GT_operator +%type GE_operator +%type EQ_operator +%type LT_operator +%type LE_operator +%type NE_operator +%type CAL_operator +%type CALC_operator +%type CALCN_operator +%type RET_operator +%type RETC_operator +%type RETCN_operator +%type JMP_operator +%type JMPC_operator +%type JMPCN_operator + +%type il_simple_operator +%type il_simple_operator_clash +%type il_simple_operator_clash1 +%type il_simple_operator_clash2 +%type il_simple_operator_noclash + +//%type il_expr_operator +%type il_expr_operator_clash +%type il_expr_operator_noclash + +%type il_assign_operator +%type il_assign_out_operator +%type il_call_operator +%type il_return_operator +%type il_jump_operator + + +%token LD +%token LDN +%token ST +%token STN +%token NOT +%token S +%token R +%token S1 +%token R1 +%token CLK +%token CU +%token CD +%token PV +%token IN +%token PT +%token AND +%token AND2 /* character '&' in the source code*/ +%token OR +%token XOR +%token ANDN +%token ANDN2 /* characters '&N' in the source code */ +%token ORN +%token XORN +%token ADD +%token SUB +%token MUL +%token DIV +%token MOD +%token GT +%token GE +%token EQ +%token LT +%token LE +%token NE +%token CAL +%token CALC +%token CALCN +%token RET +%token RETC +%token RETCN +%token JMP +%token JMPC +%token JMPCN + +%token SENDTO /* "=>" */ + + +/***********************/ +/* B 3.1 - Expressions */ +/***********************/ +/* NOTE: + * + * - unary_operator, multiply_operator, + * add_operator and comparison_operator + * are not required. Their values are integrated + * directly into other rules... + */ +%type expression +%type xor_expression +%type and_expression +%type comparison +%type equ_expression +// %type comparison_operator +%type add_expression +// %type add_operator +%type term +// %type multiply_operator +%type power_expression +%type unary_expression +// %type unary_operator +%type primary_expression +/* intermediate helper symbol for primary_expression */ +%type function_invocation + +%token AND +%token XOR +%token OR +%token MOD +%token NOT +%token OPER_NE +%token OPER_GE +%token OPER_LE +%token OPER_EXP + + +/********************/ +/* B 3.2 Statements */ +/********************/ +%type statement_list +%type statement + + + +/*********************************/ +/* B 3.2.1 Assignment Statements */ +/*********************************/ +%type assignment_statement +%token ASSIGN /* ":=" */ + + +/*****************************************/ +/* B 3.2.2 Subprogram Control Statements */ +/*****************************************/ +%type subprogram_control_statement +%type return_statement +%type fb_invocation +%type param_assignment +/* helper symbol for fb_invocation */ +%type param_assignment_list + +%token ASSIGN +%token SENDTO /* "=>" */ +%token RETURN + + +/********************************/ +/* B 3.2.3 Selection Statements */ +/********************************/ +%type selection_statement +%type if_statement +%type case_statement +%type case_element +%type case_list +%type case_list_element +/* helper symbol for if_statement */ +%type elseif_statement_list +/* helper symbol for elseif_statement_list */ +%type elseif_statement +/* helper symbol for case_statement */ +%type case_element_list + +%token IF +%token THEN +%token ELSIF +%token ELSE +%token END_IF + +%token CASE +%token OF +%token ELSE +%token END_CASE + + + +/********************************/ +/* B 3.2.4 Iteration Statements */ +/********************************/ +%type iteration_statement +%type for_statement +%type control_variable +%type while_statement +%type repeat_statement +%type exit_statement +/* Integrated directly into for_statement */ +// %type for_list + +%token FOR +%token ASSIGN +%token TO +%token BY +%token DO +%token END_FOR + +%token WHILE +%token DO +%token END_WHILE + +%token REPEAT +%token UNTIL +%token END_REPEAT + +%token EXIT + +%% + + + + +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ +/********************************************************/ + + + + + +/*****************************/ +/* 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 '[' ']' + * 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 +| +*/ +; + + + + +/**********************/ +/* 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 /* required for printf() */ +#include +#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(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; +} + + +