/*
* matiec - a compiler for the programming languages defined in IEC 61131-3
*
* Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt)
* Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
* This code is made available on the understanding that it will not be
* used in safety-critical situations without a full and competent review.
*/
/*
* An IEC 61131-3 compiler.
*
* Based on the
* FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
*
*/
/*
* Stage 2
* =======
*
* This file contains the syntax definition of the textual
* languages IL and ST, as well as the textual version of SFC.
* The syntax parser, comprising the 2nd stage of the overall
* compiler, is generated by runing bison on this file.
*/
/**********************************************************************/
/**********************************************************************/
/**********************************************************************/
/**********************************************************************/
/******* *******/
/******* The following syntax does not have any conflicts. *******/
/******* *******/
/******* P L E A S E K E E P I T T H A T W A Y ! *******/
/******* =================================================== *******/
/******* *******/
/**********************************************************************/
/**********************************************************************/
/**********************************************************************/
/**********************************************************************/
%{
#include /* required for strdup() */
/* declare the token parser generated by flex... */
int yylex(void);
/* declare the error handler defined at the end of this file */
void yyerror (const char *error_msg);
/* produce a more verbose parsing error message */
#define YYERROR_VERBOSE
/* Include debuging code.
* Printing of debug info must then be activated by setting
* the variable yydebug to 1.
*/
#define YYDEBUG 0
/* file with declaration of absyntax classes... */
#include "../absyntax/absyntax.hh"
/* file with declaration of token constants. Generated by bison! */
#include "iec.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 in list_c *
* execute the code
*/
#define FOR_EACH_ELEMENT(elem, list, code) { \
symbol_c *elem; \
for(int i = 0; i < list->n; i++) { \
elem = list->elements[i]; \
code; \
} \
}
/* Macros used to pass the line and column locations when
* creating a new object for the abstract syntax tree.
*/
#define locloc(foo) foo.first_line, foo.first_column, foo.first_file, foo.first_order, foo.last_line, foo.last_column, foo.last_file, foo.last_order
#define locf(foo) foo.first_line, foo.first_column, foo.first_file, foo.first_order
#define locl(foo) foo.last_line, foo.last_column, foo.last_file, foo.last_order
/* Redefine the default action to take for each rule, so that the filenames are correctly processed... */
# define YYLLOC_DEFAULT(Current, Rhs, N) \
do \
if (N) \
{ \
(Current).first_line = YYRHSLOC(Rhs, 1).first_line; \
(Current).first_column = YYRHSLOC(Rhs, 1).first_column; \
(Current).first_file = YYRHSLOC(Rhs, 1).first_file; \
(Current).first_order = YYRHSLOC(Rhs, 1).first_order; \
(Current).last_line = YYRHSLOC(Rhs, N).last_line; \
(Current).last_column = YYRHSLOC(Rhs, N).last_column; \
(Current).last_file = YYRHSLOC(Rhs, 1).last_file; \
(Current).last_order = YYRHSLOC(Rhs, 1).last_order; \
} \
else \
{ \
(Current).first_line = (Current).last_line = \
YYRHSLOC(Rhs, 0).last_line; \
(Current).first_column = (Current).last_column = \
YYRHSLOC(Rhs, 0).last_column; \
(Current).first_file = (Current).last_file = \
YYRHSLOC(Rhs, 0).last_file; \
(Current).first_order = (Current).last_order = \
YYRHSLOC(Rhs, 0).last_order; \
} \
while (0)
/* A macro for printing out internal parser errors... */
#define ERROR error_exit(__FILE__,__LINE__)
/* function defined in main.cc */
extern void error_exit(const char *file_name, int line_no);
/*************************/
/* global variables... */
/*************************/
/* NOTE: For some strange reason bison ver 2.3 is including these declarations
* in the iec.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)
*/
/* NOTE: These variable are really parameters we would like the stage2__ function to pass
* to the yyparse() function. However, the yyparse() function is created automatically
* by bison, so we cannot add parameters to this function. The only other
* option is to use global variables! yuck!
*/
/* A global flag used to tell the parser if overloaded funtions should be allowed.
* The IEC 61131-3 standard allows overloaded funtions in the standard library,
* but disallows them in user code...
*/
extern bool allow_function_overloading;
/* A global flag used to tell the parser whether to include the full variable location
* when printing out error messages...
*/
extern bool full_token_loc;
/* A pointer to the root of the parsing tree that will be generated
* by bison.
*/
extern symbol_c *tree_root;
/************************/
/* forward declarations */
/************************/
/* The functions declared here are defined at the end of this file... */
/* Convert an il_operator_c into an identifier_c */
symbol_c *il_operator_c_2_identifier_c(symbol_c *il_operator);
/* return if current token is a syntax element */
/* ERROR_CHECK_BEGIN */
bool is_current_syntax_token();
/* ERROR_CHECK_END */
/* print an error message */
void print_err_msg(int first_line,
int first_column,
const char *first_filename,
long int first_order,
int last_line,
int last_column,
const char *last_filename,
long int last_order,
const char *additional_error_msg);
%}
// %glr-parser
// %expect-rr 1
/* The following definitions need to be inside a '%code requires'
* so that they are also included in the header files. If this were not the case,
* YYLTYPE would be delcared as something in the iec.cc file, and another thing
* (actually the default value of YYLTYPE) in the iec.y.hh heder file.
*/
%code requires {
/* define a new data type to store the locations, so we can also store
* the filename in which the token is expressed.
*/
/* NOTE: since this code will be placed in the iec.y.hh header file,
* as well as the iec.cc file that also includes the iec.y.hh header file,
* declaring the typedef struct yyltype__local here would result in a
* compilation error when compiling iec.cc, as this struct would be
* declared twice.
* We therefore use the #if !defined YYLTYPE ...
* to make sure only the first declaration is parsed by the C++ compiler.
*
* At first glance it seems that what we really should do is delcare the
* YYLTYPE directly as an anonymous struct, thus:
* #define YYLTYPE struct{ ...}
* however, this also results in compilation errors.
*
* I (Mario) think this is kind of a hack. If you know how to
* do this re-declaration of YYLTYPE properly, please let me know!
*/
#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
typedef struct {
int first_line;
int first_column;
const char *first_file;
long int first_order;
int last_line;
int last_column;
const char *last_file;
long int last_order;
} yyltype__local;
#define YYLTYPE yyltype__local
#endif
}
%union {
symbol_c *leaf;
list_c *list;
char *ID; /* token value */
}
/*
TODO: DO we need to define a destructor do free
memory when recovering from errors, or do the
class destructors already handle this?
Following is example on how to define
detructors, using the syntax:
%destructor { CODE } SYMBOLS
%union
{
char *string;
}
%token STRING
%type string
%destructor { free ($$); } STRING string
*/
/*************************************/
/* Prelimenary helpful constructs... */
/*************************************/
/* A token used to identify the very end of the input file
* after all includes have already been processed.
*
* Flex automatically returns the token with value 0
* at the end of the file. We therefore specify here
* a token with that exact same value here, so we can use it
* to detect the very end of the input files.
*/
%token END_OF_INPUT 0
/* A bogus token that, in principle, flex MUST NEVER generate */
/* USE 1:
* ======
* This token is currently also being used as the default
* initialisation value of the token_id member in
* the symbol_c base class.
*
* USE 2
* =====
* This token may also be used in the future to remove
* mysterious reduce/reduce conflicts due to the fact
* that our grammar may not be LALR(1) but merely LR(1).
* This means that bison cannot handle it without some
* caoxing from ourselves. We will then need this token
* to do the coaxing...
*/
%token BOGUS_TOKEN_ID
%type start
%type any_identifier
%token prev_declared_variable_name_token
%token prev_declared_direct_variable_token
%token prev_declared_fb_name_token
%type prev_declared_variable_name
%type prev_declared_direct_variable
%type prev_declared_fb_name
%token prev_declared_simple_type_name_token
%token prev_declared_subrange_type_name_token
%token prev_declared_enumerated_type_name_token
%token prev_declared_array_type_name_token
%token prev_declared_structure_type_name_token
%token prev_declared_string_type_name_token
%type prev_declared_simple_type_name
%type prev_declared_subrange_type_name
%type prev_declared_enumerated_type_name
%type prev_declared_array_type_name
%type prev_declared_structure_type_name
%type prev_declared_string_type_name
%token prev_declared_derived_function_name_token
%token prev_declared_derived_function_block_name_token
%token prev_declared_program_type_name_token
%type prev_declared_derived_function_name
%type prev_declared_derived_function_block_name
%type prev_declared_program_type_name
/**********************************************************************************/
/* B XXX - Things that are missing from the standard, but should have been there! */
/**********************************************************************************/
/* Pragmas that our compiler will accept.
* See the comment in iec.flex for why these pragmas exist.
*/
%token disable_code_generation_pragma_token
%token enable_code_generation_pragma_token
%type disable_code_generation_pragma
%type enable_code_generation_pragma
/* All other pragmas that we do not support... */
/* In most stage 4, the text inside the pragmas will simply be copied to the output file.
* This allows us to insert C code (if using stage 4 generating C code)
* inside/interningled with the IEC 61131-3 code!
*/
%token pragma_token
%type pragma
/* The joining of all previous pragmas, i.e. any possible pragma */
%type any_pragma
/* Where do these tokens belong?? They are missing from the standard! */
/* NOTE: There are other tokens related to these 'EN' ENO', that are also
* missing from the standard. However, their location in the annex B is
* relatively obvious, so they have been inserted in what seems to us their
* correct place in order to ease understanding of the parser...
*/
%token EN
%token ENO
%type en_identifier
%type eno_identifier
/***************************/
/* B 0 - Programming Model */
/***************************/
%type library
%type library_element_declaration
/*******************************************/
/* B 1.1 - Letters, digits and identifiers */
/*******************************************/
/* Done totally within flex...
letter
digit
octal_digit
hex_digit
*/
%token identifier_token
%type identifier
/*********************/
/* B 1.2 - Constants */
/*********************/
%type constant
%type non_negative_constant
/******************************/
/* B 1.2.1 - Numeric Literals */
/******************************/
/* Done totally within flex...
bit
*/
%type numeric_literal
%type integer_literal
%type signed_integer
%token integer_token
%type integer
%token binary_integer_token
%type binary_integer
%token octal_integer_token
%type octal_integer
%token hex_integer_token
%type hex_integer
%token real_token
%type real
%type signed_real
%type real_literal
// %type exponent
%type bit_string_literal
%type boolean_literal
%token safeboolean_true_literal_token
%token safeboolean_false_literal_token
%token boolean_true_literal_token
%token boolean_false_literal_token
%token FALSE
%token TRUE
/*******************************/
/* B 1.2.2 - Character Strings */
/*******************************/
%token single_byte_character_string_token
%token double_byte_character_string_token
%type character_string
%type single_byte_character_string
%type double_byte_character_string
/***************************/
/* B 1.2.3 - Time Literals */
/***************************/
%type time_literal
/************************/
/* B 1.2.3.1 - Duration */
/************************/
%type duration
%type interval
%type days
%type fixed_point
%type hours
%type minutes
%type seconds
%type milliseconds
%type integer_d
%type integer_h
%type integer_m
%type integer_s
%type integer_ms
%type fixed_point_d
%type fixed_point_h
%type fixed_point_m
%type fixed_point_s
%type fixed_point_ms
%token fixed_point_token
%token fixed_point_d_token
%token integer_d_token
%token fixed_point_h_token
%token integer_h_token
%token fixed_point_m_token
%token integer_m_token
%token fixed_point_s_token
%token integer_s_token
%token fixed_point_ms_token
%token integer_ms_token
// %token TIME
%token T_SHARP
/************************************/
/* B 1.2.3.2 - Time of day and Date */
/************************************/
%type time_of_day
%type daytime
%type day_hour
%type day_minute
%type day_second
%type date
%type date_literal
%type year
%type month
%type day
%type date_and_time
// %token TIME_OF_DAY
// %token DATE
%token D_SHARP
// %token DATE_AND_TIME
/**********************/
/* B 1.3 - Data Types */
/**********************/
/* Strangely, the following symbol does seem to be required! */
// %type data_type_name
%type non_generic_type_name
/***********************************/
/* B 1.3.1 - Elementary Data Types */
/***********************************/
/* NOTES:
*
* - To make the definition of bit_string_literal more
* concise, it is useful to use an extra non-terminal
* symbol (i.e. a grouping or construct) that groups the
* following elements (BYTE, WORD, DWORD, LWORD).
* Note that the definition of bit_string_type_name
* (according to the spec) includes the above elements
* and an extra BOOL.
* We could use an extra construct with the first four
* elements to be used solely in the definition of
* bit_string_literal, but with the objective of not
* having to replicate the actions (if we ever need
* to change them, they would need to be changed in both
* bit_string_type_name and the extra grouping), we
* have re-defined bit_string_type_name as only including
* the first four elements.
* In order to have our parser implement the specification
* correctly we have augmented every occurence of
* bit_string_type_name in other rules with the BOOL
* token. Since bit_string_type_name only appears in
* the rule for elementary_type_name, this does not
* seem to be a big concession to make!
*
* - We have added a helper symbol to concentrate the
* instantiation of STRING and WSTRING into a single
* location (elementary_string_type_name).
* These two elements show up in several other rules,
* but we want to create the equivalent abstract syntax
* in a single location of this file, in order to make
* possible future changes easier to edit...
*/
%type elementary_type_name
%type numeric_type_name
%type integer_type_name
%type signed_integer_type_name
%type unsigned_integer_type_name
%type real_type_name
%type date_type_name
%type bit_string_type_name
/* helper symbol to concentrate the instantiation
* of STRING and WSTRING into a single location
*/
%type elementary_string_type_name
%token BYTE
%token WORD
%token DWORD
%token LWORD
%token LREAL
%token REAL
%token SINT
%token INT
%token DINT
%token LINT
%token USINT
%token UINT
%token UDINT
%token ULINT
%token WSTRING
%token STRING
%token BOOL
%token TIME
%token DATE
%token DATE_AND_TIME
%token DT
%token TIME_OF_DAY
%token TOD
/******************************************************/
/* Symbols defined in */
/* "Safety Software Technical Specification, */
/* Part 1: Concepts and Function Blocks, */
/* Version 1.0 – Official Release" */
/* by PLCopen - Technical Committee 5 - 2006-01-31 */
/******************************************************/
%token SAFEBYTE
%token SAFEWORD
%token SAFEDWORD
%token SAFELWORD
%token SAFELREAL
%token SAFEREAL
%token SAFESINT
%token SAFEINT
%token SAFEDINT
%token SAFELINT
%token SAFEUSINT
%token SAFEUINT
%token SAFEUDINT
%token SAFEULINT
%token SAFEWSTRING
%token SAFESTRING
%token SAFEBOOL
%token SAFETIME
%token SAFEDATE
%token SAFEDATE_AND_TIME
%token SAFEDT
%token SAFETIME_OF_DAY
%token SAFETOD
/********************************/
/* B 1.3.2 - Generic data types */
/********************************/
/* Strangely, the following symbol does seem to be required! */
// %type generic_type_name
/* The following tokens do not seem to be used either
* but we declare them so they become reserved words...
*/
%token ANY
%token ANY_DERIVED
%token ANY_ELEMENTARY
%token ANY_MAGNITUDE
%token ANY_NUM
%token ANY_REAL
%token ANY_INT
%token ANY_BIT
%token ANY_STRING
%token ANY_DATE
/********************************/
/* B 1.3.3 - Derived data types */
/********************************/
%type derived_type_name
%type single_element_type_name
// %type simple_type_name
// %type subrange_type_name
// %type enumerated_type_name
// %type array_type_name
// %type structure_type_name
%type data_type_declaration
/* helper symbol for data_type_declaration */
%type type_declaration_list
%type type_declaration
%type single_element_type_declaration
%type simple_type_declaration
%type simple_spec_init
%type simple_specification
%type subrange_type_declaration
%type subrange_spec_init
%type subrange_specification
%type subrange
%type enumerated_type_declaration
%type enumerated_spec_init
%type enumerated_specification
/* helper symbol for enumerated_value */
%type enumerated_value_list
%type enumerated_value
//%type enumerated_value_without_identifier
%type array_type_declaration
%type array_spec_init
%type array_specification
/* helper symbol for array_specification */
%type array_subrange_list
%type array_initialization
/* helper symbol for array_initialization */
%type array_initial_elements_list
%type array_initial_elements
%type array_initial_element
%type structure_type_declaration
%type structure_specification
%type initialized_structure
%type structure_declaration
/* helper symbol for structure_declaration */
%type structure_element_declaration_list
%type structure_element_declaration
%type structure_element_name
%type structure_initialization
/* helper symbol for structure_initialization */
%type structure_element_initialization_list
%type structure_element_initialization
//%type string_type_name
%type string_type_declaration
/* helper symbol for string_type_declaration */
%type string_type_declaration_size
/* helper symbol for string_type_declaration */
%type string_type_declaration_init
%token ASSIGN
%token DOTDOT /* ".." */
%token TYPE
%token END_TYPE
%token ARRAY
%token OF
%token STRUCT
%token END_STRUCT
/*********************/
/* B 1.4 - Variables */
/*********************/
%type variable
%type symbolic_variable
/* helper symbol for prog_cnxn */
%type any_symbolic_variable
%type variable_name
/********************************************/
/* B.1.4.1 Directly Represented Variables */
/********************************************/
/* Done totally within flex...
location_prefix
size_prefix
*/
%token direct_variable_token
//%type direct_variable
/*************************************/
/* B.1.4.2 Multi-element Variables */
/*************************************/
%type multi_element_variable
/* helper symbol for any_symbolic_variable */
%type any_multi_element_variable
%type array_variable
/* helper symbol for any_symbolic_variable */
%type any_array_variable
%type subscripted_variable
/* helper symbol for any_symbolic_variable */
%type any_subscripted_variable
%type subscript_list
%type subscript
%type structured_variable
/* helper symbol for any_symbolic_variable */
%type any_structured_variable
%type record_variable
/* helper symbol for any_symbolic_variable */
%type any_record_variable
%type field_selector
/******************************************/
/* B 1.4.3 - Declaration & Initialisation */
/******************************************/
%type input_declarations
/* helper symbol for input_declarations */
%type input_declaration_list
%type input_declaration
%type edge_declaration
/* en_param_declaration is not in the standard, but should be! */
%type en_param_declaration
%type var_init_decl
%type var1_init_decl
%type var1_list
%type array_var_init_decl
%type structured_var_init_decl
%type fb_name_decl
/* helper symbol for fb_name_decl */
%type fb_name_list_with_colon
/* helper symbol for fb_name_list_with_colon */
%type var1_list_with_colon
// %type fb_name_list
// %type fb_name
%type output_declarations
%type var_output_init_decl
%type var_output_init_decl_list
/* eno_param_declaration is not in the standard, but should be! */
%type eno_param_declaration
%type input_output_declarations
/* helper symbol for input_output_declarations */
%type var_declaration_list
%type var_declaration
%type temp_var_decl
%type var1_declaration
%type array_var_declaration
%type structured_var_declaration
%type var_declarations
%type retentive_var_declarations
%type located_var_declarations
/* helper symbol for located_var_declarations */
%type located_var_decl_list
%type located_var_decl
%type external_var_declarations
/* helper symbol for external_var_declarations */
%type external_declaration_list
%type external_declaration
%type global_var_name
%type global_var_declarations
/* helper symbol for global_var_declarations */
%type global_var_decl_list
%type global_var_decl
%type global_var_spec
%type located_var_spec_init
%type location
%type global_var_list
%type string_var_declaration
%type single_byte_string_var_declaration
%type single_byte_string_spec
%type double_byte_string_var_declaration
%type double_byte_string_spec
%type incompl_located_var_declarations
/* helper symbol for incompl_located_var_declarations */
%type incompl_located_var_decl_list
%type incompl_located_var_decl
%type incompl_location
%type var_spec
/* helper symbol for var_spec */
%type string_spec
/* intermediate helper symbol for:
* - non_retentive_var_decls
* - var_declarations
*/
%type var_init_decl_list
%token incompl_location_token
%token VAR_INPUT
%token VAR_OUTPUT
%token VAR_IN_OUT
%token VAR_EXTERNAL
%token VAR_GLOBAL
%token END_VAR
%token RETAIN
%token NON_RETAIN
%token R_EDGE
%token F_EDGE
%token AT
/***********************/
/* B 1.5.1 - Functions */
/***********************/
// %type function_name
/* helper symbol for IL language */
%type function_name_no_clashes
%type function_name_simpleop_clashes
//%type function_name_expression_clashes
/* helper symbols for ST language */
//%type function_name_NOT_clashes
%type function_name_no_NOT_clashes
//%type standard_function_name
/* helper symbols for IL language */
%type standard_function_name_no_clashes
%type standard_function_name_simpleop_clashes
%type standard_function_name_expression_clashes
/* helper symbols for ST language */
%type standard_function_name_NOT_clashes
%type standard_function_name_no_NOT_clashes
%type derived_function_name
%type