stage1_2/iec.y
author lbessard
Fri, 27 Jun 2008 09:36:40 +0200
changeset 125 7ec16536bc87
parent 121 9e8ce092e169
child 131 f55ef301e14c
permissions -rwxr-xr-x
Modifying time qualifier in SFC to take real time enlapsed instead of theoric period time
/*
 * (c) 2003-2007 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, ST and SFC compiler.
 *
 * Based on the
 * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
 *
 */

/*
 * Stage 2
 * =======
 *
 *  This file contains the syntax definition of the textual
 *  languages IL and ST, as well as the textual version of SFC.
 *  The syntax parser, comprising the 2nd stage of the overall 
 *  compiler, is generated by runing bison on this file.
 */




/**********************************************************************/
/**********************************************************************/
/**********************************************************************/
/**********************************************************************/
/*******                                                        *******/
/*******   The following syntax does not have any conflicts.    *******/
/*******                                                        *******/
/*******   P L E A S E    K E E P    I T    T H A T    W A Y !  *******/
/*******   ===================================================  *******/
/*******                                                        *******/
/**********************************************************************/
/**********************************************************************/
/**********************************************************************/
/**********************************************************************/




%{
#include <string.h>	/* required for strdup()  */


/* declare the token parser generated by flex... */
int yylex(void);

/* declare the error handler defined at the end of this file */
void yyerror (const char *error_msg);

/* produce a more verbose parsing error message */
#define YYERROR_VERBOSE

/* Include debuging code.
 * Printing of debug info must then be activated by setting
 * the variable yydebug to 1.
 */
#define YYDEBUG 0


/* file with declaration of absyntax classes... */
#include "../absyntax/absyntax.hh"

/* file with declaration of token constants. Generated by bison! */
// #include "iec.y.hh"

/* The interface through which bison and flex interact. */
#include "stage1_2_priv.hh"


/* an ugly hack!!
 * We will probably not need it when we decide
 *  to cut down the abstract syntax down to size.
 *  We keep it as it is until we get to write
 *  stages 3 and 4 of the compiler. Who knows,
 *  we might just find out that we really do need
 *  the abstract syntax tree to stay as it is
 *  afterall!
 */
/* for each element <elem> in list_c * <list>
 * execute the code <code>
 */
#define FOR_EACH_ELEMENT(elem, list, code) {		\
  symbol_c *elem;					\
  for(int i = 0; i < list->n; i++) {			\
    elem = list->elements[i];				\
    code;						\
  }							\
}



/* Macros used to pass the line and column locations when
 * creating a new object for the abstract syntax tree.
 */
#define locloc(foo) foo.first_line, foo.first_column, foo.last_line, foo.last_column
#define   locf(foo) foo.first_line, foo.first_column
#define   locl(foo) foo.last_line,  foo.last_column



/* A macro for printing out internal parser errors... */
#define ERROR error_exit(__FILE__,__LINE__)
/* function defined in main.cc */
extern void error_exit(const char *file_name, int line_no);



/*************************/
/* global variables...   */
/*************************/
/* NOTE: For some strange reason bison ver 2.3 is including these declarations
 *       in the iec.y.hh file, which is in turn included by flex.
 *       We cannot therefore define any variables over here, but merely declare 
 *       their existance (otherwise we get errors when linking the code, since we
 *       would get a new variable defined each time iec.y.hh is included!).
 *       Even though the variables are declared 'extern' over here, they will in
 *       fact be defined towards the end of this same file (i.e. in the prologue)
 */

/* A global flag used to tell the parser if overloaded funtions should be allowed.
 * The IEC 61131-3 standard allows overloaded funtions in the standard library,
 * but disallows them in user code...
 */
extern bool allow_function_overloading;

/* A pointer to the root of the parsing tree that will be generated 
 * by bison.
 */
extern symbol_c *tree_root;



/************************/
/* forward declarations */
/************************/
/* The functions declared here are defined at the end of this file... */

/* Convert an il_operator_c into an identifier_c */
symbol_c *il_operator_c_2_identifier_c(symbol_c *il_operator);

/* print an error message */
void print_err_msg(const char *filename,
                   int first_line,
                   int first_column,
                   int last_line,
                   int last_column,
                   const char *additional_error_msg);
%}




// %glr-parser
// %expect-rr 1




%union {
    symbol_c 	*leaf;
    list_c	*list;
    char 	*ID;	/* token value */
}

/*
 TODO: DO we need to define a destructor do free
       memory when recovering from errors, or do the
       class destructors already handle this?
       Following is example on how to define
       detructors, using the syntax:
       %destructor { CODE } SYMBOLS
%union
      {
        char *string;
      }
      %token <string> STRING
      %type  <string> string
      %destructor { free ($$); } STRING string
*/




/*****************************/
/* Prelimenary constructs... */
/*****************************/
/* A token used to identify the very end of the input file
 * after all includes have already been processed.
 *
 * Flex automatically returns the token with value 0
 * at the end of the file. We therefore specify here
 * a token with that exact same value here, so we can use it
 * to detect the very end of the input files.
 */
%token END_OF_INPUT 0

/* A bogus token that, in principle, flex MUST NEVER generate */
/* USE 1:
 * ======
 * This token is currently also being used as the default
 * initialisation value of the token_id member in
 * the symbol_c base class.
 *
 * USE 2
 * =====
 * This token may also be used in the future to remove
 * mysterious reduce/reduce conflicts due to the fact
 * that our grammar may not be LALR(1) but merely LR(1).
 * This means that bison cannot handle it without some
 * caoxing from ourselves. We will then need this token
 * to do the coaxing...
 */
%token BOGUS_TOKEN_ID


%type <leaf>	start

%type <leaf>	any_identifier

%token <ID>	prev_declared_variable_name_token
%token <ID>	prev_declared_fb_name_token
%type <leaf>	prev_declared_variable_name
%type <leaf>	prev_declared_fb_name

%token  <ID>	prev_declared_simple_type_name_token
%token  <ID>	prev_declared_subrange_type_name_token
%token  <ID>	prev_declared_enumerated_type_name_token
%token  <ID>	prev_declared_array_type_name_token
%token  <ID>	prev_declared_structure_type_name_token
%token  <ID>	prev_declared_string_type_name_token

%type  <leaf>	prev_declared_simple_type_name
%type  <leaf>	prev_declared_subrange_type_name
%type  <leaf>	prev_declared_enumerated_type_name
%type  <leaf>	prev_declared_array_type_name
%type  <leaf>	prev_declared_structure_type_name
%type  <leaf>	prev_declared_string_type_name

%token <ID>	prev_declared_derived_function_name_token
%token <ID>	prev_declared_derived_function_block_name_token
%token <ID>	prev_declared_program_type_name_token
%type  <leaf>	prev_declared_derived_function_name
%type  <leaf>	prev_declared_derived_function_block_name
%type  <leaf>	prev_declared_program_type_name




/* The pragmas... */
%token <ID>	pragma_token
%type <leaf>	pragma


/* Where do these tokens belong ?? */
/* TODO: get the syntax parser to handle these tokens... */
%token	EN
%token	ENO



/***************************/
/* B 0 - Programming Model */
/***************************/
%type <list>	library
%type <leaf>	library_element_declaration


/*******************************************/
/* B 1.1 - Letters, digits and identifiers */
/*******************************************/
/* Done totally within flex...
  letter
  digit
  octal_digit
  hex_digit
*/
%token <ID>	identifier_token
%type  <leaf>	identifier


/*********************/
/* B 1.2 - Constants */
/*********************/
%type <leaf>	constant
/* a helper symbol for expression */
%type  <leaf> non_negative_constant


/******************************/
/* B 1.2.1 - Numeric Literals */
/******************************/
/* Done totally within flex...
  bit
*/
%type  <leaf> numeric_literal
/* helper symbol for non_negative_constant */
%type  <leaf> non_negative_numeric_literal
%type  <leaf> integer_literal
%type  <leaf> signed_integer
/* a helper symbol for non_negative_constant */
%type  <leaf> non_negative_signed_integer
%token <ID>   integer_token
%type  <leaf> integer
%token <ID>   binary_integer_token
%type  <leaf> binary_integer
%token <ID>   octal_integer_token
%type  <leaf> octal_integer
%token <ID>   hex_integer_token
%type  <leaf> hex_integer
%token <ID>   real_token
%type  <leaf> real
%type  <leaf> signed_real
/* helper symbol for non_negative_real_literal */
%type  <leaf> non_negative_signed_real
%type  <leaf> real_literal
/* helper symbol for non_negative_numeric_literal */
%type  <leaf> non_negative_real_literal
// %type  <leaf> exponent
%type  <leaf> bit_string_literal
%type  <leaf> boolean_literal

%token FALSE
%token TRUE


/*******************************/
/* B 1.2.2 - Character Strings */
/*******************************/
%token <ID>   single_byte_character_string_token
%token <ID>   double_byte_character_string_token

%type  <leaf> character_string
%type  <leaf> single_byte_character_string
%type  <leaf> double_byte_character_string


/***************************/
/* B 1.2.3 - Time Literals */
/***************************/
%type  <leaf> time_literal


/************************/
/* B 1.2.3.1 - Duration */
/************************/
%type  <leaf>	duration
%type  <leaf>	interval
%type  <leaf>	days
%type  <leaf>	fixed_point
%type  <leaf>	hours
%type  <leaf>	minutes
%type  <leaf>	seconds
%type  <leaf>	milliseconds

%type  <leaf>	integer_d
%type  <leaf>	integer_h
%type  <leaf>	integer_m
%type  <leaf>	integer_s
%type  <leaf>	integer_ms
%type  <leaf>	fixed_point_d
%type  <leaf>	fixed_point_h
%type  <leaf>	fixed_point_m
%type  <leaf>	fixed_point_s
%type  <leaf>	fixed_point_ms

%token <ID>	fixed_point_token
%token <ID>	fixed_point_d_token
%token <ID>	integer_d_token
%token <ID>	fixed_point_h_token
%token <ID>	integer_h_token
%token <ID>	fixed_point_m_token
%token <ID>	integer_m_token
%token <ID>	fixed_point_s_token
%token <ID>	integer_s_token
%token <ID>	fixed_point_ms_token
%token <ID>	integer_ms_token

%token TIME
%token T_SHARP


/************************************/
/* B 1.2.3.2 - Time of day and Date */
/************************************/
%type  <leaf>	time_of_day
%type  <leaf>	daytime
%type  <leaf>	day_hour
%type  <leaf>	day_minute
%type  <leaf>	day_second
%type  <leaf>	date
%type  <leaf>	date_literal
%type  <leaf>	year
%type  <leaf>	month
%type  <leaf>	day
%type  <leaf>	date_and_time

%token TIME_OF_DAY
%token DATE
%token D_SHARP
%token DATE_AND_TIME


/**********************/
/* B 1.3 - Data Types */
/**********************/
/* Strangely, the following symbol does seem to be required! */
// %type  <leaf> data_type_name
%type  <leaf> non_generic_type_name


/***********************************/
/* B 1.3.1 - Elementary Data Types */
/***********************************/
/* NOTES:
 *
 *    - To make the definition of bit_string_literal more
 *      concise, it is useful to use an extra non-terminal
 *      symbol (i.e. a grouping or construct) that groups the
 *      following elements (BYTE, WORD, DWORD, LWORD).
 *      Note that the definition of bit_string_type_name
 *      (according to the spec) includes the above elements
 *      and an extra BOOL.
 *      We could use an extra construct with the first four
 *      elements to be used solely in the definition of
 *      bit_string_literal, but with the objective of not
 *      having to replicate the actions (if we ever need
 *      to change them, they would need to be changed in both
 *      bit_string_type_name and the extra grouping), we
 *      have re-defined bit_string_type_name as only including
 *      the first four elements.
 *      In order to have our parser implement the specification
 *      correctly we have augmented every occurence of
 *      bit_string_type_name in other rules with the BOOL
 *      token. Since bit_string_type_name only appears in
 *      the rule for elementary_type_name, this does not
 *      seem to be a big concession to make!
 *
 *    - We have added a helper symbol to concentrate the
 *      instantiation of STRING and WSTRING into a single
 *      location (elementary_string_type_name).
 *      These two elements show up in several other rules,
 *      but we want to create the equivalent abstract syntax
 *      in a single location of this file, in order to make
 *      possible future changes easier to edit...
 */
%type  <leaf>	elementary_type_name
%type  <leaf>	numeric_type_name
%type  <leaf>	integer_type_name
%type  <leaf>	signed_integer_type_name
%type  <leaf>	unsigned_integer_type_name
%type  <leaf>	real_type_name
%type  <leaf>	date_type_name
%type  <leaf>	bit_string_type_name
/* helper symbol to concentrate the instantiation
 * of STRING and WSTRING into a single location
 */
%type  <leaf>	elementary_string_type_name

%token BYTE
%token WORD
%token DWORD
%token LWORD

%token LREAL
%token REAL

%token SINT
%token INT
%token DINT
%token LINT

%token USINT
%token UINT
%token UDINT
%token ULINT

%token WSTRING
%token STRING
%token BOOL

// %token TIME
// %token DATE
// %token DATE_AND_TIME
%token DT
// %token TIME_OF_DAY
%token TOD


/********************************/
/* B 1.3.2 - Generic data types */
/********************************/
/* Strangely, the following symbol does seem to be required! */
// %type  <leaf>	generic_type_name

/* The following tokens do not seem to be used either
 * but we declare them so they become reserved words...
 */
%token ANY
%token ANY_DERIVED
%token ANY_ELEMENTARY
%token ANY_MAGNITUDE
%token ANY_NUM
%token ANY_REAL
%token ANY_INT
%token ANY_BIT
%token ANY_STRING
%token ANY_DATE


/********************************/
/* B 1.3.3 - Derived data types */
/********************************/
%type  <leaf>	derived_type_name
%type  <leaf>	single_element_type_name
// %type  <leaf>	simple_type_name
// %type  <leaf>	subrange_type_name
// %type  <leaf>	enumerated_type_name
// %type  <leaf>	array_type_name
// %type  <leaf>	structure_type_name

%type  <leaf>	data_type_declaration
/* helper symbol for data_type_declaration */
%type  <list>	type_declaration_list
%type  <leaf>	type_declaration
%type  <leaf>	single_element_type_declaration

%type  <leaf>	simple_type_declaration
%type  <leaf>	simple_spec_init
%type  <leaf>	simple_specification

%type  <leaf>	subrange_type_declaration
%type  <leaf>	subrange_spec_init
%type  <leaf>	subrange_specification
%type  <leaf>	subrange

%type  <leaf>	enumerated_type_declaration
%type  <leaf>	enumerated_spec_init
%type  <leaf>	enumerated_specification
/* helper symbol for enumerated_value */
%type  <list>	enumerated_value_list
%type  <leaf>	enumerated_value
//%type  <leaf>	enumerated_value_without_identifier

%type  <leaf>	array_type_declaration
%type  <leaf>	array_spec_init
%type  <leaf>	array_specification
/* helper symbol for array_specification */
%type  <list>	array_subrange_list
%type  <leaf>	array_initialization
/* helper symbol for array_initialization */
%type  <list>	array_initial_elements_list
%type  <leaf>	array_initial_elements
%type  <leaf>	array_initial_element

%type  <leaf>	structure_type_declaration
%type  <leaf>	structure_specification
%type  <leaf>	initialized_structure
%type  <leaf>	structure_declaration
/* helper symbol for structure_declaration */
%type  <list>	structure_element_declaration_list
%type  <leaf>	structure_element_declaration
%type  <leaf>	structure_element_name
%type  <leaf>	structure_initialization
/* helper symbol for structure_initialization */
%type  <list>	structure_element_initialization_list
%type  <leaf>	structure_element_initialization

//%type  <leaf>	string_type_name
%type  <leaf>	string_type_declaration
/* helper symbol for string_type_declaration */
%type  <leaf>	string_type_declaration_size
/* helper symbol for string_type_declaration */
%type  <leaf>	string_type_declaration_init

%token ASSIGN
%token DOTDOT  /* ".." */
%token TYPE
%token END_TYPE
%token ARRAY
%token OF
%token STRUCT
%token END_STRUCT



/*********************/
/* B 1.4 - Variables */
/*********************/
%type  <leaf>	variable
%type  <leaf>	symbolic_variable
/* helper symbol for prog_cnxn */
%type  <leaf>	any_symbolic_variable
%type  <leaf>	variable_name




/********************************************/
/* B.1.4.1   Directly Represented Variables */
/********************************************/
/* Done totally within flex...
 location_prefix
 size_prefix
*/
%token <ID>	direct_variable_token
%type  <leaf>	direct_variable


/*************************************/
/* B.1.4.2   Multi-element Variables */
/*************************************/
%type  <leaf>	multi_element_variable
/* helper symbol for any_symbolic_variable */
%type  <leaf>	any_multi_element_variable
%type  <leaf>	array_variable
/* helper symbol for any_symbolic_variable */
%type  <leaf>	any_array_variable
%type  <leaf>	subscripted_variable
/* helper symbol for any_symbolic_variable */
%type  <leaf>	any_subscripted_variable
%type  <list>	subscript_list
%type  <leaf>	subscript
%type  <leaf>	structured_variable
/* helper symbol for any_symbolic_variable */
%type  <leaf>	any_structured_variable
%type  <leaf>	record_variable
/* helper symbol for any_symbolic_variable */
%type  <leaf>	any_record_variable
%type  <leaf>	field_selector


/******************************************/
/* B 1.4.3 - Declaration & Initialisation */
/******************************************/
%type  <leaf>	input_declarations
/* helper symbol for input_declarations */
%type  <list>	input_declaration_list
%type  <leaf>	input_declaration
%type  <leaf>	edge_declaration
%type  <leaf>	var_init_decl
%type  <leaf>	var1_init_decl
%type  <list>	var1_list
%type  <leaf>	array_var_init_decl
%type  <leaf>	structured_var_init_decl
%type  <leaf>	fb_name_decl
/* helper symbol for fb_name_decl */
%type  <list>	fb_name_list_with_colon
/* helper symbol for fb_name_list_with_colon */
%type  <list>	var1_list_with_colon
// %type  <list>	fb_name_list
// %type  <leaf>	fb_name
%type  <leaf>	output_declarations
%type  <leaf>	input_output_declarations
/* helper symbol for input_output_declarations */
%type  <list>	var_declaration_list
%type  <leaf>	var_declaration
%type  <leaf>	temp_var_decl
%type  <leaf>	var1_declaration
%type  <leaf>	array_var_declaration
%type  <leaf>	structured_var_declaration
%type  <leaf>	var_declarations
%type  <leaf>	retentive_var_declarations
%type  <leaf>	located_var_declarations
/* helper symbol for located_var_declarations */
%type  <list>	located_var_decl_list
%type  <leaf>	located_var_decl
%type  <leaf>	external_var_declarations
/* helper symbol for external_var_declarations */
%type  <list>	external_declaration_list
%type  <leaf>	external_declaration
%type  <leaf>	global_var_name
%type  <leaf>	global_var_declarations
/* helper symbol for global_var_declarations */
%type  <list>	global_var_decl_list
%type  <leaf>	global_var_decl
%type  <leaf>	global_var_spec
%type  <leaf>	located_var_spec_init
%type  <leaf>	location
%type  <list>	global_var_list
%type  <leaf>	string_var_declaration
%type  <leaf>	single_byte_string_var_declaration
%type  <leaf>	single_byte_string_spec
%type  <leaf>	double_byte_string_var_declaration
%type  <leaf>	double_byte_string_spec
%type  <leaf>	incompl_located_var_declarations
/* helper symbol for incompl_located_var_declarations */
%type  <list>	incompl_located_var_decl_list
%type  <leaf>	incompl_located_var_decl
%type  <leaf>	incompl_location
%type  <leaf>	var_spec
/* helper symbol for var_spec */
%type  <leaf>	string_spec
/* intermediate helper symbol for:
 *  - non_retentive_var_decls
 *  - output_declarations
 */
%type  <list>	var_init_decl_list

%token  <ID>	incompl_location_token

%token VAR_INPUT
%token VAR_OUTPUT
%token VAR_IN_OUT
%token VAR_EXTERNAL
%token VAR_GLOBAL
%token END_VAR
%token RETAIN
%token NON_RETAIN
%token R_EDGE
%token F_EDGE
%token AT


/***********************/
/* B 1.5.1 - Functions */
/***********************/
// %type  <leaf>	function_name
/* helper symbol for IL language */
%type  <leaf>	function_name_no_clashes
%type  <leaf>	function_name_simpleop_clashes
//%type  <leaf>	function_name_expression_clashes
/* helper symbols for ST language */
//%type  <leaf>	function_name_NOT_clashes
%type  <leaf>	function_name_no_NOT_clashes

//%type  <leaf>	standard_function_name
/* helper symbols for IL language */
%type  <leaf>	standard_function_name_no_clashes
%type  <leaf>	standard_function_name_simpleop_clashes
%type  <leaf>	standard_function_name_expression_clashes
/* helper symbols for ST language */
%type  <leaf>	standard_function_name_NOT_clashes
%type  <leaf>	standard_function_name_no_NOT_clashes

%type  <leaf>	derived_function_name
%type  <leaf>	function_declaration
/* helper symbol for function_declaration */
%type  <leaf>	function_name_declaration
%type  <leaf>	io_var_declarations
%type  <leaf>	function_var_decls
%type  <leaf>	function_body
%type  <leaf>	var2_init_decl
/* intermediate helper symbol for function_declaration */
%type  <list>	io_OR_function_var_declarations_list
/* intermediate helper symbol for function_var_decls */
%type  <list>	var2_init_decl_list

%token <ID>	standard_function_name_token

%token FUNCTION
%token END_FUNCTION
%token CONSTANT


/*****************************/
/* B 1.5.2 - Function Blocks */
/*****************************/
%type  <leaf>	function_block_type_name
%type  <leaf>	standard_function_block_name
%type  <leaf>	derived_function_block_name
%type  <leaf>	function_block_declaration
%type  <leaf>	other_var_declarations
%type  <leaf>	temp_var_decls
%type  <leaf>	non_retentive_var_decls
%type  <leaf>	function_block_body
/* intermediate helper symbol for function_declaration */
%type  <list>	io_OR_other_var_declarations_list
/* intermediate helper symbol for temp_var_decls */
%type  <list>	temp_var_decls_list

%token <ID>	standard_function_block_name_token

%token FUNCTION_BLOCK
%token END_FUNCTION_BLOCK
%token VAR_TEMP
// %token END_VAR
%token VAR
// %token NON_RETAIN
// %token END_VAR


/**********************/
/* B 1.5.3 - Programs */
/**********************/
%type  <leaf>	program_type_name
%type  <leaf>	program_declaration
/* helper symbol for program_declaration */
%type  <list>	program_var_declarations_list

%token PROGRAM
%token END_PROGRAM


/********************************************/
/* B 1.6 Sequential Function Chart elements */
/********************************************/

%type  <list>	sequential_function_chart
%type  <list>	sfc_network
%type  <leaf>	initial_step
%type  <leaf>	step
%type  <list>	action_association_list
%type  <leaf>	step_name
%type  <leaf>	action_association
/* helper symbol for action_association */
%type  <list>	indicator_name_list
%type  <leaf>	action_name
%type  <leaf>	action_qualifier
%type  <leaf>	qualifier
%type  <leaf>	timed_qualifier
%type  <leaf>	action_time
%type  <leaf>	indicator_name
%type  <leaf>	transition
%type  <leaf>	steps
%type  <list>	step_name_list
%type  <leaf>	transition_condition
%type  <leaf>	action
%type  <leaf>	transition_name


// %token ASSIGN
%token ACTION
%token END_ACTION

%token TRANSITION
%token END_TRANSITION
%token FROM
%token TO
%token PRIORITY

%token INITIAL_STEP
%token STEP
%token END_STEP

%token L
%token D
%token SD
%token DS
%token SL

%token N
%token P
/* NOTE: the following two clash with the R and S IL operators.
 * It will have to be handled when we include parsing of SFC...
 */
/*
%token R
%token S
*/


/********************************/
/* B 1.7 Configuration elements */
/********************************/
%type  <leaf>	configuration_name
%type  <leaf>	resource_type_name
%type  <leaf>	configuration_declaration
// helper symbol for
//  - configuration_declaration
//  - resource_declaration
//
%type  <leaf>	optional_global_var_declarations
// helper symbol for configuration_declaration
%type  <leaf>	optional_access_declarations
// helper symbol for configuration_declaration
%type  <leaf>	optional_instance_specific_initializations
// helper symbol for configuration_declaration
%type  <list>	resource_declaration_list
%type  <leaf>	resource_declaration
%type  <leaf>	single_resource_declaration
// helper symbol for single_resource_declaration
%type  <list>	task_configuration_list
// helper symbol for single_resource_declaration
%type  <list>	program_configuration_list
%type  <leaf>	resource_name
// %type  <leaf>	access_declarations
// helper symbol for access_declarations
// %type  <leaf>	access_declaration_list
// %type  <leaf>	access_declaration
// %type  <leaf>	access_path
// helper symbol for access_path
%type  <list>	any_fb_name_list
%type  <leaf>	global_var_reference
// %type  <leaf>	access_name
%type  <leaf>	program_output_reference
%type  <leaf>	program_name
// %type  <leaf>	direction
%type  <leaf>	task_configuration
%type  <leaf>	task_name
%type  <leaf>	task_initialization
// 3 helper symbols for task_initialization
%type  <leaf>	task_initialization_single
%type  <leaf>	task_initialization_interval
%type  <leaf>	task_initialization_priority

%type  <leaf>	data_source
%type  <leaf>	program_configuration
// helper symbol for program_configuration
%type  <leaf>	optional_task_name
// helper symbol for program_configuration
%type  <leaf>	optional_prog_conf_elements
%type  <list>	prog_conf_elements
%type  <leaf>	prog_conf_element
%type  <leaf>	fb_task
%type  <leaf>	prog_cnxn
%type  <leaf>	prog_data_source
%type  <leaf>	data_sink
%type  <leaf>	instance_specific_initializations
// helper symbol for instance_specific_initializations
%type  <list>	instance_specific_init_list
%type  <leaf>	instance_specific_init
// helper symbol for instance_specific_init
%type  <leaf>	fb_initialization

%type  <leaf>	prev_declared_global_var_name
%token  <ID>	prev_declared_global_var_name_token

%type  <leaf>	prev_declared_program_name
%token  <ID>	prev_declared_program_name_token

%type  <leaf>	prev_declared_resource_name
%token  <ID>	prev_declared_resource_name_token

%token  <ID>	prev_declared_configuration_name_token

// %type  <leaf>	prev_declared_task_name
// %token  <ID>	prev_declared_task_name_token

%token CONFIGURATION
%token END_CONFIGURATION
%token TASK
%token RESOURCE
%token ON
%token END_RESOURCE
%token VAR_CONFIG
%token VAR_ACCESS
// %token END_VAR
%token WITH
// %token PROGRAM
// %token RETAIN
// %token NON_RETAIN
// %token PRIORITY
%token SINGLE
%token INTERVAL
%token READ_WRITE
%token READ_ONLY


/***********************************/
/* B 2.1 Instructions and Operands */
/***********************************/
%type  <list>	instruction_list
%type  <leaf>	il_instruction
%type  <leaf>	il_incomplete_instruction
%type  <leaf>	label
%type  <leaf>	il_simple_operation
// helper symbol for il_simple_operation
//%type <tmp_symbol> il_simple_operator_clash_il_operand
%type  <leaf>	il_expression
%type  <leaf>	il_jump_operation
%type  <leaf>	il_fb_call
%type  <leaf>	il_formal_funct_call
// helper symbol for il_formal_funct_call
%type  <leaf> il_expr_operator_clash_eol_list
%type  <leaf>	il_operand
%type  <list>	il_operand_list
// helper symbol for il_simple_operation
%type  <list>	il_operand_list2
%type  <list>	simple_instr_list
%type  <leaf>	il_simple_instruction
%type  <list>	il_param_list
%type  <list>	il_param_instruction_list
%type  <leaf>	il_param_instruction
%type  <leaf>	il_param_last_instruction
%type  <leaf>	il_param_assignment
%type  <leaf>	il_param_out_assignment

%token EOL


/*******************/
/* B 2.2 Operators */
/*******************/
%token <ID>	sendto_identifier_token
%type  <leaf>	sendto_identifier

%type  <leaf>	LD_operator
%type  <leaf>	LDN_operator
%type  <leaf>	ST_operator
%type  <leaf>	STN_operator
%type  <leaf>	NOT_operator
%type  <leaf>	S_operator
%type  <leaf>	R_operator
%type  <leaf>	S1_operator
%type  <leaf>	R1_operator
%type  <leaf>	CLK_operator
%type  <leaf>	CU_operator
%type  <leaf>	CD_operator
%type  <leaf>	PV_operator
%type  <leaf>	IN_operator
%type  <leaf>	PT_operator
%type  <leaf>	AND_operator
%type  <leaf>	AND2_operator
%type  <leaf>	OR_operator
%type  <leaf>	XOR_operator
%type  <leaf>	ANDN_operator
%type  <leaf>	ANDN2_operator
%type  <leaf>	ORN_operator
%type  <leaf>	XORN_operator
%type  <leaf>	ADD_operator
%type  <leaf>	SUB_operator
%type  <leaf>	MUL_operator
%type  <leaf>	DIV_operator
%type  <leaf>	MOD_operator
%type  <leaf>	GT_operator
%type  <leaf>	GE_operator
%type  <leaf>	EQ_operator
%type  <leaf>	LT_operator
%type  <leaf>	LE_operator
%type  <leaf>	NE_operator
%type  <leaf>	CAL_operator
%type  <leaf>	CALC_operator
%type  <leaf>	CALCN_operator
%type  <leaf>	RET_operator
%type  <leaf>	RETC_operator
%type  <leaf>	RETCN_operator
%type  <leaf>	JMP_operator
%type  <leaf>	JMPC_operator
%type  <leaf>	JMPCN_operator

%type  <leaf>	il_simple_operator
%type  <leaf>	il_simple_operator_clash
%type  <leaf>	il_simple_operator_clash1
%type  <leaf>	il_simple_operator_clash2
%type  <leaf>	il_simple_operator_noclash

//%type  <leaf>	il_expr_operator
%type  <leaf>	il_expr_operator_clash
%type  <leaf>	il_expr_operator_noclash

%type  <leaf>	il_assign_operator
%type  <leaf>	il_assign_out_operator
%type  <leaf>	il_call_operator
%type  <leaf>	il_return_operator
%type  <leaf>	il_jump_operator


%token LD
%token LDN
%token ST
%token STN
%token NOT
%token S
%token R
%token S1
%token R1
%token CLK
%token CU
%token CD
%token PV
%token IN
%token PT
%token AND
%token AND2  /* character '&' in the source code*/
%token OR
%token XOR
%token ANDN
%token ANDN2 /* characters '&N' in the source code */
%token ORN
%token XORN
%token ADD
%token SUB
%token MUL
%token DIV
%token MOD
%token GT
%token GE
%token EQ
%token LT
%token LE
%token NE
%token CAL
%token CALC
%token CALCN
%token RET
%token RETC
%token RETCN
%token JMP
%token JMPC
%token JMPCN

%token SENDTO   /* "=>" */


/***********************/
/* B 3.1 - Expressions */
/***********************/
/* NOTE:
 *
 *    - unary_operator, multiply_operator,
 *      add_operator and comparison_operator
 *      are not required. Their values are integrated
 *      directly into other rules...
 */
%type  <leaf>	expression
%type  <leaf>	xor_expression
%type  <leaf>	and_expression
%type  <leaf>	comparison
%type  <leaf>	equ_expression
// %type  <leaf>	comparison_operator
%type  <leaf>	add_expression
// %type  <leaf>	add_operator
%type  <leaf>	term
// %type  <leaf>	multiply_operator
%type  <leaf>	power_expression
%type  <leaf>	unary_expression
// %type  <leaf>	unary_operator
%type  <leaf>	primary_expression
/* intermediate helper symbol for primary_expression */
%type  <leaf>	function_invocation

// %token AND
// %token XOR
// %token OR
// %token MOD
// %token NOT
%token OPER_NE
%token OPER_GE
%token OPER_LE
%token OPER_EXP


/********************/
/* B 3.2 Statements */
/********************/
%type <list> statement_list
%type <leaf> statement



/*********************************/
/* B 3.2.1 Assignment Statements */
/*********************************/
%type <leaf> assignment_statement
// %token ASSIGN   /* ":=" */


/*****************************************/
/* B 3.2.2 Subprogram Control Statements */
/*****************************************/
%type <leaf>	subprogram_control_statement
%type <leaf>	return_statement
%type <leaf>	fb_invocation
// %type <leaf>	param_assignment
%type <leaf>	param_assignment_formal
%type <leaf>	param_assignment_nonformal
/* helper symbols for fb_invocation */
%type <list> param_assignment_formal_list
%type <list> param_assignment_nonformal_list

// %token ASSIGN
// %token SENDTO   /* "=>" */
%token RETURN


/********************************/
/* B 3.2.3 Selection Statements */
/********************************/
%type <leaf>	selection_statement
%type <leaf>	if_statement
%type <leaf>	case_statement
%type <leaf>	case_element
%type <list>	case_list
%type <leaf>	case_list_element
/* helper symbol for if_statement */
%type <list>	elseif_statement_list
/* helper symbol for elseif_statement_list */
%type <leaf>	elseif_statement
/* helper symbol for case_statement */
%type <list>	case_element_list

%token IF
%token THEN
%token ELSIF
%token ELSE
%token END_IF

%token CASE
// %token OF
// %token ELSE
%token END_CASE



/********************************/
/* B 3.2.4 Iteration Statements */
/********************************/
%type <leaf>	iteration_statement
%type <leaf>	for_statement
%type <leaf>	control_variable
%type <leaf>	while_statement
%type <leaf>	repeat_statement
%type <leaf>	exit_statement
/* Integrated directly into for_statement */
// %type <leaf>	for_list

%token FOR
// %token ASSIGN
// %token TO
%token BY
%token DO
%token END_FOR

%token WHILE
// %token DO
%token END_WHILE

%token REPEAT
%token UNTIL
%token END_REPEAT

%token EXIT

%%




/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/
/********************************************************/





/*****************************/
/* Prelimenary constructs... */
/*****************************/
start:
  library	{$$ = $1;}
;

/* the pragmas... */
pragma:
  pragma_token	{$$ = new pragma_c($1, locloc(@$));}



/* NOTE:
 *       short version:
 *       identifier is used for previously undeclared identifiers
 *       any_identifier is used when any identifier, previously
 *       declared or not, is required in the syntax.
 *
 *       long version:
 *       When flex comes across an identifier, it first
 *       searches through the currently declared variables,
 *       functions, types, etc... to determine if it has
 *       been previously declared.
 *       Only if the identifier has not yet been declared
 *       will it return an identifier_token (later turned into
 *       an identifier symbol by the bison generated syntax parser).
 *
 *       Some constructs in the syntax, such as when calling
 *       a function 'F(var1 := 1; var2 := 2);', will accept _any_
 *       identifier in 'var1', even if it has been previously
 *       declared in the current scope, since var1 belongs to
 *       another scope (the variables declared in function F).
 *
 *       For the above reason, we need to define the symbol
 *       any_identifier. All the symbols that may become an
 *       any_identifier are expected to be stored in the
 *       abstract syntax as a identifier_c
 */
/* NOTE:
 *  Type names, function names, function block type names and
 *  program type names are considerd keywords once they are defined,
 *  so may no longer be used for variable names!
 *  BUT the spec is confusing on this issue, as it is not clear when
 *  a function name should be considered as defined. If it is to be
 *  considered defined only from the location from where it is declared
 *  and onwards, it means that before it is declared its name may be
 *  used for variable names!
 *  This means that we must allow names previously used for functions
 *  (et. al.) to also constitue an any_identifier!
 */
any_identifier:
  identifier
| prev_declared_fb_name
| prev_declared_variable_name
/**/
| prev_declared_enumerated_type_name
| prev_declared_simple_type_name
| prev_declared_subrange_type_name
| prev_declared_array_type_name
| prev_declared_structure_type_name
| prev_declared_string_type_name
| prev_declared_derived_function_name
| prev_declared_derived_function_block_name
| prev_declared_program_type_name
/**/
| prev_declared_resource_name
| prev_declared_program_name
| prev_declared_global_var_name
;




prev_declared_variable_name: prev_declared_variable_name_token {$$ = new identifier_c($1, locloc(@$));};
prev_declared_fb_name: prev_declared_fb_name_token {$$ = new identifier_c($1, locloc(@$));};

prev_declared_simple_type_name: prev_declared_simple_type_name_token {$$ = new identifier_c($1, locloc(@$));};
prev_declared_subrange_type_name: prev_declared_subrange_type_name_token {$$ = new identifier_c($1, locloc(@$));};
prev_declared_enumerated_type_name: prev_declared_enumerated_type_name_token {$$ = new identifier_c($1, locloc(@$));};
prev_declared_array_type_name: prev_declared_array_type_name_token {$$ = new identifier_c($1, locloc(@$));};
prev_declared_structure_type_name: prev_declared_structure_type_name_token {$$ = new identifier_c($1, locloc(@$));};
prev_declared_string_type_name: prev_declared_string_type_name_token {$$ = new identifier_c($1, locloc(@$));};

prev_declared_derived_function_name: prev_declared_derived_function_name_token {$$ = new identifier_c($1, locloc(@$));};
prev_declared_derived_function_block_name: prev_declared_derived_function_block_name_token {$$ = new identifier_c($1, locloc(@$));};
prev_declared_program_type_name: prev_declared_program_type_name_token {$$ = new identifier_c($1, locloc(@$));};





/***************************/
/* B 0 - Programming Model */
/***************************/
library:
  /* empty */
	{if (tree_root == NULL)
	  tree_root = new library_c();
	 $$ = (list_c *)tree_root;
	}
| library library_element_declaration
	{$$ = $1; $$->add_element($2);}
/* ERROR_CHECK_BEGIN */
| library error END_OF_INPUT
	{$$ = NULL;
	 print_err_msg(current_filename, locf(@2), locl(@2), "unknown error.");
	 yyerrok;
	}
/* ERROR_CHECK_END */
;


library_element_declaration:
  data_type_declaration
| function_declaration
| function_block_declaration
| program_declaration
| configuration_declaration
;



/*******************************************/
/* B 1.1 - Letters, digits and identifiers */
/*******************************************/
/* NOTE: the spec defines identifier as:
 *         identifier ::= (letter|('_' (letter|digit))) {['_'] (letter|digit)}
 *       In essence, any sequence of letters or digits, starting with a letter
 *       or '_'.
 *
 *       On section 2.1.3 (pg 26) , the spec states
 *       "The keywords listed in annex C shall not be used for any other purpose,
 *         e.g., variable names or extensions as defined in 1.5.1."
 *       (NOTE: the spec itself does not follow this rule, as it defines standard
 *       functions with names identidal to keywords, e.g. 'MOD', 'NOT' !!. This is
 *       another issue altogether, and is worked around somewhere else...)
 *
 *       This means that we must re-define indentifier so as to exclude
 *       any keywords defined in annex C.
 *
 *       Note also that the list includes
 *          - Data type names
 *          - Function names
 *          - Function Block names
 *       This means that any named used for a function name, data type name
 *       or function block name, essentially becomes a keyword, and may therefore
 *       no longer be re-used for any other use! (see NOTE 2)
 *
 *       In our case, excluding the keywords is achieved in the lexical parser,
 *       by two mechanisms:
 *         (1) giving higher priority to the keywords (tokens) than to identifiers,
 *             so when the lexical parser finds a keyword it will be parsed as a
 *             token before being parsed as an identifier.
 *         (2) when an identifier is found that is not a keyword, the lexical parser
 *             then looks in the global symbol table, and will not return an identifier
 *             if the name has been previously used as a data type name, function name,
 *             or function block name! (In these cases it will return a
 *             prev_declared_function_name_token, etc...).
 *
 *       Unfortunately, the language (especially IL) uses tokens that are
 *       not defined as keywords in the spec (e.g. 'IN', 'R1', 'S1', 'PT', etc...)!
 *       This means that it is valid to name a function 'IN', a variable 'PT', etc...
 *       In order to solve this potential ambiguity, flex only parses the above 
 *       identifiers as keywords / tokens if we are currently parsing IL code.
 *       When parsing all code other than IL code, the above identifiers are treated
 *       just like any other identifier.
 *
 *
 *
 *
 * NOTE 2:
 *         I (Mario) find it strange that the writers of the spec really want
 *         names previously used for function names, data type names or function
 *         block names, to become full fledged keywords. I understand that they
 *         do not want these names being used as variable names, but how about
 *         enumeration values? How about structure element names?
 *         If we interpret the spec literally, these would not be accepted,
 *         which would probably burden the programmer quite a bit, in making sure
 *         all these name don't clash!
 *
 *
 *
 * NOTE 3: The keywords, as specified in Annex C are...
 *
 *          - Data type names
 *          - Function names
 *          - Function Block names
 *          - ACTION...END_ACTION
 *          - ARRAY...OF
 *          - AT
 *          - CASE...OF...ELSE...END_CASE
 *          - CONFIGURATION...END_CONFIGURATION
 *          - CONSTANT
 *          - EN, ENO
 *          - EXIT
 *          - FALSE
 *          - F_EDGE
 *          - FOR...TO...BY...DO...END_FOR
 *          - FUNCTION...END_FUNCTION
 *          - FUNCTION_BLOCK...END_FUNCTION_BLOCK
 *          - IF...THEN...ELSIF...ELSE...END_IF
 *          - INITIAL_STEP...END_STEP
 *          - NOT, MOD, AND, XOR, OR
 *          - PROGRAM...WITH...
 *          - PROGRAM...END_PROGRAM
 *          - R_EDGE
 *          - READ_ONLY, READ_WRITE
 *          - REPEAT...UNTIL...END_REPEAT
 *          - RESOURCE...ON...END_RESOURCE
 *          - RETAIN, NON_RETAIN
 *          - RETURN
 *          - STEP...END_STEP
 *          - STRUCT...END_STRUCT
 *          - TASK
 *          - TRANSITION...FROM...TO...END_TRANSITION
 *          - TRUE
 *          - TYPE...END_TYPE
 *          - VAR...END_VAR
 *          - VAR_INPUT...END_VAR
 *          - VAR_OUTPUT...END_VAR
 *          - VAR_IN_OUT...END_VAR
 *          - VAR_TEMP...END_VAR
 *          - VAR_EXTERNAL...END_VAR
 *          - VAR_ACCESS...END_VAR
 *          - VAR_CONFIG...END_VAR
 *          - VAR_GLOBAL...END_VAR
 *          - WHILE...DO...END_WHILE
 *          - WITH
 */

identifier:
  identifier_token	{$$ = new identifier_c($1, locloc(@$));}
;



/*********************/
/* B 1.2 - Constants */
/*********************/
constant:
  numeric_literal
| character_string
| time_literal
| bit_string_literal
| boolean_literal
/* NOTE: in order to remove reduce/reduce conflicts,
 * 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, locloc(@$));}
| fixed_point_token	{$$ = new real_c($1, locloc(@$));}
;

integer:	integer_token		{$$ = new integer_c($1, locloc(@$));};
binary_integer:	binary_integer_token	{$$ = new binary_integer_c($1, locloc(@$));};
octal_integer:	octal_integer_token	{$$ = new octal_integer_c($1, locloc(@$));};
hex_integer:	hex_integer_token	{$$ = new hex_integer_c($1, locloc(@$));};

numeric_literal:
  integer_literal
| real_literal
;

/* 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, locf(@1), locl(@3));}
| integer_type_name '#' binary_integer
	{$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));}
| integer_type_name '#' octal_integer
	{$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));}
| integer_type_name '#' hex_integer
	{$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));}
/* NOTE: see note in the definition of constant for reason
 * why signed_integer, binary_integer, octal_integer
 * and hex_integer are missing here!
 */
;

signed_integer:
  integer
| '+' integer   {$$ = $2;}
| '-' integer	{$$ = new neg_literal_c($2, locloc(@$));}
;

/* 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, locf(@1), locl(@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, locf(@1), locl(@3));}
;

signed_real:
  real
| '+' real	{$$ = $2;}
| '-' real	{$$ = new neg_literal_c($2, locloc(@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, locf(@1), locl(@3));}
| bit_string_type_name '#' binary_integer
	{$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));}
| bit_string_type_name '#' octal_integer
	{$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));}
| bit_string_type_name '#' hex_integer
	{$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));}
/* NOTE: see note in the definition of constant for reason
 * why unsigned_integer, binary_integer, octal_integer
 * and hex_integer are missing here!
 */
/* NOTE: see note under the B 1.2.1 section of token
 * and grouping type definition for reason why the use of
 * bit_string_type_name, although seemingly incorrect, is
 * really correct here!
 */
;


boolean_literal:
  TRUE	{$$ = new boolean_literal_c(new bool_type_name_c(locloc(@$)),
  				    new boolean_true_c(locloc(@$)),
				    locloc(@$));}
| FALSE	{$$ = new boolean_literal_c(new bool_type_name_c(locloc(@$)),
				    new boolean_false_c(locloc(@$)),
				    locloc(@$));}
/*
|	BOOL '#' '1' {}
|	BOOL '#' '0' {}
*/
/* NOTE: the rules
 * BOOL '#' '1'
 * and
 * BOOL '#' '0'
 * do not work as expected...
 * Consider that we are using 'BOOL' and '#' as tokens
 * that flex hands over to bison (yacc). Because flex would
 * then parse the single '1' or '0' as an integer,
 * the rule in bison would have to be
 * BOOL '#' integer, followed by verifying of the
 * integer has the correct value!
 *
 * We therefore have flex return TRUE whenever it
 * comes across 'TRUE' or 'BOOL#1', and FALSE whenever
 * it comes across 'FALSE' or 'BOOL#0'.
 * Note that this means that flex will parse "BOOL#01"
 * as FALSE followed by an integer ('1').
 * Bison should detect this as an error, so we should
 * be OK.
 *
 * Another option would be to change the rules to accept
 * BOOL '#' integer
 * but then check whether the integer has a correct
 * value! At the moment I feel that the first option
 * is more straight forward.
 */
;



/*******************************/
/* B 1.2.2 - Character Strings */
/*******************************/
/* Transform the tokens given us by flex into leafs */
single_byte_character_string:	single_byte_character_string_token
	{$$ = new single_byte_character_string_c($1, locloc(@$));};

double_byte_character_string:	double_byte_character_string_token
	{$$ = new double_byte_character_string_c($1, locloc(@$));};


character_string:
  single_byte_character_string
| double_byte_character_string
;





/***************************/
/* B 1.2.3 - Time Literals */
/***************************/
time_literal:
  time_of_day
| date
| date_and_time
| duration
;


/************************/
/* B 1.2.3.1 - Duration */
/************************/
duration:
/*  (T | TIME) '#' ['-'] interval */
/* NOTE: since TIME is also a data type, it is a keyword
 *       and may therefore be handled by a token.
 *
 *       Unfortunately T is not a data type, and therefore
 *       not a keyword. This means that we may have variables named T!
 *       Flex cannot return the token TIME when it comes across a single T!
 *
 *       We therefore have flex returning the token T_SHARP
 *       when it comes across 'T#'
 */
  TIME '#' interval
	{$$ = new duration_c(NULL, $3, locloc(@$));}
| TIME '#' '-' interval
	{$$ = new duration_c(new neg_time_c(locloc(@$)), $4, locloc(@$));}
| T_SHARP interval
	{$$ = new duration_c(NULL, $2, locloc(@$));}
| T_SHARP '-' interval
	{$$ = new duration_c(new neg_time_c(locloc(@$)), $3, locloc(@$));}
;


interval:
  days
| hours
| minutes
| seconds
| milliseconds
;

integer_d:  integer_d_token  {$$ = new integer_c($1, locloc(@$));};
integer_h:  integer_h_token  {$$ = new integer_c($1, locloc(@$));};
integer_m:  integer_m_token  {$$ = new integer_c($1, locloc(@$));};
integer_s:  integer_s_token  {$$ = new integer_c($1, locloc(@$));};
integer_ms: integer_ms_token {$$ = new integer_c($1, locloc(@$));};

fixed_point_d:
  fixed_point_d_token
	{$$ = new fixed_point_c($1, locloc(@$));}
| integer_d
;

fixed_point_h:
  fixed_point_h_token
	{$$ = new fixed_point_c($1, locloc(@$));}
| integer_h
;

fixed_point_m:
  fixed_point_m_token
	{$$ = new fixed_point_c($1, locloc(@$));}
| integer_m
;

fixed_point_s:
  fixed_point_s_token
	{$$ = new fixed_point_c($1, locloc(@$));}
| integer_s
;

fixed_point_ms:
  fixed_point_ms_token
	{$$ = new fixed_point_c($1, locloc(@$));}
| integer_ms
;


fixed_point:
  fixed_point_token
	{$$ = new fixed_point_c($1, locloc(@$));}
| integer
;


days:
/*  fixed_point ('d') */
  fixed_point_d
	{$$ = new days_c($1, NULL, locloc(@$));}
/*| integer ('d') ['_'] hours */
| integer_d hours
	{$$ = new days_c($1, $2, locloc(@$));}
| integer_d '_' hours
	{$$ = new days_c($1, $3, locloc(@$));}
;


hours:
/*  fixed_point ('h') */
  fixed_point_h
	{$$ = new hours_c($1, NULL, locloc(@$));}
/*| integer ('h') ['_'] minutes */
| integer_h minutes
	{$$ = new hours_c($1, $2, locloc(@$));}
| integer_h '_' minutes
	{$$ = new hours_c($1, $3, locloc(@$));}
;

minutes:
/*  fixed_point ('m') */
  fixed_point_m
	{$$ = new minutes_c($1, NULL, locloc(@$));}
/*| integer ('m') ['_'] seconds */
| integer_m seconds
	{$$ = new minutes_c($1, $2, locloc(@$));}
| integer_m '_' seconds
	{$$ = new minutes_c($1, $3, locloc(@$));}
;

seconds:
/*  fixed_point ('s') */
  fixed_point_s
	{$$ = new seconds_c($1, NULL, locloc(@$));}
/*| integer ('s') ['_'] milliseconds */
| integer_s milliseconds
	{$$ = new seconds_c($1, $2, locloc(@$));}
| integer_s '_' milliseconds
	{$$ = new seconds_c($1, $3, locloc(@$));}
;

milliseconds:
/*  fixed_point ('ms') */
  fixed_point_ms
	{$$ = new milliseconds_c($1, locloc(@$));}
;



/************************************/
/* B 1.2.3.2 - Time of day and Date */
/************************************/
time_of_day:
  TIME_OF_DAY '#' daytime
	{$$ = new time_of_day_c($3, locloc(@$));}
;


daytime:
  day_hour ':' day_minute ':' day_second
	{$$ = new daytime_c($1, $3, $5, locloc(@$));}
;


day_hour: integer;
day_minute: integer;
day_second: fixed_point;


date:
  DATE '#' date_literal
	{$$ = new date_c($3, locloc(@$));}
| D_SHARP date_literal
	{$$ = new date_c($2, locloc(@$));}
;


date_literal:
  year '-' month '-' day
	{$$ = new date_literal_c($1, $3, $5, locloc(@$));}
;


year: integer;
month: integer;
day: integer;


date_and_time:
  DATE_AND_TIME '#' date_literal '-' daytime
	{$$ = new date_and_time_c($3, $5, locloc(@$));}
;






/**********************/
/* 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(locloc(@$));}
| BOOL		{$$ = new bool_type_name_c(locloc(@$));}
/* NOTE: see note under the B 1.2.1 section of token
 * and grouping type definition for reason why BOOL
 * was added to this definition.
 */
;

numeric_type_name:
  integer_type_name
| real_type_name
;

integer_type_name:
  signed_integer_type_name
| unsigned_integer_type_name
;

signed_integer_type_name:
  SINT	{$$ = new sint_type_name_c(locloc(@$));}
| INT	{$$ = new int_type_name_c(locloc(@$));}
| DINT	{$$ = new dint_type_name_c(locloc(@$));}
| LINT	{$$ = new lint_type_name_c(locloc(@$));}
;

unsigned_integer_type_name:
  USINT	{$$ = new usint_type_name_c(locloc(@$));}
| UINT	{$$ = new uint_type_name_c(locloc(@$));}
| UDINT	{$$ = new udint_type_name_c(locloc(@$));}
| ULINT	{$$ = new ulint_type_name_c(locloc(@$));}
;

real_type_name:
  REAL	{$$ = new real_type_name_c(locloc(@$));}
| LREAL	{$$ = new lreal_type_name_c(locloc(@$));}
;

date_type_name:
  DATE		{$$ = new date_type_name_c(locloc(@$));}
| TIME_OF_DAY	{$$ = new tod_type_name_c(locloc(@$));}
| TOD		{$$ = new tod_type_name_c(locloc(@$));}
| DATE_AND_TIME	{$$ = new dt_type_name_c(locloc(@$));}
| DT		{$$ = new dt_type_name_c(locloc(@$));}
;


bit_string_type_name:
  BYTE	{$$ = new byte_type_name_c(locloc(@$));}
| WORD	{$$ = new word_type_name_c(locloc(@$));}
| DWORD	{$$ = new dword_type_name_c(locloc(@$));}
| LWORD	{$$ = new lword_type_name_c(locloc(@$));}
/* NOTE: see note under the B 1.2.1 section of token
 * and grouping type definition for reason why the BOOL
 * was omitted from this definition.
 */
;


/* Helper symbol to concentrate the instantiation
 * of STRING and WSTRING into a single location.
 *
 * These two elements show up in several other rules,
 * but we want to create the equivalent abstract syntax
 * in a single location of this file, in order to make
 * possible future changes easier to edit...
 */
elementary_string_type_name:
  STRING	{$$ = new string_type_name_c(locloc(@$));}
| WSTRING	{$$ = new wstring_type_name_c(locloc(@$));}
;



/********************************/
/* B 1.3.2 - Generic data types */
/********************************/
/* Strangely, the following symbol does not seem to be required! */
/*
generic_type_name:
  ANY
| ANY_DERIVED
| ANY_ELEMENTARY
| ANY_MAGNITUDE
| ANY_NUM
| ANY_REAL
| ANY_INT
| ANY_BIT
| ANY_STRING
| ANY_DATE
;
*/


/********************************/
/* B 1.3.3 - Derived data types */
/********************************/

derived_type_name:
  single_element_type_name
| prev_declared_array_type_name
| prev_declared_structure_type_name
| prev_declared_string_type_name
;

single_element_type_name:
  prev_declared_simple_type_name
/* Include the following if arrays of function blocks are to be allowed!
 * Since the standard does not allow them,
 * we leave it commented out for the time being...
 */
//| prev_declared_derived_function_block_name
| prev_declared_subrange_type_name
| prev_declared_enumerated_type_name
;

/* NOTE: in order to remove a reduce/reduce conflict,
 *       all occurences of simple_type_name, etc...
 *       have been replaced with identifier!
 */
/*
simple_type_name: identifier;
subrange_type_name: identifier;
enumerated_type_name: identifier;
array_type_name: identifier;
structure_type_name: identifier;
*/

data_type_declaration:
  TYPE type_declaration_list END_TYPE
	{$$ = new data_type_declaration_c($2, locloc(@$));}
;

/* helper symbol for data_type_declaration */
type_declaration_list:
  type_declaration ';'
	{$$ = new type_declaration_list_c(locloc(@$)); $$->add_element($1);}
| type_declaration_list type_declaration ';'
	{$$ = $1; $$->add_element($2);}
;

type_declaration:
  single_element_type_declaration
| array_type_declaration
| structure_type_declaration
| string_type_declaration
;

single_element_type_declaration:
  simple_type_declaration
| subrange_type_declaration
| enumerated_type_declaration
;

simple_type_declaration:
/*  simple_type_name ':' simple_spec_init */
  identifier ':' simple_spec_init
	{$$ = new simple_type_declaration_c($1, $3, locloc(@$));
	 library_element_symtable.insert($1, prev_declared_simple_type_name_token);
	}
;


simple_spec_init:
  simple_specification
  /* The following commented line was changed to the 
   * next two lines so that we wouldn't
   * have the first element of a simple_spec_init_c()
   * pointing to another simple_spec_init_c!
   */
/*
| simple_specification ASSIGN constant
	{$$ = new simple_spec_init_c($1, $3);}
*/
| elementary_type_name ASSIGN constant
	{$$ = new simple_spec_init_c($1, $3, locloc(@$));}
| prev_declared_simple_type_name ASSIGN constant
	{$$ = new simple_spec_init_c($1, $3, locloc(@$));}
;

/* When converting to C/C++, we need to know whether
 * the elementary_type_name is being used in a variable
 * declaration or elsewhere (ex. declaration of a derived
 * type), so the abstract syntax has the elementary_type_name
 * wrapped inside a simple_spec_init_c.
 * The exact same thing occurs with prev_declared_simple_type_name.
 *
 * This is why in the definition of simple_spec_init,
 * simple_specification was brocken up into its
 * constituent components...
 */
simple_specification:
// elementary_type_name | simple_type_name
  elementary_type_name
	{$$ = new simple_spec_init_c($1, NULL, locloc(@$));}
| prev_declared_simple_type_name
	{$$ = new simple_spec_init_c($1, NULL, locloc(@$));}
;


subrange_type_declaration:
/*  subrange_type_name ':' subrange_spec_init */
  identifier ':' subrange_spec_init
	{$$ = new subrange_type_declaration_c($1, $3, locloc(@$));
	 library_element_symtable.insert($1, prev_declared_subrange_type_name_token);
	}
;

subrange_spec_init:
  subrange_specification
	{$$ = new subrange_spec_init_c($1, NULL, locloc(@$));}
| subrange_specification ASSIGN signed_integer
	{$$ = new subrange_spec_init_c($1, $3, locloc(@$));}
;

subrange_specification:
  integer_type_name '(' subrange')'
	{$$ = new subrange_specification_c($1, $3, locloc(@$));}
| prev_declared_subrange_type_name
  {$$ = new subrange_specification_c($1, NULL, locloc(@$));}
;


subrange:
  signed_integer DOTDOT signed_integer
	{$$ = new subrange_c($1, $3, locloc(@$));}
;

enumerated_type_declaration:
/*  enumerated_type_name ':' enumerated_spec_init */
  identifier ':' enumerated_spec_init
	{$$ = new enumerated_type_declaration_c($1, $3, locloc(@$));
	 library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);
	}
;


enumerated_spec_init:
  enumerated_specification
	{$$ = new enumerated_spec_init_c($1, NULL, locloc(@$));}
| enumerated_specification ASSIGN enumerated_value
	{$$ = new enumerated_spec_init_c($1, $3, locloc(@$));}
;

enumerated_specification:
  '(' enumerated_value_list ')'
	{$$ = $2;}
| prev_declared_enumerated_type_name
;

/* helper symbol for enumerated_specification */
enumerated_value_list:
  enumerated_value
	{$$ = new enumerated_value_list_c(locloc(@$)); $$->add_element($1);}
| enumerated_value_list ',' enumerated_value
	{$$ = $1; $$->add_element($3);}
;


enumerated_value:
  identifier 
  {$$ = new enumerated_value_c(NULL, $1, locloc(@$));}
| prev_declared_enumerated_type_name '#' any_identifier
	{$$ = new enumerated_value_c($1, $3, locloc(@$));}
;


/*
enumerated_value_without_identifier:
  prev_declared_enumerated_type_name '#' any_identifier
	{$$ = new enumerated_value_c($1, $3, locloc(@$));}
;
*/


array_type_declaration:
/*  array_type_name ':' array_spec_init */
  identifier ':' array_spec_init
	{$$ = new array_type_declaration_c($1, $3, locloc(@$));
	 library_element_symtable.insert($1, prev_declared_array_type_name_token);
	}
;

array_spec_init:
  array_specification
	{$$ = new array_spec_init_c($1, NULL, locloc(@$));}
| array_specification ASSIGN array_initialization
	{$$ = new array_spec_init_c($1, $3, locloc(@$));}
;


array_specification:
  prev_declared_array_type_name
| ARRAY '[' array_subrange_list ']' OF non_generic_type_name
	{$$ = new array_specification_c($3, $6, locloc(@$));}
;

/* helper symbol for array_specification */
array_subrange_list:
  subrange
	{$$ = new array_subrange_list_c(locloc(@$)); $$->add_element($1);}
| array_subrange_list ',' subrange
	{$$ = $1; $$->add_element($3);}
;


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(locloc(@$)); $$->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, locloc(@$));}
;


array_initial_element:
  constant
| enumerated_value
| structure_initialization
| array_initialization
;



structure_type_declaration:
/*  structure_type_name ':' structure_specification */
  identifier ':' structure_specification
	{$$ = new structure_type_declaration_c($1, $3, locloc(@$));
	 library_element_symtable.insert($1, prev_declared_structure_type_name_token);
	}
;


structure_specification:
  structure_declaration
| initialized_structure
;


initialized_structure:
  prev_declared_structure_type_name
	{$$ = new initialized_structure_c($1, NULL, locloc(@$));}
| prev_declared_structure_type_name ASSIGN structure_initialization
	{$$ = new initialized_structure_c($1, $3, locloc(@$));}
;


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(locloc(@$)); $$->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, locloc(@$));}
| structure_element_name ':' subrange_spec_init
	{$$ = new structure_element_declaration_c($1, $3, locloc(@$));}
| structure_element_name ':' enumerated_spec_init
	{$$ = new structure_element_declaration_c($1, $3, locloc(@$));}
| structure_element_name ':' array_spec_init
	{$$ = new structure_element_declaration_c($1, $3, locloc(@$));}
| structure_element_name ':' initialized_structure
	{$$ = new structure_element_declaration_c($1, $3, locloc(@$));}
;


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(locloc(@$)); $$->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, locloc(@$));}
| structure_element_name ASSIGN enumerated_value
	{$$ = new structure_element_initialization_c($1, $3, locloc(@$));}
| structure_element_name ASSIGN array_initialization
	{$$ = new structure_element_initialization_c($1, $3, locloc(@$));}
| structure_element_name ASSIGN structure_initialization
	{$$ = new structure_element_initialization_c($1, $3, locloc(@$));}
;

/* NOTE: in order to remove a reduce/reduce conflict,
 *       all occurences of string_type_name
 *       have been replaced with identifier!
 */
/*
string_type_name: identifier;
*/

string_type_declaration:
/*  string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */
  identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init
	{$$ = new string_type_declaration_c($1, $3, $4, $5, locloc(@$));
	 library_element_symtable.insert($1, prev_declared_string_type_name_token);
	}
;


/* helper symbol for string_type_declaration */
string_type_declaration_size:
  '[' integer ']'
	{$$ = $2;}
/* REMOVED !! */
//|  /* empty */
//	{$$ = NULL;}
;
/* The syntax contains a reduce/reduce conflict.
 * The optional '[' <size> ']'
 * has been changed to become mandatory to remove the conflict.
 *
 * The conflict arises because
 *  new_str_type : STRING := "hello!"
 * may be reduced to a string_type_declaration OR
 * a simple_type_declaration.
 *
 * Our change forces it to be reduced to a
 * simple_type_declaration!
 * We chose this option because changing the definition
 * of simple_spec_init would force us to change all the other
 * rules in which it appears. The change we made has no
 * side-effects!
 */

/* helper symbol for string_type_declaration */
string_type_declaration_init:
  /* empty */
	{$$ = NULL;}
| ASSIGN character_string
	{$$ = $2;}
;



/*********************/
/* B 1.4 - Variables */
/*********************/
variable:
  symbolic_variable
| direct_variable
;


symbolic_variable:
/* NOTE: To be entirely correct, variable_name must be replacemed by
 *         prev_declared_variable_name | prev_declared_fb_name | prev_declared_global_var_name
 */
  prev_declared_fb_name
	{$$ = new symbolic_variable_c($1, locloc(@$));}
| prev_declared_global_var_name
	{$$ = new symbolic_variable_c($1, locloc(@$));}
| prev_declared_variable_name
	{$$ = new symbolic_variable_c($1, locloc(@$));}
| multi_element_variable
/*
| identifier
	{$$ = new symbolic_variable_c($1, locloc(@$));}
*/
;


/* NOTE: in section B 1.7, when configuring a program, symbolic_variable
 *       is used. Nevertheless, during the parsing of a configuration,
 *       the variables in question are out of scope, so we should
 *       be allowing any_identifier instead of prev_declared_variable_name!
 *
 *       We therefore need a new any_symbolic_variable construct that
 *       allows the use of any_identifier instead of previously declared
 *       variables, function blocks, etc...
 */
any_symbolic_variable:
// variable_name -> replaced by any_identifier
  any_identifier
	{$$ = new symbolic_variable_c($1, locloc(@$));}
| any_multi_element_variable
;


/* for yet undeclared variable names ! */
variable_name: identifier;





/********************************************/
/* B.1.4.1   Directly Represented Variables */
/********************************************/
direct_variable: direct_variable_token	{$$ = new direct_variable_c($1, locloc(@$));};




/*************************************/
/* B.1.4.2   Multi-element Variables */
/*************************************/
multi_element_variable:
  array_variable
| structured_variable
;

/* please see note above any_symbolic_variable */
any_multi_element_variable:
  any_array_variable
| any_structured_variable
;


array_variable:
  subscripted_variable '[' subscript_list ']'
	{$$ = new array_variable_c($1, $3, locloc(@$));}
;

/* please see note above any_symbolic_variable */
any_array_variable:
  any_subscripted_variable '[' subscript_list ']'
	{$$ = new array_variable_c($1, $3, locloc(@$));}
;


subscripted_variable:
  symbolic_variable
;


/* please see note above any_symbolic_variable */
any_subscripted_variable:
  any_symbolic_variable
;


subscript_list:
  subscript
	{$$ = new subscript_list_c(locloc(@$)); $$->add_element($1);}
| subscript_list ',' subscript
	{$$ = $1; $$->add_element($3);}
;


subscript:  expression;


structured_variable:
  record_variable '.' field_selector
	{$$ = new structured_variable_c($1, $3, locloc(@$));}
;


/* please see note above any_symbolic_variable */
any_structured_variable:
  any_record_variable '.' field_selector
	{$$ = new structured_variable_c($1, $3, locloc(@$));}
;



record_variable:
  symbolic_variable
;


/* please see note above any_symbolic_variable */
any_record_variable:
  any_symbolic_variable
;


field_selector: any_identifier;






/******************************************/
/* B 1.4.3 - Declaration & Initialisation */
/******************************************/
input_declarations:
  VAR_INPUT            input_declaration_list END_VAR
	{$$ = new input_declarations_c(NULL, $2, locloc(@$));}
| VAR_INPUT RETAIN     input_declaration_list END_VAR
	{$$ = new input_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));}
| VAR_INPUT NON_RETAIN input_declaration_list END_VAR
	{$$ = new input_declarations_c(new non_retain_option_c(locloc(@2)), $3, locloc(@$));}
/* ERROR_CHECK_BEGIN */
| VAR_INPUT error END_VAR
	{$$ = NULL;
	 print_err_msg(current_filename, locf(@1), locl(@3), "error in input variable(s) declaration.");
	 /* yychar */
	 yyerrok;
	}
/* ERROR_CHECK_END */
;

/* helper symbol for input_declarations */
input_declaration_list:
  input_declaration ';'
	{$$ = new input_declaration_list_c(locloc(@$)); $$->add_element($1);}
| input_declaration_list input_declaration ';'
	{$$ = $1; $$->add_element($2);}
;


input_declaration:
  var_init_decl
| edge_declaration
;


edge_declaration:
  var1_list ':' BOOL R_EDGE
	{$$ = new edge_declaration_c(new raising_edge_option_c(locloc(@3)), $1, locloc(@$));}
| var1_list ':' BOOL F_EDGE
	{$$ = new edge_declaration_c(new falling_edge_option_c(locloc(@3)), $1, locloc(@$));}
;


var_init_decl:
  var1_init_decl
| array_var_init_decl
| structured_var_init_decl
| fb_name_decl
| string_var_declaration
;




var1_init_decl:
  var1_list ':' simple_spec_init
	{$$ = new var1_init_decl_c($1, $3, locloc(@$));}
| var1_list ':' subrange_spec_init
	{$$ = new var1_init_decl_c($1, $3, locloc(@$));}
| var1_list ':' enumerated_spec_init
	{$$ = new var1_init_decl_c($1, $3, locloc(@$));}
;


var1_list:
  variable_name
	{$$ = new var1_list_c(locloc(@$)); $$->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, locloc(@$));}
;


structured_var_init_decl:
  var1_list ':' initialized_structure
	{$$ = new structured_var_init_decl_c($1, $3, locloc(@$));}
;


/* NOTE: see notes above fb_name_list and var1_list
 *       for reason why ':' was removed from this rule!
 *       In essence, to remove a shift/reduce conflict,
 *       the ':' was moved to var1_list and fb_name_list!
 */
fb_name_decl:
/*  fb_name_list ':' function_block_type_name */
  fb_name_list_with_colon function_block_type_name
	{$$ = new fb_name_decl_c($1, $2, NULL, locloc(@$));}
/*| fb_name_list ':' function_block_type_name ASSIGN structure_initialization */
| fb_name_list_with_colon function_block_type_name ASSIGN structure_initialization
	{$$ = new fb_name_decl_c($1, $2, $4, locloc(@$));}
;



/* NOTE: In order to remove a reduce/reduce conflict between
 *       var1_list and fb_name_list, which are identical to each
 *       other, fb_name_list has been redefined to be a var1_list.
 *
 *        In order to remove a further shift/reduce conflict, var1_list
 *        is imediately transfomred into var1_list_with_colon
 *        (i.e. it includes the ':' following the list), which
 *        means that fb_name_list is built from a
 *        var1_list_with_colon after all!
 */
/*
fb_name_list:
 (*  fb_name *)
  identifier
	{$$ = new fb_name_list_c($1);
	 variable_name_symtable.insert($1, prev_declared_fb_name_token);
	}
(* | fb_name_list ',' fb_name *)
| fb_name_list ',' identifier
	{$$ = $1; $$->add_element($3);
	 variable_name_symtable.insert($3, prev_declared_fb_name_token);
	}
;
*/

fb_name_list_with_colon:
  var1_list_with_colon
	{$$ = new fb_name_list_c(locloc(@$));
	 /* fill up the new fb_name_list_c object with the references
	  * contained in the var1_list_c object.
	  */
	 FOR_EACH_ELEMENT(elem, $1, {$$->add_element(elem);});
	 delete $1;
	 /* change the tokens associated with the symbols stored in
	  * the variable name symbol table from prev_declared_variable_name_token
	  * to prev_declared_fb_name_token
	  */
	 FOR_EACH_ELEMENT(elem, $$, {variable_name_symtable.set(elem, prev_declared_fb_name_token);});
	}
;

/* helper symbol for fb_name_list_with_colon */
var1_list_with_colon:
  var1_list ':'
;


// fb_name: identifier;



output_declarations:
  VAR_OUTPUT var_init_decl_list END_VAR
	{$$ = new output_declarations_c(NULL, $2, locloc(@$));}
| VAR_OUTPUT RETAIN var_init_decl_list END_VAR
	{$$ = new output_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));}
| VAR_OUTPUT NON_RETAIN var_init_decl_list END_VAR
	{$$ = new output_declarations_c(new non_retain_option_c(locloc(@2)), $3, locloc(@$));}
/* ERROR_CHECK_BEGIN */
| VAR_OUTPUT error END_VAR
	{$$ = NULL;
	 print_err_msg(current_filename, locf(@1), locl(@3), "error in output variable(s) declaration.");
	 /* yychar */
	 yyerrok;
	}
/* ERROR_CHECK_END */
;



input_output_declarations:
  VAR_IN_OUT var_declaration_list END_VAR
	{$$ = new input_output_declarations_c($2, locloc(@$));}
/* ERROR_CHECK_BEGIN */
| VAR_IN_OUT error END_VAR
	{$$ = NULL;
	 print_err_msg(current_filename, locf(@1), locl(@3), "error in in_out variable(s) declaration.");
	 /* yychar */
	 yyerrok;
	}
/* ERROR_CHECK_END */
;



/* helper symbol for input_output_declarations */
var_declaration_list:
  var_declaration ';'
	{$$ = new var_declaration_list_c(locloc(@$)); $$->add_element($1);}
| var_declaration_list var_declaration ';'
	{$$ = $1; $$->add_element($2);}
;


var_declaration:
  temp_var_decl
| fb_name_decl
;


temp_var_decl:
  var1_declaration
| array_var_declaration
| structured_var_declaration
| string_var_declaration
;

var1_declaration:
  var1_list  ':' simple_specification
	{$$ = new var1_init_decl_c($1, $3, locloc(@$));}
| var1_list  ':' subrange_specification
	{$$ = new var1_init_decl_c($1, $3, locloc(@$));}
| var1_list  ':' enumerated_specification
	{$$ = new var1_init_decl_c($1, $3, locloc(@$));}
;



array_var_declaration:
  var1_list ':' array_specification
	{$$ = new array_var_declaration_c($1, $3, locloc(@$));}
;

structured_var_declaration:
  var1_list ':' prev_declared_structure_type_name
	{$$ = new structured_var_declaration_c($1, $3, locloc(@$));}
;


var_declarations:
  VAR var_init_decl_list END_VAR
	{$$ = new var_declarations_c(NULL, $2, locloc(@$));}
| VAR CONSTANT var_init_decl_list END_VAR
	{$$ = new var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));}
;


retentive_var_declarations:
  VAR RETAIN var_init_decl_list END_VAR
	{$$ = new retentive_var_declarations_c($3, locloc(@$));}
/* ERROR_CHECK_BEGIN */
| VAR RETAIN error END_VAR
	{$$ = NULL;
	 print_err_msg(current_filename, locf(@1), locl(@3), "error in variable(s) declaration.");
	 /* yychar */
	 yyerrok;
	}
/* ERROR_CHECK_END */
;


located_var_declarations:
  VAR  located_var_decl_list END_VAR
	{$$ = new located_var_declarations_c(NULL, $2, locloc(@$));}
| VAR CONSTANT located_var_decl_list END_VAR
	{$$ = new located_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));}
| VAR RETAIN located_var_decl_list END_VAR
	{$$ = new located_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));}
| VAR NON_RETAIN located_var_decl_list END_VAR
	{$$ = new located_var_declarations_c(new non_retain_option_c(locloc(@2)), $3, locloc(@$));}
;


/* helper symbol for located_var_declarations */
located_var_decl_list:
  located_var_decl ';'
	{$$ = new located_var_decl_list_c(locloc(@$)); $$->add_element($1);}
| located_var_decl_list located_var_decl ';'
	{$$ = $1; $$->add_element($2);}
;


located_var_decl:
  variable_name location ':' located_var_spec_init
	{$$ = new located_var_decl_c($1, $2, $4, locloc(@$));
	 variable_name_symtable.insert($1, prev_declared_variable_name_token);
	}
| location ':' located_var_spec_init
	{$$ = new located_var_decl_c(NULL, $1, $3, locloc(@$));}
;




external_var_declarations:
  VAR_EXTERNAL external_declaration_list END_VAR
	{$$ = new external_var_declarations_c(NULL, $2, locloc(@$));}
| VAR_EXTERNAL CONSTANT external_declaration_list END_VAR
	{$$ = new external_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));}
/* ERROR_CHECK_BEGIN */
| VAR_EXTERNAL error END_VAR
	{$$ = NULL;
	 print_err_msg(current_filename, locf(@1), locl(@3), "error in external variable(s) declaration.");
	 /* yychar */
	 yyerrok;
	}
/* ERROR_CHECK_END */
;

/* helper symbol for external_var_declarations */
external_declaration_list:
  external_declaration ';'
	{$$ = new external_declaration_list_c(locloc(@$)); $$->add_element($1);}
| external_declaration_list external_declaration';'
	{$$ = $1; $$->add_element($2);}
;


external_declaration:
  global_var_name ':' simple_specification
	{$$ = new external_declaration_c($1, $3, locloc(@$));
	 variable_name_symtable.insert($1, prev_declared_variable_name_token);
	}
| global_var_name ':' subrange_specification
	{$$ = new external_declaration_c($1, $3, locloc(@$));
	 variable_name_symtable.insert($1, prev_declared_variable_name_token);
	}
| global_var_name ':' enumerated_specification
	{$$ = new external_declaration_c($1, $3, locloc(@$));
	 variable_name_symtable.insert($1, prev_declared_variable_name_token);
	}
| global_var_name ':' array_specification
	{$$ = new external_declaration_c($1, $3, locloc(@$));
	 variable_name_symtable.insert($1, prev_declared_variable_name_token);
	}
| global_var_name ':' prev_declared_structure_type_name
	{$$ = new external_declaration_c($1, $3, locloc(@$));
	 variable_name_symtable.insert($1, prev_declared_variable_name_token);
	}
| global_var_name ':' function_block_type_name
	{$$ = new external_declaration_c($1, $3, locloc(@$));
	 variable_name_symtable.insert($1, prev_declared_fb_name_token);
	}
;


global_var_name: identifier;


global_var_declarations:
  VAR_GLOBAL global_var_decl_list END_VAR
	{$$ = new global_var_declarations_c(NULL, $2, locloc(@$));}
| VAR_GLOBAL CONSTANT global_var_decl_list END_VAR
	{$$ = new global_var_declarations_c(new constant_option_c(locloc(@2)), $3, locloc(@$));}
| VAR_GLOBAL RETAIN global_var_decl_list END_VAR
	{$$ = new global_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));}
/* ERROR_CHECK_BEGIN */
| VAR_GLOBAL error END_VAR
	{$$ = NULL;
	 print_err_msg(current_filename, locf(@1), locl(@3), "error in global variable(s) declaration.");
	 /* yychar */
	 yyerrok;
	}
/* ERROR_CHECK_END */
;


/* helper symbol for global_var_declarations */
global_var_decl_list:
  global_var_decl ';'
	{$$ = new global_var_decl_list_c(locloc(@$)); $$->add_element($1);}
| global_var_decl_list global_var_decl ';'
	{$$ = $1; $$->add_element($2);}
;


global_var_decl:
  global_var_spec ':'
	{$$ = new global_var_decl_c($1, NULL, locloc(@$));}
| global_var_spec ':' located_var_spec_init
	{$$ = new global_var_decl_c($1, $3, locloc(@$));}
| global_var_spec ':' function_block_type_name
	{$$ = new global_var_decl_c($1, $3, locloc(@$));}
;


global_var_spec:
  global_var_list	{$$ = $1;}
| location
	{$$ = new global_var_spec_c(NULL, $1, locloc(@$));}
| global_var_name location
	{$$ = new global_var_spec_c($1, $2, locloc(@$));
	 variable_name_symtable.insert($1, prev_declared_global_var_name_token);
	}

;


located_var_spec_init:
  simple_spec_init
| subrange_spec_init
| enumerated_spec_init
| array_spec_init
| initialized_structure
| single_byte_string_spec
| double_byte_string_spec
;


location:
  AT direct_variable
	{$$ = new location_c($2, locloc(@$));}
;



global_var_list:
  global_var_name
	{$$ = new global_var_list_c(locloc(@$)); $$->add_element($1);
	 variable_name_symtable.insert($1, prev_declared_global_var_name_token);
	}
| global_var_list ',' global_var_name
	{$$ = $1; $$->add_element($3);
	 variable_name_symtable.insert($3, prev_declared_global_var_name_token);
	}
;



string_var_declaration:
  single_byte_string_var_declaration
| double_byte_string_var_declaration
;

single_byte_string_var_declaration:
  var1_list ':' single_byte_string_spec
	{$$ = new single_byte_string_var_declaration_c($1, $3, locloc(@$));}
;

/* 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, locloc(@$));}
/*
| STRING ASSIGN single_byte_character_string
	{$$ = new single_byte_string_spec_c(NULL, $3, locloc(@$));}
*/
| STRING '[' integer ']' ASSIGN single_byte_character_string
	{$$ = new single_byte_string_spec_c($3, $6, locloc(@$));}
;


double_byte_string_var_declaration:
  var1_list ':' double_byte_string_spec
	{$$ = new double_byte_string_var_declaration_c($1, $3, locloc(@$));}
;

double_byte_string_spec:
/*  WSTRING
	{$$ = new double_byte_string_spec_c(NULL, NULL, locloc(@$));}
*/
  WSTRING '[' integer ']'
	{$$ = new double_byte_string_spec_c($3, NULL, locloc(@$));}
/*
| WSTRING ASSIGN double_byte_character_string
	{$$ = new double_byte_string_spec_c(NULL, $3, locloc(@$));}
*/
| WSTRING '[' integer ']' ASSIGN double_byte_character_string
	{$$ = new double_byte_string_spec_c($3, $6, locloc(@$));}
;



incompl_located_var_declarations:
  VAR            incompl_located_var_decl_list END_VAR
	{$$ = new incompl_located_var_declarations_c(NULL, $2, locloc(@$));}
| VAR     RETAIN incompl_located_var_decl_list END_VAR
	{$$ = new incompl_located_var_declarations_c(new retain_option_c(locloc(@2)), $3, locloc(@$));}
| VAR NON_RETAIN incompl_located_var_decl_list END_VAR
	{$$ = new incompl_located_var_declarations_c(new non_retain_option_c(locloc(@2)), $3, locloc(@$));}
;

/* helper symbol for incompl_located_var_declarations */
incompl_located_var_decl_list:
  incompl_located_var_decl ';'
	{$$ = new incompl_located_var_decl_list_c(locloc(@$)); $$->add_element($1);}
| incompl_located_var_decl_list incompl_located_var_decl ';'
	{$$ = $1; $$->add_element($2);}
;


incompl_located_var_decl:
  variable_name incompl_location ':' var_spec
	{$$ = new incompl_located_var_decl_c($1, $2, $4, locloc(@$));}
;


incompl_location:
  AT incompl_location_token
	{$$ = new incompl_location_c($2, locloc(@$));}
;


var_spec:
  simple_specification
| subrange_specification
| enumerated_specification
| array_specification
| prev_declared_structure_type_name
| string_spec
;


/* helper symbol for var_spec */
/* 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, locloc(@$));}
*/
  STRING '[' integer ']'
	{$$ = new single_byte_string_spec_c($3, NULL, locloc(@$));}
/*
| WSTRING
	{$$ = new double_byte_string_spec_c(NULL, NULL, locloc(@$));}
*/
| WSTRING '[' integer ']'
	{$$ = new double_byte_string_spec_c($3, NULL, locloc(@$));}
;




/* 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(locloc(@$)); $$->add_element($1);}
| var_init_decl_list var_init_decl ';'
	{$$ = $1; $$->add_element($2);}
;




/***********************/
/* B 1.5.1 - Functions */
/***********************/
/*
function_name:
  prev_declared_derived_function_name
| standard_function_name 
;
*/

/* The following rules should be set such as:
 * function_name: function_name_no_clashes | function_name_simpleop_clashes | function_name_expression_clashes
 * function_name: function_name_no_NOT_clashes | function_name_NOT_clashes;
 */

function_name_no_clashes: prev_declared_derived_function_name | standard_function_name_no_clashes;
function_name_simpleop_clashes: standard_function_name_simpleop_clashes;
//function_name_expression_clashes: standard_function_name_expression_clashes;

function_name_no_NOT_clashes: prev_declared_derived_function_name | standard_function_name_no_NOT_clashes;
//function_name_NOT_clashes: standard_function_name_NOT_clashes;


/* NOTE: The list of standard function names
 *       includes the standard functions MOD(), NOT()
 *
 *       Strangely enough, MOD and NOT are reserved keywords,
 *       so shouldn't be used for function names.
 *
 *       The specification contradicts itself!
 *       Our workaround  is to treat MOD as a token,
 *       but to include this token as a
 *       standard_function_name.
 *
 *       The names of all other standard functions get
 *       preloaded into the library_element_symbol_table
 *       with the token value of
 *       standard_function_name_token
 *       Actually, simply for completeness, MOD is also
 *       loaded into the library_element_symbol_table, but
 *       it is irrelevant since flex will catch MOD as a
 *       token, before it interprets it as an identifier,
 *       and looks in the library_element_symbol_table to check
 *       whether it has been previously declared.
 *
 * NOTE: The same as the above also occurs with the IL
 *       operators NOT AND OR XOR ADD SUB MUL DIV MOD
 *       GT GE EQ LT LE NE.
 *       Note that MOD is once again in the list!
 *       Anyway, we give these the same treatement as
 *       MOD, since we are writing a parser for ST and
 *       IL simultaneously. If this were not the case,
 *       the ST parser would not need the tokens NOT AND ...
 *
 * NOTE: Note that 'NOT' is special, as it conflicts
 *       with two operators: the  IL 'NOT' operator, and
 *       the unary operator 'NOT' in ST!!
 *
 * NOTE: The IL language is ambiguous, since using NOT, AND, ...
 *       may be interpreted as either an IL operator, or
 *       as a standard function call!
 *       I (Mario) opted to interpret it as an IL operator.
 *       This requires changing the syntax for IL language
 *       function   calling, to exclude all function with
 *       names that clash with IL operators. I therefore
 *       created the constructs
 *       function_name_without_clashes
 *       standard_function_name_without_clashes
 *       to include all function names, except those that clash
 *       with IL operators. These constructs are only used
 *       within the IL language!
 */
/* The following rules should be set such as:
 * standard_function_name: standard_function_name_no_clashes | standard_function_name_simpleop_clashes | standard_function_name_expression_clashes
 * standard_function_name: standard_function_name_no_NOT_clashes | standard_function_name_NOT_clashes;
 */

/*
standard_function_name:
  standard_function_name_no_clashes
| standard_function_name_expression_clashes
| standard_function_name_NOT_clashes
//| standard_function_name_simpleop_only_clashes
;
*/

standard_function_name_no_NOT_clashes:
  standard_function_name_no_clashes
| standard_function_name_expression_clashes
//| standard_function_name_simpleop_only_clashes
;

standard_function_name_no_clashes:
  standard_function_name_token
	{$$ = new identifier_c($1, locloc(@$));}
;


standard_function_name_simpleop_clashes:
  standard_function_name_NOT_clashes
//| standard_function_name_simpleop_only_clashes
;

standard_function_name_NOT_clashes:
  NOT
	{$$ = new identifier_c(strdup("NOT"), locloc(@$));}
;

/* Add here any other IL simple operators that collide
 * with standard function names!
 * Don't forget to uncomment the equivalent lines in
 *   - standard_function_name_simpleop_clashes
 *   - standard_function_name
 *   - standard_function_name_no_NOT_clashes
 */
/*
standard_function_name_simpleop_only_clashes:
;
*/

standard_function_name_expression_clashes:
  AND	{$$ = new identifier_c(strdup("AND"), locloc(@$));}
| OR	{$$ = new identifier_c(strdup("OR"), locloc(@$));}
| XOR	{$$ = new identifier_c(strdup("XOR"), locloc(@$));}
| ADD	{$$ = new identifier_c(strdup("ADD"), locloc(@$));}
| SUB	{$$ = new identifier_c(strdup("SUB"), locloc(@$));}
| MUL	{$$ = new identifier_c(strdup("MUL"), locloc(@$));}
| DIV	{$$ = new identifier_c(strdup("DIV"), locloc(@$));}
| MOD	{$$ = new identifier_c(strdup("MOD"), locloc(@$));}
| GT	{$$ = new identifier_c(strdup("GT"), locloc(@$));}
| GE	{$$ = new identifier_c(strdup("GE"), locloc(@$));}
| EQ	{$$ = new identifier_c(strdup("EQ"), locloc(@$));}
| LT	{$$ = new identifier_c(strdup("LT"), locloc(@$));}
| LE	{$$ = new identifier_c(strdup("LE"), locloc(@$));}
| NE	{$$ = new identifier_c(strdup("NE"), locloc(@$));}
/*
  AND_operator	{$$ = il_operator_c_2_identifier_c($1);}
//NOTE: AND2 (corresponding to the source code string '&') does not clash
//      with a standard function name, so should be commented out!
//| AND2_operator	{$$ = il_operator_c_2_identifier_c($1);}
| OR_operator	{$$ = il_operator_c_2_identifier_c($1);}
| XOR_operator	{$$ = il_operator_c_2_identifier_c($1);}
| ADD_operator	{$$ = il_operator_c_2_identifier_c($1);}
| SUB_operator	{$$ = il_operator_c_2_identifier_c($1);}
| MUL_operator	{$$ = il_operator_c_2_identifier_c($1);}
| DIV_operator	{$$ = il_operator_c_2_identifier_c($1);}
| MOD_operator	{$$ = il_operator_c_2_identifier_c($1);}
| GT_operator	{$$ = il_operator_c_2_identifier_c($1);}
| GE_operator	{$$ = il_operator_c_2_identifier_c($1);}
| EQ_operator	{$$ = il_operator_c_2_identifier_c($1);}
| LT_operator	{$$ = il_operator_c_2_identifier_c($1);}
| LE_operator	{$$ = il_operator_c_2_identifier_c($1);}
| NE_operator	{$$ = il_operator_c_2_identifier_c($1);}
*/
;


derived_function_name:
  identifier
| prev_declared_derived_function_name
	{$$ = $1;
	 if (not(allow_function_overloading)) {
	   fprintf(stderr, "Function overloading not allowed. Invalid identifier %s\n", ((token_c *)($1))->value);
	   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, locloc(@$));
	 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, locloc(@$));
	 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);
	 }
	}
/* ERROR_CHECK_BEGIN */
| FUNCTION error END_FUNCTION
	{$$ = NULL;
	 print_err_msg(current_filename, locf(@1), locl(@3), "error in function declaration.");
	 /* yychar */
	 yyerrok;
	}
/* ERROR_CHECK_END */
;



/* helper symbol for function_declaration */
/* NOTE: due to reduce/reduce conflicts between identifiers
 *       being reduced to either a variable or an enumerator value,
 *       we were forced to keep a symbol table of the names
 *       of all declared variables. Variables are no longer
 *       created from simple identifier_token, but from
 *       prev_declared_variable_name_token.
 *
 *       BUT, in functions the function name itself may be used as
 *       a variable! In order to be able to parse this correctly,
 *       the token parser (flex) must return a prev_declared_variable_name_token
 *       when it comes across the function name, while parsing
 *       the function itself.
 *       We do this by inserting the function name into the variable
 *       symbol table, and having flex return a prev_declared_variable_name_token
 *       whenever it comes across it.
 *       When we finish parsing the function the variable name
 *       symbol table is cleared of all entries, and the function
 *       name is inserted into the library element symbol table. This
 *       means that from then onwards flex will return a
 *       derived_function_name_token whenever it comes across the
 *       function name.
 *
 *       In order to insert the function name into the variable_name
 *       symbol table BEFORE the function body gets parsed, we
 *       need the parser to reduce a construct that contains the
 *       the function name. That is why we created this extra
 *       construct (function_name_declaration), i.e. to force
 *       the parser to reduce it, before parsing the function body!
 */
function_name_declaration:
  FUNCTION derived_function_name
	{$$ = $2;
	 /* the function name functions as a
	  * variable within the function itself!
	  *
	  * Remember that the variable_name_symtable
	  * is cleared once the end of the function
	  * is parsed.
	  */
	 variable_name_symtable.insert($2, prev_declared_variable_name_token);
	}
;



/* intermediate helper symbol for function_declaration */
io_OR_function_var_declarations_list:
  /* empty */
	{$$ = new var_declarations_list_c(locloc(@$));}
| 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(locloc(@2)), $3, locloc(@$));}
| VAR var2_init_decl_list END_VAR
	{$$ = new function_var_decls_c(NULL, $2, locloc(@$));}
;

/* intermediate helper symbol for function_var_decls */
var2_init_decl_list:
  var2_init_decl ';'
	{$$ = new var2_init_decl_list_c(locloc(@$)); $$->add_element($1);}
| var2_init_decl_list var2_init_decl ';'
	{$$ = $1; $$->add_element($2);}
;


function_body:
  statement_list	{$$ = $1;} /* if we leave it for the default action we get a type clash! */
| instruction_list	{$$ = $1;} /* if we leave it for the default action we get a type clash! */
/*
| ladder_diagram
| function_block_diagram
*/
;


var2_init_decl:
  var1_init_decl
| array_var_init_decl
| structured_var_init_decl
| string_var_declaration
;



/*****************************/
/* B 1.5.2 - Function Blocks */
/*****************************/
function_block_type_name:
  prev_declared_derived_function_block_name
| standard_function_block_name
;


standard_function_block_name: standard_function_block_name_token {$$ = new identifier_c($1, locloc(@$));};

derived_function_block_name: identifier;


function_block_declaration:
  FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK
	{$$ = new function_block_declaration_c($2, $3, $4, locloc(@$));
	 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();
	}
/* ERROR_CHECK_BEGIN */
| FUNCTION_BLOCK error END_FUNCTION_BLOCK
	{$$ = NULL;
	 print_err_msg(current_filename, locf(@1), locl(@3), "error in function block declaration.");
	 /* yychar */
	 yyerrok;
	}
/* ERROR_CHECK_END */
;



/* intermediate helper symbol for function_declaration */
/*  { io_var_declarations | other_var_declarations }   */
/*
 * NOTE: we re-use the var_declarations_list_c
 */
io_OR_other_var_declarations_list:
  /* empty */
	{$$ = new var_declarations_list_c(locloc(@$));}
| 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
/* TODO: the following error rule is not working! Must be fixed. */
/* ERROR_CHECK_BEGIN */
| VAR error END_VAR
	{$$ = NULL;
	 print_err_msg(current_filename, locf(@1), locl(@3), "error in variable(s) declaration.");
	 /* yychar */
	 yyerrok;
	}
/* ERROR_CHECK_END */
;


temp_var_decls:
  VAR_TEMP temp_var_decls_list END_VAR
	{$$ = new temp_var_decls_c($2, locloc(@$));}
;


/* intermediate helper symbol for temp_var_decls */
temp_var_decls_list:
  temp_var_decl ';'
	{$$ = new temp_var_decls_list_c(locloc(@$)); $$->add_element($1);}
| temp_var_decls_list temp_var_decl ';'
	{$$ = $1; $$->add_element($2);}
;


non_retentive_var_decls:
  VAR NON_RETAIN var_init_decl_list END_VAR
	{$$ = new non_retentive_var_decls_c($3, locloc(@$));}
;



function_block_body:
  statement_list	{$$ = $1;}
| instruction_list	{$$ = $1;}
| sequential_function_chart	{$$ = $1;}
/*
| ladder_diagram
| function_block_diagram
| <other languages>
*/
;




/**********************/
/* B 1.5.3 - Programs */
/**********************/
program_type_name: identifier;


program_declaration:
  PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM
	{$$ = new program_declaration_c($2, $3, $4, locloc(@$));
	 library_element_symtable.insert($2, prev_declared_program_type_name_token);
	 /* Clear the variable_name_symtable. Since
	  * we have finished parsing the program declaration,
	  * the variable names are now out of scope, so
	  * are no longer valid!
	  */
	 variable_name_symtable.pop();
	}
/* ERROR_CHECK_BEGIN */
| PROGRAM error END_PROGRAM
	{$$ = NULL;
	 print_err_msg(current_filename, locf(@1), locl(@3), "error in function block declaration.");
	 /* yychar */
	 yyerrok;
	}
/* ERROR_CHECK_END */
;


/* helper symbol for program_declaration */
/*
 * NOTE: we re-use the var_declarations_list_c
 */
program_var_declarations_list:
  /* empty */
	{$$ = new var_declarations_list_c(locloc(@$));}
| 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 *
/********************************************/

sequential_function_chart:
  sfc_network
	{$$ = new sequential_function_chart_c(locloc(@$)); $$->add_element($1);}
| sequential_function_chart sfc_network
	{$$ = $1; $$->add_element($2);}
;

sfc_network:
  initial_step
	{$$ = new sfc_network_c(locloc(@$)); $$->add_element($1);}
| sfc_network step
	{$$ = $1; $$->add_element($2);}
| sfc_network transition
	{$$ = $1; $$->add_element($2);}
| sfc_network action
	{$$ = $1; $$->add_element($2);}
;

initial_step:
  INITIAL_STEP step_name ':' action_association_list END_STEP
//  INITIAL_STEP identifier ':' action_association_list END_STEP
	{$$ = new initial_step_c($2, $4, locloc(@$));}
;

step:
  STEP step_name ':' action_association_list END_STEP
//  STEP identifier ':' action_association_list END_STEP
	{$$ = new step_c($2, $4, locloc(@$));}
;

/* helper symbol for:
 *  - initial_step
 *  - step
 */
action_association_list:
  /* empty */
	{$$ = new action_association_list_c(locloc(@$));}
| action_association_list action_association ';'
	{$$ = $1; $$->add_element($2);}
;


// step_name: identifier;
step_name: any_identifier;

action_association:
  action_name '(' {cmd_goto_sfc_qualifier_state()} action_qualifier {cmd_pop_state()} indicator_name_list ')'
	{$$ = new action_association_c($1, $4, $6, locloc(@$));}
;

/* helper symbol for action_association */
indicator_name_list:
  /* empty */
	{$$ = new indicator_name_list_c(locloc(@$));}
| indicator_name_list ',' indicator_name
	{$$ = $1; $$->add_element($3);}
;

// action_name: identifier;
action_name: any_identifier;

action_qualifier:
  /* empty */
	{$$ = NULL;}
| qualifier
	{$$ = new action_qualifier_c($1, NULL, locloc(@$));}
| timed_qualifier ',' action_time
	{$$ = new action_qualifier_c($1, $3, locloc(@$));}
;

qualifier:
  N		{$$ = new qualifier_c(strdup("N"), locloc(@$));}
| R		{$$ = new qualifier_c(strdup("R"), locloc(@$));}
| S		{$$ = new qualifier_c(strdup("S"), locloc(@$));}
| P		{$$ = new qualifier_c(strdup("P"), locloc(@$));}
;

timed_qualifier:
  L		{$$ = new timed_qualifier_c(strdup("L"), locloc(@$));}
| D		{$$ = new timed_qualifier_c(strdup("D"), locloc(@$));}
| SD		{$$ = new timed_qualifier_c(strdup("SD"), locloc(@$));}
| DS		{$$ = new timed_qualifier_c(strdup("DS"), locloc(@$));}
| SL		{$$ = new timed_qualifier_c(strdup("SL"), locloc(@$));}
;

action_time:
  duration
| variable
;

indicator_name: variable;

// transition_name: identifier;
transition_name: any_identifier;


steps:
  step_name
	{$$ = new steps_c($1, NULL, locloc(@$));}
| '(' step_name_list ')'
	{$$ = new steps_c(NULL, $2, locloc(@$));}
;

step_name_list:
  step_name ',' step_name
	{$$ = new step_name_list_c(locloc(@$)); $$->add_element($1); $$->add_element($3);}
| step_name_list ',' step_name
	{$$ = $1; $$->add_element($3);}
;


/* NOTE: flex will automatically pop() out of body_state to previous state.
 *       We do not need to give a command from bison to return to previous flex state,
 *       after forcing flex to go to body_state.
 */
transition:
  TRANSITION 
    FROM steps TO steps 
    {cmd_goto_body_state();} transition_condition 
  END_TRANSITION 
	{$$ = new transition_c(NULL, NULL, $3, $5, $7, locloc(@$));}
//| TRANSITION identifier FROM steps TO steps ... 
| TRANSITION transition_name 
    FROM steps TO steps 
    {cmd_goto_body_state();} transition_condition 
  END_TRANSITION 
	{$$ = new transition_c($2, NULL, $4, $6, $8, locloc(@$));}
| TRANSITION '(' {cmd_goto_sfc_priority_state();} PRIORITY {cmd_pop_state();} ASSIGN integer ')' 
    FROM steps TO steps 
    {cmd_goto_body_state();} transition_condition 
  END_TRANSITION
        {$$ = new transition_c(NULL, $7, $10, $12, $14, locloc(@$));}
//| TRANSITION identifier '(' PRIORITY ASSIGN integer ')' FROM steps TO steps ...
| TRANSITION transition_name '(' {cmd_goto_sfc_priority_state();} PRIORITY {cmd_pop_state();} ASSIGN integer ')' 
    FROM steps TO steps 
    {cmd_goto_body_state();} transition_condition 
  END_TRANSITION
        {$$ = new transition_c($2, $8, $11, $13, $15, locloc(@$));}
;



transition_condition:
  ':' eol_list simple_instr_list
	{$$ = new transition_condition_c($3, NULL, locloc(@$));}
| ASSIGN expression ';'
	{$$ = new transition_condition_c(NULL, $2, locloc(@$));}
;



action:
//  ACTION identifier ':' ... 
  ACTION action_name ':' {cmd_goto_body_state();} function_block_body END_ACTION
	{$$ = new action_c($2, $5, locloc(@$));}
;


/********************************/
/* 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, locloc(@$));};
prev_declared_resource_name: prev_declared_resource_name_token {$$ = new identifier_c($1, locloc(@$));};
prev_declared_program_name: prev_declared_program_name_token {$$ = new identifier_c($1, locloc(@$));};
// prev_declared_task_name: prev_declared_task_name_token {$$ = new identifier_c($1, locloc(@$));};






configuration_name: identifier;

/* NOTE: The specification states that valid resource type names
 *       are implementation defined, i.e. each implementaion will define
 *       what resource types it supports.
 *       We are implementing this syntax parser to be used by any
 *       implementation, so at the moment we accept any identifier
 *       as a resource type name.
 *       This implementation should probably be changed in the future. We
 *       should probably have a resource_type_name_token, and let the
 *       implementation load the global symbol library with the
 *       accepted resource type names before parsing the code.
 *
 */
resource_type_name: any_identifier;

configuration_declaration:
  CONFIGURATION configuration_name
   optional_global_var_declarations
   single_resource_declaration
   {variable_name_symtable.pop();}
   optional_access_declarations
   optional_instance_specific_initializations
  END_CONFIGURATION
	{$$ = new configuration_declaration_c($2, $3, $4, $6, $7, locloc(@$));
	 library_element_symtable.insert($2, prev_declared_configuration_name_token);
	 variable_name_symtable.pop();
	}
| CONFIGURATION configuration_name
   optional_global_var_declarations
   resource_declaration_list
   optional_access_declarations
   optional_instance_specific_initializations
 END_CONFIGURATION
	{$$ = new configuration_declaration_c($2, $3, $4, $5, $6, locloc(@$));
	 library_element_symtable.insert($2, prev_declared_configuration_name_token);
	 variable_name_symtable.pop();
}
/* ERROR_CHECK_BEGIN */
| CONFIGURATION error END_CONFIGURATION
	{$$ = NULL;
	 print_err_msg(current_filename, locf(@1), locl(@3), "error in configuration declaration.");
	 /* yychar */
	 yyerrok;
	}
/* ERROR_CHECK_END */
;

// helper symbol for
//  - configuration_declaration
//  - resource_declaration
//
optional_global_var_declarations:
  // empty
	{$$ = NULL;}
| global_var_declarations
;


// helper symbol for configuration_declaration //
optional_access_declarations:
  // empty
	{$$ = NULL;}
//| access_declarations
;

// helper symbol for configuration_declaration //
optional_instance_specific_initializations:
  // empty
	{$$ = NULL;}
| instance_specific_initializations
;

// helper symbol for configuration_declaration //
resource_declaration_list:
  resource_declaration
	{$$ = new resource_declaration_list_c(locloc(@$)); $$->add_element($1);}
| resource_declaration_list resource_declaration
	{$$ = $1; $$->add_element($2);}
;


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, locloc(@$));
	 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, locloc(@$));}
;


// helper symbol for single_resource_declaration //
task_configuration_list:
  // empty
	{$$ = new task_configuration_list_c(locloc(@$));}
| task_configuration_list task_configuration ';'
	{$$ = $1; $$->add_element($2);}
;


// helper symbol for single_resource_declaration //
program_configuration_list:
  program_configuration ';'
	{$$ = new program_configuration_list_c(locloc(@$)); $$->add_element($1);}
| program_configuration_list program_configuration ';'
	{$$ = $1; $$->add_element($2);}
;


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(locloc(@$));}
//| fb_name_list fb_name '.'
| any_fb_name_list any_identifier '.'
	{$$ = $1; $$->add_element($2);}
;



global_var_reference:
//  [resource_name '.'] global_var_name ['.' structure_element_name] //
                                  prev_declared_global_var_name
	{$$ = new global_var_reference_c(NULL, $1, NULL, locloc(@$));}
|                                 prev_declared_global_var_name '.' structure_element_name
	{$$ = new global_var_reference_c(NULL, $1, $3, locloc(@$));}
| prev_declared_resource_name '.' prev_declared_global_var_name
	{$$ = new global_var_reference_c($1, $3, NULL, locloc(@$));}
| prev_declared_resource_name '.' prev_declared_global_var_name '.' structure_element_name
	{$$ = new global_var_reference_c($1, $3, $5, locloc(@$));}
;


//access_name: identifier;


program_output_reference:
/* NOTE:
 * program_output_reference is merely used within data_source.
 * data_source is merely used within task_initialization
 * task_initialization appears in a configuration declaration
 * _before_ the programs are declared, so we cannot use
 * prev_declared_program_name, as what might seem correct at first.
 *
 * The semantic checker must later check whether the identifier
 * used really refers to a program declared after the task
 * initialization!
 */
//  prev_declared_program_name '.' symbolic_variable
  program_name '.' symbolic_variable
	{$$ = new program_output_reference_c($1, $3, locloc(@$));}
;

program_name: identifier;

/*
direction:
  READ_WRITE
	{$$ = NULL;}
| READ_ONLY
	{$$ = NULL;}
;
*/

task_configuration:
  TASK task_name task_initialization
	{$$ = new task_configuration_c($2, $3, locloc(@$));}
;

/* NOTE: The specification does not mention the namespace to which task names
 *       should belong to. Unlike resource and program names, for the moment we
 *       let the task names belong to their own private namespace, as they do not
 *       produce any conflicts in the syntax parser.
 *       If in the future our interpretation of the spec. turns out to be incorrect,
 *       the definition of task_name may have to be changed!
 */
task_name: any_identifier;


task_initialization:
//  '(' [SINGLE ASSIGN data_source ','] [INTERVAL ASSIGN data_source ','] PRIORITY ASSIGN integer ')' //
  '(' {cmd_goto_task_init_state();} task_initialization_single task_initialization_interval task_initialization_priority ')'
	{$$ = new task_initialization_c($3, $4, $5, locloc(@$));}
;


task_initialization_single:
// [SINGLE ASSIGN data_source ',']
  /* empty */
	{$$ = NULL;}
| SINGLE ASSIGN {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();} 
	{$$ = $4;}
;


task_initialization_interval:
// [INTERVAL ASSIGN data_source ','] 
  /* empty */
	{$$ = NULL;}
| INTERVAL ASSIGN {cmd_pop_state();} data_source ',' {cmd_goto_task_init_state();}
	{$$ = $4;}
;



task_initialization_priority:
// PRIORITY ASSIGN integer
  PRIORITY ASSIGN {cmd_pop_state();} integer 
	{$$ = $4;}
;



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, locloc(@$));
	 variable_name_symtable.insert($2, prev_declared_program_name_token);
	}
| PROGRAM RETAIN program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements
	{$$ = new program_configuration_c(new retain_option_c(locloc(@2)), $3, $4, $6, $7, locloc(@$));
	 variable_name_symtable.insert($3, prev_declared_program_name_token);
	}
| PROGRAM NON_RETAIN program_name optional_task_name ':' prev_declared_program_type_name optional_prog_conf_elements
	{$$ = new program_configuration_c(new non_retain_option_c(locloc(@2)), $3, $4, $6, $7, locloc(@$));
	 variable_name_symtable.insert($3, prev_declared_program_name_token);
	}
;

// 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(locloc(@$)); $$->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, locloc(@$));}
;


/* NOTE:
 *  The semantics of configuring a program are rather confusing, so here is
 *  my (Mario) understanding on the issue...
 *
 *  A function/program may have as its input variables a simple variable
 *  (BYTE, WORD, etc...), an array (ARRAY [1 .. 3] OF BYTE, ...) , or a structure.
 *  Nevertheless, when calling this function from within a st or il language statement
 *  it is not possible to allocate a value to a single element of the array or structure
 *  typed input variable, as the accepted syntax is simply '(' variable_name ':=' variable ')'
 *  Notice how the variable_name does not include things such as 'a.elem1' or 'a[1]'!
 *
 *  Nevertheless, when configuring a program from within a configuration,
 *  it becomes possible to allocate values to individual elements of the
 *  array or structured type input variable, as the syntax is now
 *  '(' symbolic_variable ':=' data_sink|prog_data_source ')'
 *  Notice how the symbolic_variable _does_ include things such as 'a.elem1' or 'a[1]'!
 *
 *  Conclusion: Unlike other locations in the syntax where SENDTO appears,
 *  here it is not valid to replace symbolic_variable with any_identifier!
 *  Nevertheless, it is also not correct to leave symbolic_variable as it is,
 *  as we have defined it to only include previously declared variables,
 *  which is not the case in this situation. Here symbolic_variable is refering
 *  to variables that were defined within the scope of the program that is being
 *  called, and _not_ within the scope of the configuration that is calling the
 *  program, so the variables in question are not declared in the current scope!
 *
 *  We therefore need to define a new symbolic_variable, that accepts any_identifier
 *  instead of previosuly declared variable names, to be used in the definition of
 *  prog_cnxn!
 */
prog_cnxn:
  any_symbolic_variable ASSIGN prog_data_source
	{$$ = new prog_cnxn_assign_c($1, $3, locloc(@$));}
| any_symbolic_variable SENDTO data_sink
	{$$ = new prog_cnxn_sendto_c($1, $3, locloc(@$));}
;

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, locloc(@$));}
;

// helper symbol for instance_specific_initializations //
instance_specific_init_list:
  instance_specific_init ';'
	{$$ = new instance_specific_init_list_c(locloc(@$)); $$->add_element($1);}
| instance_specific_init_list instance_specific_init ';'
	{$$ = $1; $$->add_element($2);}
;


instance_specific_init:
//
//  resource_name '.' program_name '.' {fb_name '.'}
//  ((variable_name [location] ':' located_var_spec_init) | (fb_name ':' function_block_type_name ':=' structure_initialization))
//
//  prev_declared_resource_name '.' prev_declared_program_name '.' any_fb_name_list variable_name ':' located_var_spec_init
/* NOTE: variable_name has been changed to any_identifier (and not simply identifier) because the
 *       variables being referenced have been declared outside the scope currently being parsed!
 */
/* NOTE: program_name has not been changed to prev_declared_program_name because the
 *       programs being referenced have been declared outside the scope currently being parsed!
 *       The programs are only kept inside the scope of the resource in which they are defined.
 */
  prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier ':' located_var_spec_init
	{$$ = new instance_specific_init_c($1, $3, $5, $6, NULL, $8, locloc(@$));}
| prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier location ':' located_var_spec_init
	{$$ = new instance_specific_init_c($1, $3, $5, $6, $7, $9, locloc(@$));}
| prev_declared_resource_name '.' program_name '.' any_fb_name_list any_identifier ':' fb_initialization
	{$5->add_element($6); $$ = new instance_specific_init_c($1, $3, $5, NULL, NULL, $8, locloc(@$));}
;


/* helper symbol for instance_specific_init */
fb_initialization:
  function_block_type_name ASSIGN structure_initialization
	{$$ = new fb_initialization_c($1, $3, locloc(@$));}
;

/***********************************/
/* B 2.1 Instructions and Operands */
/***********************************/
/* helper symbol for many IL instructions, etc... */
/* eat up any extra EOL tokens... */

eol_list:
  EOL
| eol_list EOL
;



instruction_list:
  il_instruction
	{$$ = new instruction_list_c(locloc(@$)); $$->add_element($1);}
| pragma eol_list
	{$$ = new instruction_list_c(locloc(@$)); $$->add_element($1);}
| instruction_list il_instruction
	{$$ = $1; $$->add_element($2);}
| instruction_list pragma
	{$$ = $1; $$->add_element($2);}
;



il_instruction:
  il_incomplete_instruction eol_list
	{$$ = new il_instruction_c(NULL, $1, locloc(@$));}
| label ':' il_incomplete_instruction eol_list
	{$$ = new il_instruction_c($1, $3, locloc(@$));}
/* ERROR_CHECK_BEGIN */
| error eol_list
	{$$ = NULL;
	 print_err_msg(current_filename, locf(@1), locl(@1), "error in IL instruction.");
	 yyerrok;
	}
/* ERROR_CHECK_END */
/* ERROR_CHECK_BEGIN */
| label ':' error eol_list
	{$$ = NULL;
	 print_err_msg(current_filename, locf(@1), locl(@3), "error in IL instruction.");
	 yyerrok;
	}
/* ERROR_CHECK_END */
;


/* helper symbol for il_instruction */
il_incomplete_instruction:
  il_simple_operation
| il_expression
| il_jump_operation
| il_fb_call
| il_formal_funct_call
| il_return_operator
;


label: identifier;



il_simple_operation:
// (il_simple_operator [il_operand]) | (function_name [il_operand_list])
  il_simple_operator
	{$$ = new il_simple_operation_c($1, NULL, locloc(@$));}
/*
 * Note: Bison is getting confused with the following rule,
 *       i.e. it is finding conflicts where there seemingly are really none.
 *       The rule was therefore replaced by the equivalent following
 *       two rules.
 */
/*
| il_simple_operator il_operand
	{$$ = new il_simple_operation_c($1, $2, locloc(@$));}
*/
| il_simple_operator_noclash il_operand
	{$$ = new il_simple_operation_c($1, $2, locloc(@$));}
| il_simple_operator_clash il_operand
	{$$ = new il_simple_operation_c($1, $2, locloc(@$));}
/* NOTE: the line
 *         | il_simple_operator
 *       already contains the 'NOT' operator, as well as all the
 *       expression operators ('MOD', 'AND', etc...), all of which
 *       may also be a function name! This means that these operators/functions,
 *       without any operands, could be reduced to either an operator or a
 *       function call. 
 *
 *       I (Mario) have chosen to reduce it to an operator.
 *       In order to do this, we must remove from the syntax that defines
 *       function calls all the functions whose names clash with the IL operators.
 *
 *       The line
 *         | function_name
 *       has been replaced with the lines
 *         | function_name_no_clashes
 *       in order to include all possible function names except
 *       those whose names coincide with operators !!
 */
| function_name_no_clashes
	{$$ = new il_function_call_c($1, NULL, locloc(@$));}
/* NOTE: the line
 *         | il_simple_operator il_operand
 *       already contains the 'NOT', 'MOD', etc. operators, followed by a single il_operand.
 *       However, this same code (MOD x) may also be reduced to a function call to the MOD
 *       function. This means that (MOD, AND,...) could be interpret as a function name
 *       or as an IL operator! This would lead us to a reduce/reduce conflict!
 *
 *       I (Mario) have chosen to reduce it to an operand, rather than a function call.
 *       In order to do this, we must remove from the syntax that defines
 *       function calls all the functions whose names clash with the IL operators.
 *
 *       The line
 *         | function_name il_operand_list
 *       has been replaced with the line
 *         | function_name_no_clashes il_operand_list
 *       in order to include all possible function names except
 *       for the function names which clash with expression and simple operators.
 *
 *       Note that:
 *       this alternative syntax does not cover the possibility of
 *       the function 'NOT', 'MOD', etc... being called with more than one il_operand,
 *       in which case it is always a function call, and not an IL instruction.
 *       We therefore need to include an extra rule where the
 *       function_name_expression_clashes and function_name_simpleop_clashes
 *       are followed by a il_operand_list with __two__ or more il_operands!!
 */
| function_name_no_clashes il_operand_list
	{$$ = new il_function_call_c($1, $2, locloc(@$));}
| il_simple_operator_clash il_operand_list2
	{$$ = new il_function_call_c(il_operator_c_2_identifier_c($1), $2, locloc(@$));}
;



il_expression:
// il_expr_operator '(' [il_operand] EOL {EOL} [simple_instr_list] ')'
/*
 * Note: Bison is getting confused with the use of il_expr_operator,
 *       i.e. it is finding conflicts where there seemingly are really none.
 *       il_expr_operator was therefore replaced by the equivalent 
 *       il_expr_operator_noclash | il_expr_operator_clash.
 */
  il_expr_operator_noclash '(' eol_list ')'
	{$$ = new il_expression_c($1, NULL, NULL, locloc(@$));}
| il_expr_operator_noclash '(' il_operand eol_list ')'
	{$$ = new il_expression_c($1, $3, NULL, locloc(@$));}
| il_expr_operator_noclash '(' eol_list simple_instr_list ')'
	{$$ = new il_expression_c($1, NULL, $4, locloc(@$));}
| il_expr_operator_noclash '(' il_operand eol_list simple_instr_list ')'
	{$$ = new il_expression_c($1, $3, $5, locloc(@$));}
| il_expr_operator_clash '(' eol_list ')'
	{$$ = new il_expression_c($1, NULL, NULL, locloc(@$));}
| il_expr_operator_clash '(' il_operand eol_list ')'
	{$$ = new il_expression_c($1, $3, NULL, locloc(@$));}
| il_expr_operator_clash '(' il_operand eol_list simple_instr_list ')'
	{$$ = new il_expression_c($1, $3, $5, locloc(@$));}
| il_expr_operator_clash_eol_list simple_instr_list ')'
	{$$ = new il_expression_c($1, NULL, $2, locloc(@$));}
;


il_jump_operation:
  il_jump_operator label
	{$$ = new il_jump_operation_c($1, $2, locloc(@$));}
;


il_fb_call:
// il_call_operator fb_name ['(' (EOL {EOL} [il_param_list]) | [il_operand_list] ')']
  il_call_operator prev_declared_fb_name
	{$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));}
| il_call_operator prev_declared_fb_name '(' ')'
	{$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));}
| il_call_operator prev_declared_fb_name '(' eol_list ')'
	{$$ = new il_fb_call_c($1, $2, NULL, NULL, locloc(@$));}
| il_call_operator prev_declared_fb_name '(' il_operand_list ')'
	{$$ = new il_fb_call_c($1, $2, $4, NULL, locloc(@$));}
| il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')'
	{$$ = new il_fb_call_c($1, $2, NULL, $5, locloc(@$));}
;


/* NOTE: Please read note above the definition of function_name_without_clashes */
il_formal_funct_call:
// function_name '(' EOL {EOL} [il_param_list] ')'
/*  function_name '(' eol_list ')'  */
/* NOTE: il_formal_funct_call is only used in the definition of
 *         - il_incomplete_instruction
 *         - il_simple_instruction
 *       In both of the above, il_expression also
 *       shows up as another option. This means that the functions whose
 *       names clash with expressions, followed by '(' eol_list ')', are
 *       already included. We must therefore leave them out in this
 *       definition in order to remove reduce/reduce conflicts.
 *
 *       In summary: 'MOD' '(' eol_list ')', and all other functions whose
 *       names clash with expressions may be interpreted by the syntax by
 *       two different routes. I (Mario) chose to interpret them
 *       as operators, rather than as function calls!
 *       (AND MOD OR XOR ADD DIV EQ GT GE LT LE MUL NE SUB)
 */
  function_name_no_clashes '(' eol_list ')'
	{$$ = new il_formal_funct_call_c($1, NULL, locloc(@$));}
| function_name_simpleop_clashes '(' eol_list ')'
	{$$ = new il_formal_funct_call_c($1, NULL, locloc(@$));}
/* | function_name '(' eol_list il_param_list ')' */
/* For the above syntax, we no longer have two ways of interpreting the
 * same syntax. The above is always a function call!
 * However, some of the functions that we may be calling
 * may have the same name as an IL operator. This means that
 * flex will be parsing them and handing them over to bison as
 * IL operator tokens, and not as function name tokens.
 * (when parsing ST, flex no longer recognizes IL operators,
 * so will always return the correct function name, unless that
 * name also coincides with an operator used in ST -> XOR, OR, MOD, AND, NOT)
 *
 * We must therefore interpret the IL operators as function names!
 */
| function_name_no_clashes '(' eol_list il_param_list ')'
	{$$ = new il_formal_funct_call_c($1, $4, locloc(@$));}
| function_name_simpleop_clashes '(' eol_list il_param_list ')'
	{$$ = new il_formal_funct_call_c($1, $4, locloc(@$));}
/* The following line should read:
 *
 * | function_name_expression_clashes '(' eol_list il_param_list ')'
 *
 * but the function_name_expression_clashes had to be first reduced to
 * an intermediary symbol in order to remove a reduce/reduce conflict.
 * In essence, the syntax requires more than one look ahead token
 * in order to be parsed. We resolve this by reducing a collection of
 * symbols into a temporary symbol (il_expr_operator_clash_eol_list), that
 * will later be replaced by the correct symbol. The correct symbol will
 * now be determined by a single look ahead token, as all the common
 * symbols have been reduced to the temporary symbol
 * il_expr_operator_clash_eol_list !
 *
 * Unfortunately, this work around results in the wrong symbol
 * being created for the abstract syntax tree.
 * We need to figure out which symbol was created, destroy it,
 * and create the correct symbol for our case.
 * This is a lot of work, so I put it in a function
 * at the end of this file... il_operator_c_2_identifier_c()
 */
| il_expr_operator_clash_eol_list il_param_list ')'
	{$$ = new il_formal_funct_call_c(il_operator_c_2_identifier_c($1), $2, locloc(@$));}
;


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(locloc(@$)); $$->add_element($1);}
| il_operand_list2
;


/* List with 2 or more il_operands */ 
il_operand_list2:
  il_operand ',' il_operand 
	{$$ = new il_operand_list_c(locloc(@$)); $$->add_element($1); $$->add_element($3);}
| il_operand_list2 ',' il_operand
	{$$ = $1; $$->add_element($3);}
;


simple_instr_list:
  il_simple_instruction
	{$$ = new simple_instr_list_c(locloc(@$)); $$->add_element($1);}
| simple_instr_list il_simple_instruction
	{$$ = $1; $$->add_element($2);}
;


il_simple_instruction:
  il_simple_operation eol_list
| il_expression eol_list
| il_formal_funct_call eol_list
;


/* NOTE: the correct definition of il_param_list is
 * il_param_list ::= {il_param_instruction} il_param_last_instruction
 *
 * where {...} denotes zero or many il_param_instruction's.
 *
 * We could do this by defining the following:
 * il_param_list: il_param_instruction_list il_param_last_instruction;
 * il_param_instruction_list : ** empty ** | il_param_instruction_list il_param_instruction;
 *
 * Unfortunately, the above leads to reduce/reduce conflicts.
 * The chosen alternative (as follows) does not have any conflicts!
 * il_param_list: il_param_last_instruction | il_param_instruction_list il_param_last_instruction;
 * il_param_instruction_list : il_param_instruction_list | il_param_instruction_list il_param_instruction;
 */
il_param_list:
  il_param_instruction_list il_param_last_instruction
	{$$ = $1; $$->add_element($2);}
| il_param_last_instruction
	{$$ = new il_param_list_c(locloc(@$)); $$->add_element($1);}
;


/* Helper symbol for il_param_list */
il_param_instruction_list:
  il_param_instruction
	{$$ = new il_param_list_c(locloc(@$)); $$->add_element($1);}
| il_param_instruction_list il_param_instruction
	{$$ = $1; $$->add_element($2);}
;


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, locloc(@$));}
| il_assign_operator '(' eol_list simple_instr_list ')'
	{$$ = new il_param_assignment_c($1, NULL, $4, locloc(@$));}
;


il_param_out_assignment:
  il_assign_out_operator variable
	{$$ = new il_param_out_assignment_c($1, $2, locloc(@$));}
;



/*******************/
/* B 2.2 Operators */
/*******************/
sendto_identifier: sendto_identifier_token {$$ = new identifier_c($1, locloc(@$));};


/* NOTE:
 *  The spec includes the operator 'EQ '
 * Note that EQ is followed by a space.
 * I am considering this a typo, and defining the operator
 * as 'EQ'
 * (Mario)
 */
LD_operator: 		LD 	{$$ = new LD_operator_c(locloc(@$));};
LDN_operator: 		LDN 	{$$ = new LDN_operator_c(locloc(@$));};
ST_operator: 		ST 	{$$ = new ST_operator_c(locloc(@$));};
STN_operator: 		STN 	{$$ = new STN_operator_c(locloc(@$));};
NOT_operator: 		NOT 	{$$ = new NOT_operator_c(locloc(@$));};
S_operator: 		S 	{$$ = new S_operator_c(locloc(@$));};
R_operator: 		R 	{$$ = new R_operator_c(locloc(@$));};
S1_operator: 		S1 	{$$ = new S1_operator_c(locloc(@$));};
R1_operator: 		R1 	{$$ = new R1_operator_c(locloc(@$));};
CLK_operator: 		CLK 	{$$ = new CLK_operator_c(locloc(@$));};
CU_operator: 		CU 	{$$ = new CU_operator_c(locloc(@$));};
CD_operator: 		CD 	{$$ = new CD_operator_c(locloc(@$));};
PV_operator: 		PV 	{$$ = new PV_operator_c(locloc(@$));};
IN_operator: 		IN 	{$$ = new IN_operator_c(locloc(@$));};
PT_operator: 		PT 	{$$ = new PT_operator_c(locloc(@$));};
AND_operator: 		AND 	{$$ = new AND_operator_c(locloc(@$));};
AND2_operator: 		AND2 	{$$ = new AND_operator_c(locloc(@$));}; /* '&' in the source code! */
OR_operator: 		OR 	{$$ = new OR_operator_c(locloc(@$));};
XOR_operator: 		XOR 	{$$ = new XOR_operator_c(locloc(@$));};
ANDN_operator: 		ANDN 	{$$ = new ANDN_operator_c(locloc(@$));};
ANDN2_operator:		ANDN2 	{$$ = new ANDN_operator_c(locloc(@$));}; /* '&N' in the source code! */
ORN_operator: 		ORN 	{$$ = new ORN_operator_c(locloc(@$));};
XORN_operator: 		XORN 	{$$ = new XORN_operator_c(locloc(@$));};
ADD_operator: 		ADD 	{$$ = new ADD_operator_c(locloc(@$));};
SUB_operator: 		SUB 	{$$ = new SUB_operator_c(locloc(@$));};
MUL_operator: 		MUL 	{$$ = new MUL_operator_c(locloc(@$));};
DIV_operator: 		DIV 	{$$ = new DIV_operator_c(locloc(@$));};
MOD_operator: 		MOD 	{$$ = new MOD_operator_c(locloc(@$));};
GT_operator: 		GT 	{$$ = new GT_operator_c(locloc(@$));};
GE_operator: 		GE 	{$$ = new GE_operator_c(locloc(@$));};
EQ_operator: 		EQ 	{$$ = new EQ_operator_c(locloc(@$));};
LT_operator: 		LT 	{$$ = new LT_operator_c(locloc(@$));};
LE_operator: 		LE 	{$$ = new LE_operator_c(locloc(@$));};
NE_operator: 		NE 	{$$ = new NE_operator_c(locloc(@$));};
CAL_operator: 		CAL 	{$$ = new CAL_operator_c(locloc(@$));};
CALC_operator: 		CALC 	{$$ = new CALC_operator_c(locloc(@$));};
CALCN_operator: 	CALCN 	{$$ = new CALCN_operator_c(locloc(@$));};
RET_operator: 		RET 	{$$ = new RET_operator_c(locloc(@$));};
RETC_operator: 		RETC 	{$$ = new RETC_operator_c(locloc(@$));};
RETCN_operator: 	RETCN 	{$$ = new RETCN_operator_c(locloc(@$));};
JMP_operator: 		JMP 	{$$ = new JMP_operator_c(locloc(@$));};
JMPC_operator: 		JMPC 	{$$ = new JMPC_operator_c(locloc(@$));};
JMPCN_operator: 	JMPCN 	{$$ = new JMPCN_operator_c(locloc(@$));};


il_simple_operator:
  il_simple_operator_clash
| il_simple_operator_noclash
;


il_simple_operator_noclash:
  LD_operator
| LDN_operator
| ST_operator
| STN_operator
| S_operator
| R_operator
| S1_operator
| R1_operator
| CLK_operator
| CU_operator
| CD_operator
| PV_operator
| IN_operator
| PT_operator
| il_expr_operator_noclash
;


il_simple_operator_clash:
  il_simple_operator_clash1
| il_simple_operator_clash2
;

il_simple_operator_clash1:
  NOT_operator
;

il_simple_operator_clash2:
  il_expr_operator_clash
;


/*
il_expr_operator:
  il_expr_operator_noclash
| il_expr_operator_clash
;
*/

il_expr_operator_clash:
  AND_operator
| OR_operator
| XOR_operator
| ADD_operator
| SUB_operator
| MUL_operator
| DIV_operator
| MOD_operator
| GT_operator
| GE_operator
| EQ_operator
| LT_operator
| LE_operator
| NE_operator
;


il_expr_operator_noclash:
  ANDN_operator
| ANDN2_operator  /* string '&N' in source code! */
| AND2_operator  /* string '&' in source code! */
| ORN_operator
| XORN_operator
;




il_assign_operator:
/*  variable_name ASSIGN */
  any_identifier ASSIGN
;


il_assign_out_operator:
/*  variable_name SENDTO */
/*  any_identifier SENDTO */
  sendto_identifier SENDTO
	{$$ = new il_assign_out_operator_c(NULL, $1, locloc(@$));}
/*| NOT variable_name SENDTO */
| NOT sendto_identifier SENDTO
	{$$ = new il_assign_out_operator_c(new not_paramassign_c(locloc(@1)), $2, locloc(@$));}
;


il_call_operator:
  CAL_operator
| CALC_operator
| CALCN_operator
;


il_return_operator:
  RET_operator
| RETC_operator
| RETCN_operator
;


il_jump_operator:
  JMP_operator
| JMPC_operator
| JMPCN_operator
;


/***********************/
/* B 3.1 - Expressions */
/***********************/
expression:
  xor_expression
| expression OR xor_expression
	{$$ = new or_expression_c($1, $3, locloc(@$));}
;

xor_expression:
  and_expression
| xor_expression XOR and_expression
	{$$ = new xor_expression_c($1, $3, locloc(@$));}
;

and_expression:
  comparison
| and_expression '&' comparison
	{$$ = new and_expression_c($1, $3, locloc(@$));}
| and_expression AND comparison
	{$$ = new and_expression_c($1, $3, locloc(@$));}
/* NOTE: The lexical parser never returns the token '&'.
 *       The '&' string is interpreted by the lexcial parser as the token
 *       AND2!
 *       This means that the first rule with '&' is actually not required,
 *       but we leave it in nevertheless just in case we later decide
 *       to remove theh AND2 token...
 */
| and_expression AND2 comparison
	{$$ = new and_expression_c($1, $3, locloc(@$));}
;

comparison:
  equ_expression
| comparison '=' equ_expression
	{$$ = new equ_expression_c($1, $3, locloc(@$));}
| comparison OPER_NE equ_expression
	{$$ = new notequ_expression_c($1, $3, locloc(@$));}
;

equ_expression:
  add_expression
| equ_expression '<' add_expression
	{$$ = new lt_expression_c($1, $3, locloc(@$));}
| equ_expression '>' add_expression
	{$$ = new gt_expression_c($1, $3, locloc(@$));}
| equ_expression OPER_LE add_expression
	{$$ = new le_expression_c($1, $3, locloc(@$));}
| equ_expression OPER_GE add_expression
	{$$ = new ge_expression_c($1, $3, locloc(@$));}
;

/* Not required...
comparison_operator: '<' | '>' | '>=' '<='
*/

add_expression:
  term
| add_expression '+' term
	{$$ = new add_expression_c($1, $3, locloc(@$));}
| add_expression '-' term
	{$$ = new sub_expression_c($1, $3, locloc(@$));}
;

/* Not required...
add_operator: '+' | '-'
*/

term:
  power_expression
| term '*' power_expression
	{$$ = new mul_expression_c($1, $3, locloc(@$));}
| term '/' power_expression
	{$$ = new div_expression_c($1, $3, locloc(@$));}
| term MOD power_expression
	{$$ = new mod_expression_c($1, $3, locloc(@$));}
;

/* Not required...
multiply_operator: '*' | '/' | 'MOD'
*/

power_expression:
  unary_expression
| power_expression OPER_EXP unary_expression
	{$$ = new power_expression_c($1, $3, locloc(@$));}
;


unary_expression:
  primary_expression
| '-' primary_expression
	{$$ = new neg_expression_c($2, locloc(@$));}
| NOT primary_expression
	{$$ = new not_expression_c($2, locloc(@$));}
;

/* 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
 */
/* NOTE: We use enumerated_value_without_identifier instead of enumerated_value
 *       in order to remove a reduce/reduce conflict between reducing an
 *       identifier to a variable or an enumerated_value.
 *
 *       This change follows the IEC specification. The specification seems to
 *       imply (by introducing syntax that allows to unambiguosly reference an
 *       enumerated value - enum_type#enum_value) that in case the same identifier is used
 *       for a variable and an enumerated value, then the variable shall be
 *       considered.
 */
primary_expression:
/* constant */
  non_negative_constant
//| enumerated_value_without_identifier
| 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_formal_list ')'
	{$$ = new function_invocation_c($1, $3, locloc(@$));}
| function_name_no_NOT_clashes '(' param_assignment_nonformal_list ')'
	{$$ = new function_invocation_c($1, $3, locloc(@$));}
;


/********************/
/* B 3.2 Statements */
/********************/
statement_list:
  statement ';'
	{$$ = new statement_list_c(locloc(@$)); $$->add_element($1);}
| pragma
	{$$ = new statement_list_c(locloc(@$)); $$->add_element($1);}
| statement_list statement ';'
	{$$ = $1; $$->add_element($2);}
| statement_list pragma
	{$$ = $1; $$->add_element($2);}
/* ERROR_CHECK_BEGIN */
| statement_list error ';'
	{$$ = $1;
	 print_err_msg(current_filename, locf(@2), locl(@2), "error in statement.");
	 /* yychar */
	 yyerrok;
	}
/* ERROR_CHECK_END */
;


statement:
  assignment_statement
| subprogram_control_statement
| selection_statement
| iteration_statement
;


/*********************************/
/* B 3.2.1 Assignment Statements */
/*********************************/
assignment_statement:
  variable ASSIGN expression
	{$$ = new assignment_statement_c($1, $3, locloc(@$));}
;




/*****************************************/
/* B 3.2.2 Subprogram Control Statements */
/*****************************************/
subprogram_control_statement:
  fb_invocation
| return_statement
;


return_statement:
  RETURN	{$$ = new return_statement_c(locloc(@$));}
;



fb_invocation:
  prev_declared_fb_name '(' ')'
	{$$ = new fb_invocation_c($1, NULL, locloc(@$));	}
| prev_declared_fb_name '(' param_assignment_formal_list ')'
	{$$ = new fb_invocation_c($1, $3, locloc(@$));}
| prev_declared_fb_name '(' param_assignment_nonformal_list ')'
	{$$ = new fb_invocation_c($1, $3, locloc(@$));}
;


/* helper symbol for
 * - fb_invocation
 * - function_invocation
 */
param_assignment_formal_list:
  param_assignment_formal
	{$$ = new param_assignment_list_c(locloc(@$)); $$->add_element($1);}
| param_assignment_formal_list ',' param_assignment_formal
	{$$ = $1; $$->add_element($3);}
;

/* helper symbol for
 * - fb_invocation
 * - function_invocation
 */
param_assignment_nonformal_list:
  param_assignment_nonformal
	{$$ = new param_assignment_list_c(locloc(@$)); $$->add_element($1);}
| param_assignment_nonformal_list ',' param_assignment_nonformal
	{$$ = $1; $$->add_element($3);}
;


/* NOTE: According to the IEC 61131-3 standard, there are two possible
 *       syntaxes for calling function blocks within ST.
 *       The formal method has the form:
 *        fb ( invar := x, inoutvar := var1, outvar => var2);
 *       The non-formal method has the form:
 *        fb (x, var1, var2);
 *       In the text of IEC 61131-3 (where the semantics are defined),
 *       it is obvious that mixing the two syntaxes is considered incorrect.
 *       The following should therefore be incorrect: 
 *        fb ( invar := x, var1, var2);
 *       However, according to the syntax definition, as defined in IEC 61131-3,
 *       mixing the formal and non-formal methods of invocation is allowed.
 *       We have two alternatives:
 *        (a) implement the syntax here in iec.y according to the standard,
 *            and leave it to the semantic analyser stage to find this error
 *        (b) or implement the syntax in iec.y correctly, not allowing 
 *            the mixing of formal and non-formal invocation syntaxes.
 *       Considering that this is a syntax issue, and not semantic issue,
 *       I (Mario) have decided to go with alternative (a).
 *       In other words, in iec.y we do not follow the syntax as defined in
 *       Annex B of the IEC 61131-3 standard, but rather implement
 *       the syntax also taking into account the textual part of the standard too.
 */
/*
param_assignment:
  variable_name ASSIGN expression 
*/
param_assignment_nonformal:
  expression
;


param_assignment_formal:
  any_identifier ASSIGN expression
	{$$ = new input_variable_param_assignment_c($1, $3, locloc(@$));}
/*| variable_name SENDTO variable */
/*| any_identifier SENDTO variable */
| sendto_identifier SENDTO variable
	{$$ = new output_variable_param_assignment_c(NULL,$1, $3, locloc(@$));}
/*| NOT variable_name SENDTO variable */
/*| NOT any_identifier SENDTO variable*/
| NOT sendto_identifier SENDTO variable
	{$$ = new output_variable_param_assignment_c(new not_paramassign_c(locloc(@$)),$2, $4, locloc(@$));}
;





/********************************/
/* B 3.2.3 Selection Statements */
/********************************/
selection_statement:
  if_statement
| case_statement
;


if_statement:
  IF expression THEN statement_list elseif_statement_list END_IF
	{$$ = new if_statement_c($2, $4, $5, NULL, locloc(@$));}
| IF expression THEN statement_list elseif_statement_list ELSE statement_list END_IF
	{$$ = new if_statement_c($2, $4, $5, $7, locloc(@$));}
;

/* helper symbol for if_statement */
elseif_statement_list:
  /* empty */
	{$$ = new elseif_statement_list_c(locloc(@$));}
| elseif_statement_list elseif_statement
	{$$ = $1; $$->add_element($2);}
;

/* helper symbol for elseif_statement_list */
elseif_statement:
  ELSIF expression THEN statement_list
	{$$ = new elseif_statement_c($2, $4, locloc(@$));}
;


case_statement:
  CASE expression OF case_element_list END_CASE
	{$$ = new case_statement_c($2, $4, NULL, locloc(@$));}
| CASE expression OF case_element_list ELSE statement_list END_CASE
	{$$ = new case_statement_c($2, $4, $6, locloc(@$));}
;


/* helper symbol for case_statement */
case_element_list:
  case_element
	{$$ = new case_element_list_c(locloc(@$)); $$->add_element($1);}
| case_element_list case_element
	{$$ = $1; $$->add_element($2);}
;


case_element:
  case_list ':' statement_list
	{$$ = new case_element_c($1, $3, locloc(@$));}
;


case_list:
  case_list_element
	{$$ = new case_list_c(locloc(@$)); $$->add_element($1);}
| case_list ',' case_list_element
	{$$ = $1; $$->add_element($3);}
;


case_list_element:
  signed_integer
| subrange
| enumerated_value
;





/********************************/
/* B 3.2.4 Iteration Statements */
/********************************/
iteration_statement:
  for_statement
| while_statement
| repeat_statement
| exit_statement
;


for_statement:
  FOR control_variable ASSIGN expression TO expression BY expression DO statement_list END_FOR
	{$$ = new for_statement_c($2, $4, $6, $8, $10, locloc(@$));}
| FOR control_variable ASSIGN expression TO expression DO statement_list END_FOR
	{$$ = new for_statement_c($2, $4, $6, NULL, $8, locloc(@$));}
;

/* The spec has the syntax
 * control_variable: identifier;
 * but then defines the semantics of control_variable
 * (Section 3.3.2.4) as being of an integer type
 * (e.g., SINT, INT, or DINT).
 *
 * Obviously this presuposes that the control_variable
 * must have been declared in some VAR .. END_VAR
 * We must therefore change the syntax to read
 * control_variable: prev_declared_variable_name;
 * 
 * If we don't, then the correct use of any previosuly declared 
 * variable would result in an incorrect syntax error
*/
control_variable: prev_declared_variable_name {$$ = $1;};
// control_variable: identifier {$$ = $1;};

/* Integrated directly into for_statement */
/*
for_list:
  expression TO expression [BY expression]
;
*/


while_statement:
  WHILE expression DO statement_list END_WHILE
	{$$ = new while_statement_c($2, $4, locloc(@$));}
;


repeat_statement:
  REPEAT statement_list UNTIL expression END_REPEAT
	{$$ = new repeat_statement_c($2, $4, locloc(@$));}
;


exit_statement:
  EXIT	{$$ = new exit_statement_c(locloc(@$));}
;





%%

#include <stdio.h>	/* required for printf() */
#include <errno.h>
#include "../util/symtable.hh"

/* variables defined in code generated by flex... */
extern FILE *yyin;
extern int yylineno;



/* 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;

/* A pointer to the root of the parsing tree that will be generated 
 * by bison.
 */
symbol_c *tree_root;



/* The following function is called automatically by bison whenever it comes across
 * an error. Unfortunately it calls this function before executing the code that handles
 * the error itself, so we cannot print out the correct line numbers of the error location
 * over here.
 * Our solution is to store the current error message in a global variable, and have all
 * error action handlers call the function print_err_msg() after setting the location
 * (line number) variable correctly.
 */
const char *current_error_msg;
void yyerror (const char *error_msg) {
  current_error_msg = error_msg;
/* fprintf(stderr, "error %d: %s\n", yynerrs // global variable //, error_msg); */
/*  print_include_stack(); */
}


void print_err_msg(const char *filename,
                   int first_line,
                   int first_column,
                   int last_line,
                   int last_column,
                   const char *additional_error_msg) {
  fprintf(stderr, "error %d: %s\n", yynerrs /* a global variable */, additional_error_msg);
  print_include_stack();
  fprintf(stderr, "%s(%d-%d): %s\n", filename, first_line, last_line, current_error_msg);
}



/* convert between an il_operator to a function name */
/* This a kludge!
 * It is required because our language requires more than one
 * look ahead token, and bison only works with one!
 */
#define op_2_str(op, str) {\
  op ## _operator_c *ptr = dynamic_cast<op ## _operator_c *>(il_operator); \
  if (ptr != NULL) name = str; \
}

/* NOTE: this code is very ugly and un-eficient, but I (Mario) have many
 *       more things to worry about right now, so just let it be...
 */
symbol_c *il_operator_c_2_identifier_c(symbol_c *il_operator) {
  const char *name = NULL;
  identifier_c *res;

  op_2_str(NOT, "NOT");

  op_2_str(AND, "AND");
  op_2_str(OR, "OR");
  op_2_str(XOR, "XOR");
  op_2_str(ADD, "ADD");
  op_2_str(SUB, "SUB");
  op_2_str(MUL, "MUL");
  op_2_str(DIV, "DIV");
  op_2_str(MOD, "MOD");
  op_2_str(GT, "GT");
  op_2_str(GE, "GE");
  op_2_str(EQ, "EQ");
  op_2_str(LT, "LT");
  op_2_str(LE, "LE");
  op_2_str(NE, "NE");

  op_2_str(LD, "LD");
  op_2_str(LDN, "LDN");
  op_2_str(ST, "ST");
  op_2_str(STN, "STN");

  op_2_str(S, "S");
  op_2_str(R, "R");
  op_2_str(S1, "S1");
  op_2_str(R1, "R1");

  op_2_str(CLK, "CLK");
  op_2_str(CU, "CU");
  op_2_str(CD, "CD");
  op_2_str(PV, "PV");
  op_2_str(IN, "IN");
  op_2_str(PT, "PT");

  op_2_str(ANDN, "ANDN");
  op_2_str(ORN, "ORN");
  op_2_str(XORN, "XORN");

  op_2_str(ADD, "ADD");
  op_2_str(SUB, "SUB");
  op_2_str(MUL, "MUL");
  op_2_str(DIV, "DIV");

  op_2_str(GT, "GT");
  op_2_str(GE, "GE");
  op_2_str(EQ, "EQ");
  op_2_str(LT, "LT");
  op_2_str(LE, "LE");
  op_2_str(NE, "NE");

  op_2_str(CAL, "CAL");
  op_2_str(CALC, "CALC");
  op_2_str(CALCN, "CALCN");
  op_2_str(RET, "RET");
  op_2_str(RETC, "RETC");
  op_2_str(RETCN, "RETCN");
  op_2_str(JMP, "JMP");
  op_2_str(JMPC, "JMPC");
  op_2_str(JMPCN, "JMPCN");

  if (name == NULL)
    ERROR;

  res = new identifier_c(strdup(name), 
                         il_operator->first_line,
                         il_operator->first_column,
                         il_operator->last_line,
                         il_operator->last_column
                        );
  free(il_operator);
  return res;
}


#include "standard_function_names.c"

const char *standard_function_block_names[] = {
// 2.5.2.3.1  Bistable elements
//   Table 34 - Standard bistable function blocks
"SR","RS",
// 2.5.2.3.2  Edge detection
//   Table 35 - Standard edge detection function blocks
"R_TRIG","F_TRIG",
// 2.5.2.3.3  Counters
//   Table 36 - Standard counter function blocks
"CTU","CTU_DINT","CTU_LINT","CTU_UDINT","CTU_ULINT",
"CTD","CTD_DINT","CTD_LINT","CTD_UDINT","CTD_ULINT",
"CTUD","CTUD_DINT","CTUD_LINT","CTUD_ULINT",
// 2.5.2.3.4  Timers
//   Table 37 - Standard timer function blocks
"TP","TON","TOF",
/* end of array marker! Do not remove! */
NULL
};


#define LIBFILE "ieclib.txt"
#define DEF_LIBFILENAME LIBDIRECTORY "/" LIBFILE

extern const char *INCLUDE_DIRECTORIES[];

int 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) {
    INCLUDE_DIRECTORIES[0] = includedir;
  }
  if ((libfilename = strdup3(INCLUDE_DIRECTORIES[0], "/", LIBFILE)) == NULL) {
    fprintf (stderr, "Out of memory. Bailing out!\n");
    return -1;
  }

  if((lib_file = fopen(libfilename, "r")) == NULL) {
    char *errmsg = strdup2("Error opening library file ", libfilename);
    perror(errmsg);
    free(errmsg);
  }

  if (lib_file == NULL) {
    /* we give up... */
    free(libfilename);
    fclose(in_file);
    return -1;
  }

  /* first parse the standard library file... */
  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;
  {int res;
    if ((res = yyparse()) != 0) {
      fprintf (stderr, "\nInternal error while parsing file - yyparse() returned %d. Bailing out!\n", res);
      ERROR;
    }
  }

  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;
}