# HG changeset patch # User mjsousa # Date 1418212663 0 # Node ID b05f63d9d0fa10a6a18897c001a6a6b10db543bf # Parent 8bfcc8e62bd6902f735247bbcddff7e1c56e47db# Parent 27063736913fe64553f6540aab85b1f30e616bbf merge diff -r 27063736913f -r b05f63d9d0fa absyntax/absyntax.cc --- a/absyntax/absyntax.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/absyntax/absyntax.cc Wed Dec 10 11:57:43 2014 +0000 @@ -172,7 +172,16 @@ /* corrent the new size */ n--; /* elements = (symbol_c **)realloc(elements, n * sizeof(symbol_c *)); */ -} + /* TODO: adjust the location parameters, taking into account the removed element. */ +} + + +/* remove element at position pos. */ +void list_c::clear(void) { + n = 0; + /* TODO: adjust the location parameters, taking into account the removed element. */ +} + #define SYM_LIST(class_name_c, ...) \ class_name_c::class_name_c( \ diff -r 27063736913f -r b05f63d9d0fa absyntax/absyntax.def --- a/absyntax/absyntax.def Sat Nov 22 19:30:47 2014 +0000 +++ b/absyntax/absyntax.def Wed Dec 10 11:57:43 2014 +0000 @@ -128,6 +128,7 @@ /* A special identifier class, used for identifiers that have been previously declared as a derived datatype */ /* This is currently needed because generate_c stage 4 needs to handle the array datatype identifiers differently to all other identifiers. */ SYM_TOKEN(derived_datatype_identifier_c) +SYM_TOKEN(poutype_identifier_c) /*********************/ diff -r 27063736913f -r b05f63d9d0fa absyntax/absyntax.hh --- a/absyntax/absyntax.hh Sat Nov 22 19:30:47 2014 +0000 +++ b/absyntax/absyntax.hh Wed Dec 10 11:57:43 2014 +0000 @@ -247,6 +247,8 @@ virtual void insert_element(symbol_c *elem, int pos = 0); /* remove element at position pos. */ virtual void remove_element(int pos = 0); + /* remove all elements from list. Does not delete the elements in the list! */ + virtual void clear(void); }; diff -r 27063736913f -r b05f63d9d0fa absyntax_utils/function_call_iterator.cc --- a/absyntax_utils/function_call_iterator.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/absyntax_utils/function_call_iterator.cc Wed Dec 10 11:57:43 2014 +0000 @@ -89,10 +89,10 @@ } /* Returns the name of the currently referenced function invocation */ -identifier_c *function_call_iterator_c::fname(void) { - identifier_c *identifier = dynamic_cast(current_fcall_name); - if (identifier == NULL) ERROR; - return identifier; +token_c *function_call_iterator_c::fname(void) { + token_c *fname_sym = dynamic_cast(current_fcall_name); + if (fname_sym == NULL) ERROR; + return fname_sym; } diff -r 27063736913f -r b05f63d9d0fa absyntax_utils/function_call_iterator.hh --- a/absyntax_utils/function_call_iterator.hh Sat Nov 22 19:30:47 2014 +0000 +++ b/absyntax_utils/function_call_iterator.hh Wed Dec 10 11:57:43 2014 +0000 @@ -73,7 +73,7 @@ symbol_c *next(void); /* Returns the name of the currently referenced function invocation */ - identifier_c *fname(void); + token_c *fname(void); private: /***************************************/ diff -r 27063736913f -r b05f63d9d0fa absyntax_utils/get_datatype_info.cc --- a/absyntax_utils/get_datatype_info.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/absyntax_utils/get_datatype_info.cc Wed Dec 10 11:57:43 2014 +0000 @@ -149,12 +149,18 @@ * That anotation is specific to the generate_c stage4 code, and must therefore NOT be referenced * in the absyntax_utils code, as this last code should be independent of the stage4 version! */ - + /*****************************/ /* B 1.5.2 - Function Blocks */ /*****************************/ /* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */ void *visit(function_block_declaration_c *symbol) {return symbol->fblock_name;} + /**********************/ + /* B 1.5.3 - Programs */ + /**********************/ + /* PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */ + void *visit(program_declaration_c *symbol) {return symbol->program_type_name;} + }; // get_datatype_id_c get_datatype_id_c *get_datatype_id_c::singleton = NULL; @@ -200,7 +206,12 @@ /* B 1.1 - Letters, digits and identifiers */ /*******************************************/ void *visit( identifier_c *symbol) {return (void *)symbol->value;}; - void *visit(derived_datatype_identifier_c *symbol) {return (void *)symbol->value;}; + // Should not be necessary, as datatype declarations currently use an identifier_c for their name! + // Only references to the datatype (when declaring variable, for ex., will use poutype_identifier_c + void *visit(derived_datatype_identifier_c *symbol) {return (void *)symbol->value;}; + // Should not be necessary, as FB declarations currently use an identifier_c for their name! + // Only references to the FB (when declaring variable, for ex., will use poutype_identifier_c + void *visit( poutype_identifier_c *symbol) {return (void *)symbol->value;}; /***********************************/ /* B 1.3.1 - Elementary Data Types */ @@ -277,11 +288,23 @@ * in the absyntax_utils code, as this last code should be independent of the stage4 version! */ + /***********************/ + /* B 1.5.1 - Functions */ + /***********************/ + /* Functions are not really datatypes, but we include it here as it helps in printing out error messages! */ + /* Currently this is needed only by remove_forward_depencies_c::print_circ_error() */ + /* FUNCTION derived_function_name ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ + void *visit( function_declaration_c *symbol) {return symbol->derived_function_name->accept(*this);} /*****************************/ /* B 1.5.2 - Function Blocks */ /*****************************/ /* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */ void *visit(function_block_declaration_c *symbol) {return symbol->fblock_name->accept(*this);} + /**********************/ + /* B 1.5.3 - Programs */ + /**********************/ + /* PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */ + void *visit( program_declaration_c *symbol) {return symbol->program_type_name->accept(*this);} }; get_datatype_id_str_c *get_datatype_id_str_c::singleton = NULL; diff -r 27063736913f -r b05f63d9d0fa absyntax_utils/get_function_type_decl.c --- a/absyntax_utils/get_function_type_decl.c Sat Nov 22 19:30:47 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1327 +0,0 @@ -/* - * Copyright (C) 2007-2011: Edouard TISSERANT and Laurent BESSARD - * - * See COPYING and COPYING.LESSER files for copyright details. - * - * 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 . - * - */ - -/**** - * IEC 61131-3 standard function library - * generated code, do not edit by hand - */ - - -function_type_t get_function_type(identifier_c *function_name) { - -if (!strcasecmp(function_name->value, "REAL_TO_SINT")) - return function_real_to_sint; - -if (!strcasecmp(function_name->value, "REAL_TO_LINT")) - return function_real_to_lint; - -if (!strcasecmp(function_name->value, "REAL_TO_DINT")) - return function_real_to_dint; - -if (!strcasecmp(function_name->value, "REAL_TO_DATE")) - return function_real_to_date; - -if (!strcasecmp(function_name->value, "REAL_TO_DWORD")) - return function_real_to_dword; - -if (!strcasecmp(function_name->value, "REAL_TO_DT")) - return function_real_to_dt; - -if (!strcasecmp(function_name->value, "REAL_TO_TOD")) - return function_real_to_tod; - -if (!strcasecmp(function_name->value, "REAL_TO_UDINT")) - return function_real_to_udint; - -if (!strcasecmp(function_name->value, "REAL_TO_WORD")) - return function_real_to_word; - -if (!strcasecmp(function_name->value, "REAL_TO_STRING")) - return function_real_to_string; - -if (!strcasecmp(function_name->value, "REAL_TO_LWORD")) - return function_real_to_lword; - -if (!strcasecmp(function_name->value, "REAL_TO_UINT")) - return function_real_to_uint; - -if (!strcasecmp(function_name->value, "REAL_TO_LREAL")) - return function_real_to_lreal; - -if (!strcasecmp(function_name->value, "REAL_TO_BYTE")) - return function_real_to_byte; - -if (!strcasecmp(function_name->value, "REAL_TO_USINT")) - return function_real_to_usint; - -if (!strcasecmp(function_name->value, "REAL_TO_ULINT")) - return function_real_to_ulint; - -if (!strcasecmp(function_name->value, "REAL_TO_BOOL")) - return function_real_to_bool; - -if (!strcasecmp(function_name->value, "REAL_TO_TIME")) - return function_real_to_time; - -if (!strcasecmp(function_name->value, "REAL_TO_INT")) - return function_real_to_int; - -if (!strcasecmp(function_name->value, "SINT_TO_REAL")) - return function_sint_to_real; - -if (!strcasecmp(function_name->value, "SINT_TO_LINT")) - return function_sint_to_lint; - -if (!strcasecmp(function_name->value, "SINT_TO_DINT")) - return function_sint_to_dint; - -if (!strcasecmp(function_name->value, "SINT_TO_DATE")) - return function_sint_to_date; - -if (!strcasecmp(function_name->value, "SINT_TO_DWORD")) - return function_sint_to_dword; - -if (!strcasecmp(function_name->value, "SINT_TO_DT")) - return function_sint_to_dt; - -if (!strcasecmp(function_name->value, "SINT_TO_TOD")) - return function_sint_to_tod; - -if (!strcasecmp(function_name->value, "SINT_TO_UDINT")) - return function_sint_to_udint; - -if (!strcasecmp(function_name->value, "SINT_TO_WORD")) - return function_sint_to_word; - -if (!strcasecmp(function_name->value, "SINT_TO_STRING")) - return function_sint_to_string; - -if (!strcasecmp(function_name->value, "SINT_TO_LWORD")) - return function_sint_to_lword; - -if (!strcasecmp(function_name->value, "SINT_TO_UINT")) - return function_sint_to_uint; - -if (!strcasecmp(function_name->value, "SINT_TO_LREAL")) - return function_sint_to_lreal; - -if (!strcasecmp(function_name->value, "SINT_TO_BYTE")) - return function_sint_to_byte; - -if (!strcasecmp(function_name->value, "SINT_TO_USINT")) - return function_sint_to_usint; - -if (!strcasecmp(function_name->value, "SINT_TO_ULINT")) - return function_sint_to_ulint; - -if (!strcasecmp(function_name->value, "SINT_TO_BOOL")) - return function_sint_to_bool; - -if (!strcasecmp(function_name->value, "SINT_TO_TIME")) - return function_sint_to_time; - -if (!strcasecmp(function_name->value, "SINT_TO_INT")) - return function_sint_to_int; - -if (!strcasecmp(function_name->value, "LINT_TO_REAL")) - return function_lint_to_real; - -if (!strcasecmp(function_name->value, "LINT_TO_SINT")) - return function_lint_to_sint; - -if (!strcasecmp(function_name->value, "LINT_TO_DINT")) - return function_lint_to_dint; - -if (!strcasecmp(function_name->value, "LINT_TO_DATE")) - return function_lint_to_date; - -if (!strcasecmp(function_name->value, "LINT_TO_DWORD")) - return function_lint_to_dword; - -if (!strcasecmp(function_name->value, "LINT_TO_DT")) - return function_lint_to_dt; - -if (!strcasecmp(function_name->value, "LINT_TO_TOD")) - return function_lint_to_tod; - -if (!strcasecmp(function_name->value, "LINT_TO_UDINT")) - return function_lint_to_udint; - -if (!strcasecmp(function_name->value, "LINT_TO_WORD")) - return function_lint_to_word; - -if (!strcasecmp(function_name->value, "LINT_TO_STRING")) - return function_lint_to_string; - -if (!strcasecmp(function_name->value, "LINT_TO_LWORD")) - return function_lint_to_lword; - -if (!strcasecmp(function_name->value, "LINT_TO_UINT")) - return function_lint_to_uint; - -if (!strcasecmp(function_name->value, "LINT_TO_LREAL")) - return function_lint_to_lreal; - -if (!strcasecmp(function_name->value, "LINT_TO_BYTE")) - return function_lint_to_byte; - -if (!strcasecmp(function_name->value, "LINT_TO_USINT")) - return function_lint_to_usint; - -if (!strcasecmp(function_name->value, "LINT_TO_ULINT")) - return function_lint_to_ulint; - -if (!strcasecmp(function_name->value, "LINT_TO_BOOL")) - return function_lint_to_bool; - -if (!strcasecmp(function_name->value, "LINT_TO_TIME")) - return function_lint_to_time; - -if (!strcasecmp(function_name->value, "LINT_TO_INT")) - return function_lint_to_int; - -if (!strcasecmp(function_name->value, "DINT_TO_REAL")) - return function_dint_to_real; - -if (!strcasecmp(function_name->value, "DINT_TO_SINT")) - return function_dint_to_sint; - -if (!strcasecmp(function_name->value, "DINT_TO_LINT")) - return function_dint_to_lint; - -if (!strcasecmp(function_name->value, "DINT_TO_DATE")) - return function_dint_to_date; - -if (!strcasecmp(function_name->value, "DINT_TO_DWORD")) - return function_dint_to_dword; - -if (!strcasecmp(function_name->value, "DINT_TO_DT")) - return function_dint_to_dt; - -if (!strcasecmp(function_name->value, "DINT_TO_TOD")) - return function_dint_to_tod; - -if (!strcasecmp(function_name->value, "DINT_TO_UDINT")) - return function_dint_to_udint; - -if (!strcasecmp(function_name->value, "DINT_TO_WORD")) - return function_dint_to_word; - -if (!strcasecmp(function_name->value, "DINT_TO_STRING")) - return function_dint_to_string; - -if (!strcasecmp(function_name->value, "DINT_TO_LWORD")) - return function_dint_to_lword; - -if (!strcasecmp(function_name->value, "DINT_TO_UINT")) - return function_dint_to_uint; - -if (!strcasecmp(function_name->value, "DINT_TO_LREAL")) - return function_dint_to_lreal; - -if (!strcasecmp(function_name->value, "DINT_TO_BYTE")) - return function_dint_to_byte; - -if (!strcasecmp(function_name->value, "DINT_TO_USINT")) - return function_dint_to_usint; - -if (!strcasecmp(function_name->value, "DINT_TO_ULINT")) - return function_dint_to_ulint; - -if (!strcasecmp(function_name->value, "DINT_TO_BOOL")) - return function_dint_to_bool; - -if (!strcasecmp(function_name->value, "DINT_TO_TIME")) - return function_dint_to_time; - -if (!strcasecmp(function_name->value, "DINT_TO_INT")) - return function_dint_to_int; - -if (!strcasecmp(function_name->value, "DATE_TO_REAL")) - return function_date_to_real; - -if (!strcasecmp(function_name->value, "DATE_TO_SINT")) - return function_date_to_sint; - -if (!strcasecmp(function_name->value, "DATE_TO_LINT")) - return function_date_to_lint; - -if (!strcasecmp(function_name->value, "DATE_TO_DINT")) - return function_date_to_dint; - -if (!strcasecmp(function_name->value, "DATE_TO_DWORD")) - return function_date_to_dword; - -if (!strcasecmp(function_name->value, "DATE_TO_UDINT")) - return function_date_to_udint; - -if (!strcasecmp(function_name->value, "DATE_TO_WORD")) - return function_date_to_word; - -if (!strcasecmp(function_name->value, "DATE_TO_STRING")) - return function_date_to_string; - -if (!strcasecmp(function_name->value, "DATE_TO_LWORD")) - return function_date_to_lword; - -if (!strcasecmp(function_name->value, "DATE_TO_UINT")) - return function_date_to_uint; - -if (!strcasecmp(function_name->value, "DATE_TO_LREAL")) - return function_date_to_lreal; - -if (!strcasecmp(function_name->value, "DATE_TO_BYTE")) - return function_date_to_byte; - -if (!strcasecmp(function_name->value, "DATE_TO_USINT")) - return function_date_to_usint; - -if (!strcasecmp(function_name->value, "DATE_TO_ULINT")) - return function_date_to_ulint; - -if (!strcasecmp(function_name->value, "DATE_TO_INT")) - return function_date_to_int; - -if (!strcasecmp(function_name->value, "DWORD_TO_REAL")) - return function_dword_to_real; - -if (!strcasecmp(function_name->value, "DWORD_TO_SINT")) - return function_dword_to_sint; - -if (!strcasecmp(function_name->value, "DWORD_TO_LINT")) - return function_dword_to_lint; - -if (!strcasecmp(function_name->value, "DWORD_TO_DINT")) - return function_dword_to_dint; - -if (!strcasecmp(function_name->value, "DWORD_TO_DATE")) - return function_dword_to_date; - -if (!strcasecmp(function_name->value, "DWORD_TO_DT")) - return function_dword_to_dt; - -if (!strcasecmp(function_name->value, "DWORD_TO_TOD")) - return function_dword_to_tod; - -if (!strcasecmp(function_name->value, "DWORD_TO_UDINT")) - return function_dword_to_udint; - -if (!strcasecmp(function_name->value, "DWORD_TO_WORD")) - return function_dword_to_word; - -if (!strcasecmp(function_name->value, "DWORD_TO_STRING")) - return function_dword_to_string; - -if (!strcasecmp(function_name->value, "DWORD_TO_LWORD")) - return function_dword_to_lword; - -if (!strcasecmp(function_name->value, "DWORD_TO_UINT")) - return function_dword_to_uint; - -if (!strcasecmp(function_name->value, "DWORD_TO_LREAL")) - return function_dword_to_lreal; - -if (!strcasecmp(function_name->value, "DWORD_TO_BYTE")) - return function_dword_to_byte; - -if (!strcasecmp(function_name->value, "DWORD_TO_USINT")) - return function_dword_to_usint; - -if (!strcasecmp(function_name->value, "DWORD_TO_ULINT")) - return function_dword_to_ulint; - -if (!strcasecmp(function_name->value, "DWORD_TO_BOOL")) - return function_dword_to_bool; - -if (!strcasecmp(function_name->value, "DWORD_TO_TIME")) - return function_dword_to_time; - -if (!strcasecmp(function_name->value, "DWORD_TO_INT")) - return function_dword_to_int; - -if (!strcasecmp(function_name->value, "DT_TO_REAL")) - return function_dt_to_real; - -if (!strcasecmp(function_name->value, "DT_TO_SINT")) - return function_dt_to_sint; - -if (!strcasecmp(function_name->value, "DT_TO_LINT")) - return function_dt_to_lint; - -if (!strcasecmp(function_name->value, "DT_TO_DINT")) - return function_dt_to_dint; - -if (!strcasecmp(function_name->value, "DT_TO_DWORD")) - return function_dt_to_dword; - -if (!strcasecmp(function_name->value, "DT_TO_UDINT")) - return function_dt_to_udint; - -if (!strcasecmp(function_name->value, "DT_TO_WORD")) - return function_dt_to_word; - -if (!strcasecmp(function_name->value, "DT_TO_STRING")) - return function_dt_to_string; - -if (!strcasecmp(function_name->value, "DT_TO_LWORD")) - return function_dt_to_lword; - -if (!strcasecmp(function_name->value, "DT_TO_UINT")) - return function_dt_to_uint; - -if (!strcasecmp(function_name->value, "DT_TO_LREAL")) - return function_dt_to_lreal; - -if (!strcasecmp(function_name->value, "DT_TO_BYTE")) - return function_dt_to_byte; - -if (!strcasecmp(function_name->value, "DT_TO_USINT")) - return function_dt_to_usint; - -if (!strcasecmp(function_name->value, "DT_TO_ULINT")) - return function_dt_to_ulint; - -if (!strcasecmp(function_name->value, "DT_TO_INT")) - return function_dt_to_int; - -if (!strcasecmp(function_name->value, "TOD_TO_REAL")) - return function_tod_to_real; - -if (!strcasecmp(function_name->value, "TOD_TO_SINT")) - return function_tod_to_sint; - -if (!strcasecmp(function_name->value, "TOD_TO_LINT")) - return function_tod_to_lint; - -if (!strcasecmp(function_name->value, "TOD_TO_DINT")) - return function_tod_to_dint; - -if (!strcasecmp(function_name->value, "TOD_TO_DWORD")) - return function_tod_to_dword; - -if (!strcasecmp(function_name->value, "TOD_TO_UDINT")) - return function_tod_to_udint; - -if (!strcasecmp(function_name->value, "TOD_TO_WORD")) - return function_tod_to_word; - -if (!strcasecmp(function_name->value, "TOD_TO_STRING")) - return function_tod_to_string; - -if (!strcasecmp(function_name->value, "TOD_TO_LWORD")) - return function_tod_to_lword; - -if (!strcasecmp(function_name->value, "TOD_TO_UINT")) - return function_tod_to_uint; - -if (!strcasecmp(function_name->value, "TOD_TO_LREAL")) - return function_tod_to_lreal; - -if (!strcasecmp(function_name->value, "TOD_TO_BYTE")) - return function_tod_to_byte; - -if (!strcasecmp(function_name->value, "TOD_TO_USINT")) - return function_tod_to_usint; - -if (!strcasecmp(function_name->value, "TOD_TO_ULINT")) - return function_tod_to_ulint; - -if (!strcasecmp(function_name->value, "TOD_TO_INT")) - return function_tod_to_int; - -if (!strcasecmp(function_name->value, "UDINT_TO_REAL")) - return function_udint_to_real; - -if (!strcasecmp(function_name->value, "UDINT_TO_SINT")) - return function_udint_to_sint; - -if (!strcasecmp(function_name->value, "UDINT_TO_LINT")) - return function_udint_to_lint; - -if (!strcasecmp(function_name->value, "UDINT_TO_DINT")) - return function_udint_to_dint; - -if (!strcasecmp(function_name->value, "UDINT_TO_DATE")) - return function_udint_to_date; - -if (!strcasecmp(function_name->value, "UDINT_TO_DWORD")) - return function_udint_to_dword; - -if (!strcasecmp(function_name->value, "UDINT_TO_DT")) - return function_udint_to_dt; - -if (!strcasecmp(function_name->value, "UDINT_TO_TOD")) - return function_udint_to_tod; - -if (!strcasecmp(function_name->value, "UDINT_TO_WORD")) - return function_udint_to_word; - -if (!strcasecmp(function_name->value, "UDINT_TO_STRING")) - return function_udint_to_string; - -if (!strcasecmp(function_name->value, "UDINT_TO_LWORD")) - return function_udint_to_lword; - -if (!strcasecmp(function_name->value, "UDINT_TO_UINT")) - return function_udint_to_uint; - -if (!strcasecmp(function_name->value, "UDINT_TO_LREAL")) - return function_udint_to_lreal; - -if (!strcasecmp(function_name->value, "UDINT_TO_BYTE")) - return function_udint_to_byte; - -if (!strcasecmp(function_name->value, "UDINT_TO_USINT")) - return function_udint_to_usint; - -if (!strcasecmp(function_name->value, "UDINT_TO_ULINT")) - return function_udint_to_ulint; - -if (!strcasecmp(function_name->value, "UDINT_TO_BOOL")) - return function_udint_to_bool; - -if (!strcasecmp(function_name->value, "UDINT_TO_TIME")) - return function_udint_to_time; - -if (!strcasecmp(function_name->value, "UDINT_TO_INT")) - return function_udint_to_int; - -if (!strcasecmp(function_name->value, "WORD_TO_REAL")) - return function_word_to_real; - -if (!strcasecmp(function_name->value, "WORD_TO_SINT")) - return function_word_to_sint; - -if (!strcasecmp(function_name->value, "WORD_TO_LINT")) - return function_word_to_lint; - -if (!strcasecmp(function_name->value, "WORD_TO_DINT")) - return function_word_to_dint; - -if (!strcasecmp(function_name->value, "WORD_TO_DATE")) - return function_word_to_date; - -if (!strcasecmp(function_name->value, "WORD_TO_DWORD")) - return function_word_to_dword; - -if (!strcasecmp(function_name->value, "WORD_TO_DT")) - return function_word_to_dt; - -if (!strcasecmp(function_name->value, "WORD_TO_TOD")) - return function_word_to_tod; - -if (!strcasecmp(function_name->value, "WORD_TO_UDINT")) - return function_word_to_udint; - -if (!strcasecmp(function_name->value, "WORD_TO_STRING")) - return function_word_to_string; - -if (!strcasecmp(function_name->value, "WORD_TO_LWORD")) - return function_word_to_lword; - -if (!strcasecmp(function_name->value, "WORD_TO_UINT")) - return function_word_to_uint; - -if (!strcasecmp(function_name->value, "WORD_TO_LREAL")) - return function_word_to_lreal; - -if (!strcasecmp(function_name->value, "WORD_TO_BYTE")) - return function_word_to_byte; - -if (!strcasecmp(function_name->value, "WORD_TO_USINT")) - return function_word_to_usint; - -if (!strcasecmp(function_name->value, "WORD_TO_ULINT")) - return function_word_to_ulint; - -if (!strcasecmp(function_name->value, "WORD_TO_BOOL")) - return function_word_to_bool; - -if (!strcasecmp(function_name->value, "WORD_TO_TIME")) - return function_word_to_time; - -if (!strcasecmp(function_name->value, "WORD_TO_INT")) - return function_word_to_int; - -if (!strcasecmp(function_name->value, "STRING_TO_REAL")) - return function_string_to_real; - -if (!strcasecmp(function_name->value, "STRING_TO_SINT")) - return function_string_to_sint; - -if (!strcasecmp(function_name->value, "STRING_TO_LINT")) - return function_string_to_lint; - -if (!strcasecmp(function_name->value, "STRING_TO_DINT")) - return function_string_to_dint; - -if (!strcasecmp(function_name->value, "STRING_TO_DATE")) - return function_string_to_date; - -if (!strcasecmp(function_name->value, "STRING_TO_DWORD")) - return function_string_to_dword; - -if (!strcasecmp(function_name->value, "STRING_TO_DT")) - return function_string_to_dt; - -if (!strcasecmp(function_name->value, "STRING_TO_TOD")) - return function_string_to_tod; - -if (!strcasecmp(function_name->value, "STRING_TO_UDINT")) - return function_string_to_udint; - -if (!strcasecmp(function_name->value, "STRING_TO_WORD")) - return function_string_to_word; - -if (!strcasecmp(function_name->value, "STRING_TO_LWORD")) - return function_string_to_lword; - -if (!strcasecmp(function_name->value, "STRING_TO_UINT")) - return function_string_to_uint; - -if (!strcasecmp(function_name->value, "STRING_TO_LREAL")) - return function_string_to_lreal; - -if (!strcasecmp(function_name->value, "STRING_TO_BYTE")) - return function_string_to_byte; - -if (!strcasecmp(function_name->value, "STRING_TO_USINT")) - return function_string_to_usint; - -if (!strcasecmp(function_name->value, "STRING_TO_ULINT")) - return function_string_to_ulint; - -if (!strcasecmp(function_name->value, "STRING_TO_BOOL")) - return function_string_to_bool; - -if (!strcasecmp(function_name->value, "STRING_TO_TIME")) - return function_string_to_time; - -if (!strcasecmp(function_name->value, "STRING_TO_INT")) - return function_string_to_int; - -if (!strcasecmp(function_name->value, "LWORD_TO_REAL")) - return function_lword_to_real; - -if (!strcasecmp(function_name->value, "LWORD_TO_SINT")) - return function_lword_to_sint; - -if (!strcasecmp(function_name->value, "LWORD_TO_LINT")) - return function_lword_to_lint; - -if (!strcasecmp(function_name->value, "LWORD_TO_DINT")) - return function_lword_to_dint; - -if (!strcasecmp(function_name->value, "LWORD_TO_DATE")) - return function_lword_to_date; - -if (!strcasecmp(function_name->value, "LWORD_TO_DWORD")) - return function_lword_to_dword; - -if (!strcasecmp(function_name->value, "LWORD_TO_DT")) - return function_lword_to_dt; - -if (!strcasecmp(function_name->value, "LWORD_TO_TOD")) - return function_lword_to_tod; - -if (!strcasecmp(function_name->value, "LWORD_TO_UDINT")) - return function_lword_to_udint; - -if (!strcasecmp(function_name->value, "LWORD_TO_WORD")) - return function_lword_to_word; - -if (!strcasecmp(function_name->value, "LWORD_TO_STRING")) - return function_lword_to_string; - -if (!strcasecmp(function_name->value, "LWORD_TO_UINT")) - return function_lword_to_uint; - -if (!strcasecmp(function_name->value, "LWORD_TO_LREAL")) - return function_lword_to_lreal; - -if (!strcasecmp(function_name->value, "LWORD_TO_BYTE")) - return function_lword_to_byte; - -if (!strcasecmp(function_name->value, "LWORD_TO_USINT")) - return function_lword_to_usint; - -if (!strcasecmp(function_name->value, "LWORD_TO_ULINT")) - return function_lword_to_ulint; - -if (!strcasecmp(function_name->value, "LWORD_TO_BOOL")) - return function_lword_to_bool; - -if (!strcasecmp(function_name->value, "LWORD_TO_TIME")) - return function_lword_to_time; - -if (!strcasecmp(function_name->value, "LWORD_TO_INT")) - return function_lword_to_int; - -if (!strcasecmp(function_name->value, "UINT_TO_REAL")) - return function_uint_to_real; - -if (!strcasecmp(function_name->value, "UINT_TO_SINT")) - return function_uint_to_sint; - -if (!strcasecmp(function_name->value, "UINT_TO_LINT")) - return function_uint_to_lint; - -if (!strcasecmp(function_name->value, "UINT_TO_DINT")) - return function_uint_to_dint; - -if (!strcasecmp(function_name->value, "UINT_TO_DATE")) - return function_uint_to_date; - -if (!strcasecmp(function_name->value, "UINT_TO_DWORD")) - return function_uint_to_dword; - -if (!strcasecmp(function_name->value, "UINT_TO_DT")) - return function_uint_to_dt; - -if (!strcasecmp(function_name->value, "UINT_TO_TOD")) - return function_uint_to_tod; - -if (!strcasecmp(function_name->value, "UINT_TO_UDINT")) - return function_uint_to_udint; - -if (!strcasecmp(function_name->value, "UINT_TO_WORD")) - return function_uint_to_word; - -if (!strcasecmp(function_name->value, "UINT_TO_STRING")) - return function_uint_to_string; - -if (!strcasecmp(function_name->value, "UINT_TO_LWORD")) - return function_uint_to_lword; - -if (!strcasecmp(function_name->value, "UINT_TO_LREAL")) - return function_uint_to_lreal; - -if (!strcasecmp(function_name->value, "UINT_TO_BYTE")) - return function_uint_to_byte; - -if (!strcasecmp(function_name->value, "UINT_TO_USINT")) - return function_uint_to_usint; - -if (!strcasecmp(function_name->value, "UINT_TO_ULINT")) - return function_uint_to_ulint; - -if (!strcasecmp(function_name->value, "UINT_TO_BOOL")) - return function_uint_to_bool; - -if (!strcasecmp(function_name->value, "UINT_TO_TIME")) - return function_uint_to_time; - -if (!strcasecmp(function_name->value, "UINT_TO_INT")) - return function_uint_to_int; - -if (!strcasecmp(function_name->value, "LREAL_TO_REAL")) - return function_lreal_to_real; - -if (!strcasecmp(function_name->value, "LREAL_TO_SINT")) - return function_lreal_to_sint; - -if (!strcasecmp(function_name->value, "LREAL_TO_LINT")) - return function_lreal_to_lint; - -if (!strcasecmp(function_name->value, "LREAL_TO_DINT")) - return function_lreal_to_dint; - -if (!strcasecmp(function_name->value, "LREAL_TO_DATE")) - return function_lreal_to_date; - -if (!strcasecmp(function_name->value, "LREAL_TO_DWORD")) - return function_lreal_to_dword; - -if (!strcasecmp(function_name->value, "LREAL_TO_DT")) - return function_lreal_to_dt; - -if (!strcasecmp(function_name->value, "LREAL_TO_TOD")) - return function_lreal_to_tod; - -if (!strcasecmp(function_name->value, "LREAL_TO_UDINT")) - return function_lreal_to_udint; - -if (!strcasecmp(function_name->value, "LREAL_TO_WORD")) - return function_lreal_to_word; - -if (!strcasecmp(function_name->value, "LREAL_TO_STRING")) - return function_lreal_to_string; - -if (!strcasecmp(function_name->value, "LREAL_TO_LWORD")) - return function_lreal_to_lword; - -if (!strcasecmp(function_name->value, "LREAL_TO_UINT")) - return function_lreal_to_uint; - -if (!strcasecmp(function_name->value, "LREAL_TO_BYTE")) - return function_lreal_to_byte; - -if (!strcasecmp(function_name->value, "LREAL_TO_USINT")) - return function_lreal_to_usint; - -if (!strcasecmp(function_name->value, "LREAL_TO_ULINT")) - return function_lreal_to_ulint; - -if (!strcasecmp(function_name->value, "LREAL_TO_BOOL")) - return function_lreal_to_bool; - -if (!strcasecmp(function_name->value, "LREAL_TO_TIME")) - return function_lreal_to_time; - -if (!strcasecmp(function_name->value, "LREAL_TO_INT")) - return function_lreal_to_int; - -if (!strcasecmp(function_name->value, "BYTE_TO_REAL")) - return function_byte_to_real; - -if (!strcasecmp(function_name->value, "BYTE_TO_SINT")) - return function_byte_to_sint; - -if (!strcasecmp(function_name->value, "BYTE_TO_LINT")) - return function_byte_to_lint; - -if (!strcasecmp(function_name->value, "BYTE_TO_DINT")) - return function_byte_to_dint; - -if (!strcasecmp(function_name->value, "BYTE_TO_DATE")) - return function_byte_to_date; - -if (!strcasecmp(function_name->value, "BYTE_TO_DWORD")) - return function_byte_to_dword; - -if (!strcasecmp(function_name->value, "BYTE_TO_DT")) - return function_byte_to_dt; - -if (!strcasecmp(function_name->value, "BYTE_TO_TOD")) - return function_byte_to_tod; - -if (!strcasecmp(function_name->value, "BYTE_TO_UDINT")) - return function_byte_to_udint; - -if (!strcasecmp(function_name->value, "BYTE_TO_WORD")) - return function_byte_to_word; - -if (!strcasecmp(function_name->value, "BYTE_TO_STRING")) - return function_byte_to_string; - -if (!strcasecmp(function_name->value, "BYTE_TO_LWORD")) - return function_byte_to_lword; - -if (!strcasecmp(function_name->value, "BYTE_TO_UINT")) - return function_byte_to_uint; - -if (!strcasecmp(function_name->value, "BYTE_TO_LREAL")) - return function_byte_to_lreal; - -if (!strcasecmp(function_name->value, "BYTE_TO_USINT")) - return function_byte_to_usint; - -if (!strcasecmp(function_name->value, "BYTE_TO_ULINT")) - return function_byte_to_ulint; - -if (!strcasecmp(function_name->value, "BYTE_TO_BOOL")) - return function_byte_to_bool; - -if (!strcasecmp(function_name->value, "BYTE_TO_TIME")) - return function_byte_to_time; - -if (!strcasecmp(function_name->value, "BYTE_TO_INT")) - return function_byte_to_int; - -if (!strcasecmp(function_name->value, "USINT_TO_REAL")) - return function_usint_to_real; - -if (!strcasecmp(function_name->value, "USINT_TO_SINT")) - return function_usint_to_sint; - -if (!strcasecmp(function_name->value, "USINT_TO_LINT")) - return function_usint_to_lint; - -if (!strcasecmp(function_name->value, "USINT_TO_DINT")) - return function_usint_to_dint; - -if (!strcasecmp(function_name->value, "USINT_TO_DATE")) - return function_usint_to_date; - -if (!strcasecmp(function_name->value, "USINT_TO_DWORD")) - return function_usint_to_dword; - -if (!strcasecmp(function_name->value, "USINT_TO_DT")) - return function_usint_to_dt; - -if (!strcasecmp(function_name->value, "USINT_TO_TOD")) - return function_usint_to_tod; - -if (!strcasecmp(function_name->value, "USINT_TO_UDINT")) - return function_usint_to_udint; - -if (!strcasecmp(function_name->value, "USINT_TO_WORD")) - return function_usint_to_word; - -if (!strcasecmp(function_name->value, "USINT_TO_STRING")) - return function_usint_to_string; - -if (!strcasecmp(function_name->value, "USINT_TO_LWORD")) - return function_usint_to_lword; - -if (!strcasecmp(function_name->value, "USINT_TO_UINT")) - return function_usint_to_uint; - -if (!strcasecmp(function_name->value, "USINT_TO_LREAL")) - return function_usint_to_lreal; - -if (!strcasecmp(function_name->value, "USINT_TO_BYTE")) - return function_usint_to_byte; - -if (!strcasecmp(function_name->value, "USINT_TO_ULINT")) - return function_usint_to_ulint; - -if (!strcasecmp(function_name->value, "USINT_TO_BOOL")) - return function_usint_to_bool; - -if (!strcasecmp(function_name->value, "USINT_TO_TIME")) - return function_usint_to_time; - -if (!strcasecmp(function_name->value, "USINT_TO_INT")) - return function_usint_to_int; - -if (!strcasecmp(function_name->value, "ULINT_TO_REAL")) - return function_ulint_to_real; - -if (!strcasecmp(function_name->value, "ULINT_TO_SINT")) - return function_ulint_to_sint; - -if (!strcasecmp(function_name->value, "ULINT_TO_LINT")) - return function_ulint_to_lint; - -if (!strcasecmp(function_name->value, "ULINT_TO_DINT")) - return function_ulint_to_dint; - -if (!strcasecmp(function_name->value, "ULINT_TO_DATE")) - return function_ulint_to_date; - -if (!strcasecmp(function_name->value, "ULINT_TO_DWORD")) - return function_ulint_to_dword; - -if (!strcasecmp(function_name->value, "ULINT_TO_DT")) - return function_ulint_to_dt; - -if (!strcasecmp(function_name->value, "ULINT_TO_TOD")) - return function_ulint_to_tod; - -if (!strcasecmp(function_name->value, "ULINT_TO_UDINT")) - return function_ulint_to_udint; - -if (!strcasecmp(function_name->value, "ULINT_TO_WORD")) - return function_ulint_to_word; - -if (!strcasecmp(function_name->value, "ULINT_TO_STRING")) - return function_ulint_to_string; - -if (!strcasecmp(function_name->value, "ULINT_TO_LWORD")) - return function_ulint_to_lword; - -if (!strcasecmp(function_name->value, "ULINT_TO_UINT")) - return function_ulint_to_uint; - -if (!strcasecmp(function_name->value, "ULINT_TO_LREAL")) - return function_ulint_to_lreal; - -if (!strcasecmp(function_name->value, "ULINT_TO_BYTE")) - return function_ulint_to_byte; - -if (!strcasecmp(function_name->value, "ULINT_TO_USINT")) - return function_ulint_to_usint; - -if (!strcasecmp(function_name->value, "ULINT_TO_BOOL")) - return function_ulint_to_bool; - -if (!strcasecmp(function_name->value, "ULINT_TO_TIME")) - return function_ulint_to_time; - -if (!strcasecmp(function_name->value, "ULINT_TO_INT")) - return function_ulint_to_int; - -if (!strcasecmp(function_name->value, "BOOL_TO_REAL")) - return function_bool_to_real; - -if (!strcasecmp(function_name->value, "BOOL_TO_SINT")) - return function_bool_to_sint; - -if (!strcasecmp(function_name->value, "BOOL_TO_LINT")) - return function_bool_to_lint; - -if (!strcasecmp(function_name->value, "BOOL_TO_DINT")) - return function_bool_to_dint; - -if (!strcasecmp(function_name->value, "BOOL_TO_DATE")) - return function_bool_to_date; - -if (!strcasecmp(function_name->value, "BOOL_TO_DWORD")) - return function_bool_to_dword; - -if (!strcasecmp(function_name->value, "BOOL_TO_DT")) - return function_bool_to_dt; - -if (!strcasecmp(function_name->value, "BOOL_TO_TOD")) - return function_bool_to_tod; - -if (!strcasecmp(function_name->value, "BOOL_TO_UDINT")) - return function_bool_to_udint; - -if (!strcasecmp(function_name->value, "BOOL_TO_WORD")) - return function_bool_to_word; - -if (!strcasecmp(function_name->value, "BOOL_TO_STRING")) - return function_bool_to_string; - -if (!strcasecmp(function_name->value, "BOOL_TO_LWORD")) - return function_bool_to_lword; - -if (!strcasecmp(function_name->value, "BOOL_TO_UINT")) - return function_bool_to_uint; - -if (!strcasecmp(function_name->value, "BOOL_TO_LREAL")) - return function_bool_to_lreal; - -if (!strcasecmp(function_name->value, "BOOL_TO_BYTE")) - return function_bool_to_byte; - -if (!strcasecmp(function_name->value, "BOOL_TO_USINT")) - return function_bool_to_usint; - -if (!strcasecmp(function_name->value, "BOOL_TO_ULINT")) - return function_bool_to_ulint; - -if (!strcasecmp(function_name->value, "BOOL_TO_TIME")) - return function_bool_to_time; - -if (!strcasecmp(function_name->value, "BOOL_TO_INT")) - return function_bool_to_int; - -if (!strcasecmp(function_name->value, "TIME_TO_REAL")) - return function_time_to_real; - -if (!strcasecmp(function_name->value, "TIME_TO_SINT")) - return function_time_to_sint; - -if (!strcasecmp(function_name->value, "TIME_TO_LINT")) - return function_time_to_lint; - -if (!strcasecmp(function_name->value, "TIME_TO_DINT")) - return function_time_to_dint; - -if (!strcasecmp(function_name->value, "TIME_TO_DWORD")) - return function_time_to_dword; - -if (!strcasecmp(function_name->value, "TIME_TO_UDINT")) - return function_time_to_udint; - -if (!strcasecmp(function_name->value, "TIME_TO_WORD")) - return function_time_to_word; - -if (!strcasecmp(function_name->value, "TIME_TO_STRING")) - return function_time_to_string; - -if (!strcasecmp(function_name->value, "TIME_TO_LWORD")) - return function_time_to_lword; - -if (!strcasecmp(function_name->value, "TIME_TO_UINT")) - return function_time_to_uint; - -if (!strcasecmp(function_name->value, "TIME_TO_LREAL")) - return function_time_to_lreal; - -if (!strcasecmp(function_name->value, "TIME_TO_BYTE")) - return function_time_to_byte; - -if (!strcasecmp(function_name->value, "TIME_TO_USINT")) - return function_time_to_usint; - -if (!strcasecmp(function_name->value, "TIME_TO_ULINT")) - return function_time_to_ulint; - -if (!strcasecmp(function_name->value, "TIME_TO_INT")) - return function_time_to_int; - -if (!strcasecmp(function_name->value, "INT_TO_REAL")) - return function_int_to_real; - -if (!strcasecmp(function_name->value, "INT_TO_SINT")) - return function_int_to_sint; - -if (!strcasecmp(function_name->value, "INT_TO_LINT")) - return function_int_to_lint; - -if (!strcasecmp(function_name->value, "INT_TO_DINT")) - return function_int_to_dint; - -if (!strcasecmp(function_name->value, "INT_TO_DATE")) - return function_int_to_date; - -if (!strcasecmp(function_name->value, "INT_TO_DWORD")) - return function_int_to_dword; - -if (!strcasecmp(function_name->value, "INT_TO_DT")) - return function_int_to_dt; - -if (!strcasecmp(function_name->value, "INT_TO_TOD")) - return function_int_to_tod; - -if (!strcasecmp(function_name->value, "INT_TO_UDINT")) - return function_int_to_udint; - -if (!strcasecmp(function_name->value, "INT_TO_WORD")) - return function_int_to_word; - -if (!strcasecmp(function_name->value, "INT_TO_STRING")) - return function_int_to_string; - -if (!strcasecmp(function_name->value, "INT_TO_LWORD")) - return function_int_to_lword; - -if (!strcasecmp(function_name->value, "INT_TO_UINT")) - return function_int_to_uint; - -if (!strcasecmp(function_name->value, "INT_TO_LREAL")) - return function_int_to_lreal; - -if (!strcasecmp(function_name->value, "INT_TO_BYTE")) - return function_int_to_byte; - -if (!strcasecmp(function_name->value, "INT_TO_USINT")) - return function_int_to_usint; - -if (!strcasecmp(function_name->value, "INT_TO_ULINT")) - return function_int_to_ulint; - -if (!strcasecmp(function_name->value, "INT_TO_BOOL")) - return function_int_to_bool; - -if (!strcasecmp(function_name->value, "INT_TO_TIME")) - return function_int_to_time; - -if (!strcasecmp(function_name->value, "TRUNC")) - return function_trunc; - -if (!strcasecmp(function_name->value, "BCD_TO_UDINT")) - return function_bcd_to_udint; - -if (!strcasecmp(function_name->value, "BCD_TO_UINT")) - return function_bcd_to_uint; - -if (!strcasecmp(function_name->value, "BCD_TO_ULINT")) - return function_bcd_to_ulint; - -if (!strcasecmp(function_name->value, "BCD_TO_USINT")) - return function_bcd_to_usint; - -if (!strcasecmp(function_name->value, "UDINT_TO_BCD")) - return function_udint_to_bcd; - -if (!strcasecmp(function_name->value, "UINT_TO_BCD")) - return function_uint_to_bcd; - -if (!strcasecmp(function_name->value, "USINT_TO_BCD")) - return function_usint_to_bcd; - -if (!strcasecmp(function_name->value, "ULINT_TO_BCD")) - return function_ulint_to_bcd; - -if (!strcasecmp(function_name->value, "DATE_AND_TIME_TO_TIME_OF_DAY")) - return function_date_and_time_to_time_of_day; - -if (!strcasecmp(function_name->value, "DATE_AND_TIME_TO_DATE")) - return function_date_and_time_to_date; - -if (!strcasecmp(function_name->value, "ABS")) - return function_abs; - -if (!strcasecmp(function_name->value, "SQRT")) - return function_sqrt; - -if (!strcasecmp(function_name->value, "LN")) - return function_ln; - -if (!strcasecmp(function_name->value, "LOG")) - return function_log; - -if (!strcasecmp(function_name->value, "EXP")) - return function_exp; - -if (!strcasecmp(function_name->value, "SIN")) - return function_sin; - -if (!strcasecmp(function_name->value, "COS")) - return function_cos; - -if (!strcasecmp(function_name->value, "TAN")) - return function_tan; - -if (!strcasecmp(function_name->value, "ASIN")) - return function_asin; - -if (!strcasecmp(function_name->value, "ACOS")) - return function_acos; - -if (!strcasecmp(function_name->value, "ATAN")) - return function_atan; - -if (!strcasecmp(function_name->value, "ADD")) - return function_add; - -if (!strcasecmp(function_name->value, "MUL")) - return function_mul; - -if (!strcasecmp(function_name->value, "SUB")) - return function_sub; - -if (!strcasecmp(function_name->value, "DIV")) - return function_div; - -if (!strcasecmp(function_name->value, "MOD")) - return function_mod; - -if (!strcasecmp(function_name->value, "EXPT")) - return function_expt; - -if (!strcasecmp(function_name->value, "MOVE")) - return function_move; - -if (!strcasecmp(function_name->value, "ADD_TIME")) - return function_add_time; - -if (!strcasecmp(function_name->value, "ADD_TOD_TIME")) - return function_add_tod_time; - -if (!strcasecmp(function_name->value, "ADD_DT_TIME")) - return function_add_dt_time; - -if (!strcasecmp(function_name->value, "MULTIME")) - return function_multime; - -if (!strcasecmp(function_name->value, "SUB_TIME")) - return function_sub_time; - -if (!strcasecmp(function_name->value, "SUB_DATE_DATE")) - return function_sub_date_date; - -if (!strcasecmp(function_name->value, "SUB_TOD_TIME")) - return function_sub_tod_time; - -if (!strcasecmp(function_name->value, "SUB_TOD_TOD")) - return function_sub_tod_tod; - -if (!strcasecmp(function_name->value, "SUB_DT_TIME")) - return function_sub_dt_time; - -if (!strcasecmp(function_name->value, "DIVTIME")) - return function_divtime; - -if (!strcasecmp(function_name->value, "SHL")) - return function_shl; - -if (!strcasecmp(function_name->value, "SHR")) - return function_shr; - -if (!strcasecmp(function_name->value, "ROR")) - return function_ror; - -if (!strcasecmp(function_name->value, "ROL")) - return function_rol; - -if (!strcasecmp(function_name->value, "AND")) - return function_and; - -if (!strcasecmp(function_name->value, "OR")) - return function_or; - -if (!strcasecmp(function_name->value, "XOR")) - return function_xor; - -if (!strcasecmp(function_name->value, "NOT")) - return function_not; - -if (!strcasecmp(function_name->value, "SEL")) - return function_sel; - -if (!strcasecmp(function_name->value, "MAX")) - return function_max; - -if (!strcasecmp(function_name->value, "MIN")) - return function_min; - -if (!strcasecmp(function_name->value, "LIMIT")) - return function_limit; - -if (!strcasecmp(function_name->value, "MUX")) - return function_mux; - -if (!strcasecmp(function_name->value, "GT")) - return function_gt; - -if (!strcasecmp(function_name->value, "GE")) - return function_ge; - -if (!strcasecmp(function_name->value, "EQ")) - return function_eq; - -if (!strcasecmp(function_name->value, "LT")) - return function_lt; - -if (!strcasecmp(function_name->value, "LE")) - return function_le; - -if (!strcasecmp(function_name->value, "NE")) - return function_ne; - -if (!strcasecmp(function_name->value, "LEN")) - return function_len; - -if (!strcasecmp(function_name->value, "LEFT")) - return function_left; - -if (!strcasecmp(function_name->value, "RIGHT")) - return function_right; - -if (!strcasecmp(function_name->value, "MID")) - return function_mid; - -if (!strcasecmp(function_name->value, "CONCAT")) - return function_concat; - -if (!strcasecmp(function_name->value, "CONCAT_DAT_TOD")) - return function_concat_dat_tod; - -if (!strcasecmp(function_name->value, "INSERT")) - return function_insert; - -if (!strcasecmp(function_name->value, "DELETE")) - return function_delete; - -if (!strcasecmp(function_name->value, "REPLACE")) - return function_replace; - -if (!strcasecmp(function_name->value, "FIND")) - return function_find; - - else return function_none; -} - diff -r 27063736913f -r b05f63d9d0fa absyntax_utils/search_base_type.cc --- a/absyntax_utils/search_base_type.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/absyntax_utils/search_base_type.cc Wed Dec 10 11:57:43 2014 +0000 @@ -131,8 +131,9 @@ return NULL; } -void *search_base_type_c::visit( identifier_c *type_name) {return handle_datatype_identifier(type_name);} // still needed to handle FB and program datatypes! -void *search_base_type_c::visit(derived_datatype_identifier_c *type_name) {return handle_datatype_identifier(type_name);} +void *search_base_type_c::visit( identifier_c *type_name) {return handle_datatype_identifier(type_name);} +void *search_base_type_c::visit(derived_datatype_identifier_c *type_name) {return handle_datatype_identifier(type_name);} +void *search_base_type_c::visit( poutype_identifier_c *type_name) {return handle_datatype_identifier(type_name);} /*********************/ diff -r 27063736913f -r b05f63d9d0fa absyntax_utils/search_base_type.hh --- a/absyntax_utils/search_base_type.hh Sat Nov 22 19:30:47 2014 +0000 +++ b/absyntax_utils/search_base_type.hh Wed Dec 10 11:57:43 2014 +0000 @@ -91,7 +91,8 @@ /*******************************************/ void *visit( identifier_c *type_name); void *visit(derived_datatype_identifier_c *type_name); - + void *visit( poutype_identifier_c *type_name); + /*********************/ /* B 1.2 - Constants */ /*********************/ diff -r 27063736913f -r b05f63d9d0fa absyntax_utils/spec_init_separator.cc --- a/absyntax_utils/spec_init_separator.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/absyntax_utils/spec_init_separator.cc Wed Dec 10 11:57:43 2014 +0000 @@ -74,11 +74,12 @@ /* B 1.1 - Letters, digits and identifiers */ /*******************************************/ // SYM_TOKEN(identifier_c) -/* visitor for identifier_c is necessary because spec_init_sperator_c will be called to analyse PROGRAM identfiers, - * which are still transformed into identfier_c, instead of a derived_datatype_identifier_c - */ -void *spec_init_sperator_c::visit( identifier_c *symbol) { - TRACE("spec_init_sperator_c::identifier_c"); +/* visitor for identifier_c should no longer be necessary. All references to derived datatypes are now stored in then */ +/* AST using either poutype_identifier_c or derived_datatype_identifier_c */ +void *spec_init_sperator_c::visit( identifier_c *symbol) { ERROR; return NULL;} /* should never occur */ + +void *spec_init_sperator_c::visit( poutype_identifier_c *symbol) { + TRACE("spec_init_sperator_c::poutype_identifier_c"); switch (search_what) { /* if we ever get called sith a simple identifier_c, then it must be a previously declared type... */ case search_spec: return symbol; @@ -90,7 +91,7 @@ void *spec_init_sperator_c::visit(derived_datatype_identifier_c *symbol) { - TRACE("spec_init_sperator_c::identifier_c"); + TRACE("spec_init_sperator_c::derived_datatype_identifier_c"); switch (search_what) { /* if we ever get called sith a simple identifier_c, then it must be a previously declared type... */ case search_spec: return symbol; @@ -226,6 +227,7 @@ } ERROR; /* should never occur */ return NULL; + } diff -r 27063736913f -r b05f63d9d0fa absyntax_utils/spec_init_separator.hh --- a/absyntax_utils/spec_init_separator.hh Sat Nov 22 19:30:47 2014 +0000 +++ b/absyntax_utils/spec_init_separator.hh Wed Dec 10 11:57:43 2014 +0000 @@ -67,7 +67,8 @@ // SYM_TOKEN(identifier_c) void *visit( identifier_c *symbol); void *visit(derived_datatype_identifier_c *symbol); - + void *visit( poutype_identifier_c *symbol); + /********************************/ /* B 1.3.3 - Derived data types */ diff -r 27063736913f -r b05f63d9d0fa absyntax_utils/type_initial_value.cc --- a/absyntax_utils/type_initial_value.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/absyntax_utils/type_initial_value.cc Wed Dec 10 11:57:43 2014 +0000 @@ -110,48 +110,29 @@ void *type_initial_value_c::handle_type_spec(symbol_c *base_type_name, symbol_c *type_spec_init) { if (type_spec_init != NULL) return type_spec_init; - /* no initial value specified, so we return - * the initial value of the type this type is based on... - */ + /* no initial value specified, so we return the initial value of the type this type is based on... */ return base_type_name->accept(*this); } -/* visitor for identifier_c is necessary because type_initial_value_c will be called to analyse PROGRAM identfiers, - * which are still transformed into identfier_c, instead of a derived_datatype_identifier_c - */ -void *type_initial_value_c::visit( identifier_c *type_name) { +void *type_initial_value_c::handle_type_name(symbol_c *type_name) { /* look up the type declaration... */ symbol_c *type_decl = type_symtable.find_value(type_name); - if (type_decl == type_symtable.end_value()) /* Type declaration not found!! */ - /* NOTE: Variables declared out of function block 'data types', - * for eg: VAR timer: TON; END_VAR - * do not have a default value, so (TON) will never be found in the - * type symbol table. This means we cannot simply consider this - * an error and abort, but must rather return a NULL. + /* NOTE: Variables declared out of function block 'data types',for eg: VAR timer: TON; END_VAR + * do not have a default value, so (TON) will never be found in the type symbol table. This means + * we cannot simply consider this an error and abort, but must rather return a NULL. */ - return NULL; + if (type_decl == type_symtable.end_value()) return NULL; return type_decl->accept(*this); } - -void *type_initial_value_c::visit(derived_datatype_identifier_c *type_name) { - /* look up the type declaration... */ - symbol_c *type_decl = type_symtable.find_value(type_name); - if (type_decl == type_symtable.end_value()) - /* Type declaration not found!! */ - /* NOTE: Variables declared out of function block 'data types', - * for eg: VAR timer: TON; END_VAR - * do not have a default value, so (TON) will never be found in the - * type symbol table. This means we cannot simply consider this - * an error and abort, but must rather return a NULL. - */ - return NULL; - - return type_decl->accept(*this); -} +/* visitor for identifier_c should no longer be necessary. All references to derived datatypes are now stored in then */ +/* AST using either poutype_identifier_c or derived_datatype_identifier_c. In principe, the following should not be necesasry */ +void *type_initial_value_c::visit( identifier_c *symbol) {return handle_type_name(symbol);} /* should never occur */ +void *type_initial_value_c::visit( poutype_identifier_c *symbol) {return handle_type_name(symbol);} /* in practice it might never get called, as FB, Functions and Programs do not have initial value */ +void *type_initial_value_c::visit(derived_datatype_identifier_c *symbol) {return handle_type_name(symbol);} /***********************************/ /* B 1.3.1 - Elementary Data Types */ diff -r 27063736913f -r b05f63d9d0fa absyntax_utils/type_initial_value.hh --- a/absyntax_utils/type_initial_value.hh Sat Nov 22 19:30:47 2014 +0000 +++ b/absyntax_utils/type_initial_value.hh Wed Dec 10 11:57:43 2014 +0000 @@ -84,10 +84,12 @@ static type_initial_value_c *_instance; static type_initial_value_c *instance(void); void *handle_type_spec(symbol_c *base_type_name, symbol_c *type_spec_init); + void *handle_type_name(symbol_c *type_name); private: - void *visit( identifier_c *type_name); - void *visit(derived_datatype_identifier_c *type_name); + void *visit( identifier_c *symbol); + void *visit(derived_datatype_identifier_c *symbol); + void *visit( poutype_identifier_c *symbol); /***********************************/ /* B 1.3.1 - Elementary Data Types */ diff -r 27063736913f -r b05f63d9d0fa main.cc --- a/main.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/main.cc Wed Dec 10 11:57:43 2014 +0000 @@ -113,6 +113,7 @@ printf(" -h : show this help message\n"); printf(" -v : print version number\n"); printf(" -f : display full token location on error messages\n"); + printf(" -p : allow use of forward references (a non-standard extension?)\n"); printf(" -l : use a relaxed datatype equivalence model (a non-standard extension?)\n"); printf(" -s : allow use of safe datatypes (SAFEBOOL, etc.) (defined in PLCOpen Safety)\n"); // PLCopen TC5 "Safety Software Technical Specification - Part 1" v1.0 printf(" -r : allow use of references (REF_TO, REF, ^, NULL) (an IEC 61131-3 v3 feature)\n"); @@ -133,12 +134,13 @@ int main(int argc, char **argv) { - symbol_c *tree_root; + symbol_c *tree_root, *ordered_tree_root; char * builddir = NULL; int optres, errflg = 0; int path_len; /* Default values for the command line options... */ + runtime_options.pre_parsing = false; /* allow use of forward references (run pre-parsing phase before the definitive parsing phase that builds the AST) */ runtime_options.safe_extensions = false; /* allow use of SAFExxx datatypes */ runtime_options.full_token_loc = false; /* error messages specify full token location */ runtime_options.conversion_functions = false; /* Create a conversion function for derived datatype */ @@ -153,7 +155,7 @@ /******************************************/ /* Parse command line options... */ /******************************************/ - while ((optres = getopt(argc, argv, ":nhvflsrRcI:T:O:")) != -1) { + while ((optres = getopt(argc, argv, ":nhvfplsrRcI:T:O:")) != -1) { switch(optres) { case 'h': printusage(argv[0]); @@ -164,7 +166,9 @@ case 'l': runtime_options.relaxed_datatype_model = true; break; - + case 'p': + runtime_options.pre_parsing = true; + break; case 'f': runtime_options.full_token_loc = true; break; @@ -248,11 +252,11 @@ //add_en_eno_param_decl_c::add_to(tree_root); /* Do semantic verification of code */ - if (stage3(tree_root) < 0) + if (stage3(tree_root, &ordered_tree_root) < 0) return EXIT_FAILURE; /* 3rd Pass */ - if (stage4(tree_root, builddir) < 0) + if (stage4(ordered_tree_root, builddir) < 0) return EXIT_FAILURE; /* 4th Pass */ diff -r 27063736913f -r b05f63d9d0fa main.hh --- a/main.hh Sat Nov 22 19:30:47 2014 +0000 +++ b/main.hh Wed Dec 10 11:57:43 2014 +0000 @@ -40,6 +40,7 @@ typedef struct { /* options specific to stage1_2 */ + bool pre_parsing; /* Support forward references (Run a pre-parsing phase before the defintive parsing phase that builds the AST) */ bool safe_extensions; /* support SAFE_* datatypes defined in PLCOpen TC5 "Safety Software Technical Specification - Part 1" v1.0 */ bool full_token_loc; /* error messages specify full token location */ bool conversion_functions; /* Create a conversion function for derived datatype */ diff -r 27063736913f -r b05f63d9d0fa stage1_2/create_enumtype_conversion_functions.cc --- a/stage1_2/create_enumtype_conversion_functions.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/stage1_2/create_enumtype_conversion_functions.cc Wed Dec 10 11:57:43 2014 +0000 @@ -76,11 +76,12 @@ return singleton->text; } - -void *create_enumtype_conversion_functions_c::visit(identifier_c *symbol) { - currentToken = symbol->value; - return NULL; -} +/* As the name of derived datatypes and POUs are still stored as identifiers in the respective datatype and POU declaration, */ +/* only the indintifier_c visitor should be necessary! */ +void *create_enumtype_conversion_functions_c::visit( identifier_c *symbol) {currentToken = symbol->value; return NULL;} +void *create_enumtype_conversion_functions_c::visit( poutype_identifier_c *symbol) {ERROR; return NULL;} +void *create_enumtype_conversion_functions_c::visit(derived_datatype_identifier_c *symbol) {ERROR; return NULL;} + /**********************/ /* B 1.3 - Data types */ diff -r 27063736913f -r b05f63d9d0fa stage1_2/create_enumtype_conversion_functions.hh --- a/stage1_2/create_enumtype_conversion_functions.hh Sat Nov 22 19:30:47 2014 +0000 +++ b/stage1_2/create_enumtype_conversion_functions.hh Wed Dec 10 11:57:43 2014 +0000 @@ -55,7 +55,10 @@ virtual ~create_enumtype_conversion_functions_c(void); static std::string &get_declaration(symbol_c *symbol); - void *visit(identifier_c *symbol); + void *visit( identifier_c *symbol); + void *visit( poutype_identifier_c *symbol); + void *visit(derived_datatype_identifier_c *symbol); + /**********************/ /* B 1.3 - Data types */ /**********************/ diff -r 27063736913f -r b05f63d9d0fa stage1_2/iec_bison.yy --- a/stage1_2/iec_bison.yy Sat Nov 22 19:30:47 2014 +0000 +++ b/stage1_2/iec_bison.yy Wed Dec 10 11:57:43 2014 +0000 @@ -224,7 +224,10 @@ /* 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); +identifier_c *il_operator_c_2_identifier_c (symbol_c *il_operator); +/* Convert an il_operator_c into an poutype_identifier_c */ +poutype_identifier_c *il_operator_c_2_poutype_identifier_c(symbol_c *il_operator); + /* return if current token is a syntax element */ /* ERROR_CHECK_BEGIN */ @@ -1143,6 +1146,7 @@ %type prev_declared_resource_name %token prev_declared_resource_name_token +%type prev_declared_configuration_name %token prev_declared_configuration_name_token // %type prev_declared_task_name @@ -1590,37 +1594,49 @@ | 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_ref_type_name /* defined in IEC 61131-3 v3 */ -| prev_declared_derived_function_name -| prev_declared_derived_function_block_name -| prev_declared_program_type_name + /* ref_type_name is defined in IEC 61131-3 v3 */ +| prev_declared_ref_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! +| prev_declared_simple_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! +| prev_declared_subrange_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! +| prev_declared_enumerated_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! +| prev_declared_array_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! +| prev_declared_structure_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! +| prev_declared_string_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! +| prev_declared_derived_function_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the poutype_identifier_c into an identifier_c, as it will be taking the place of an identifier! +| prev_declared_derived_function_block_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the poutype_identifier_c into an identifier_c, as it will be taking the place of an identifier! +| prev_declared_program_type_name {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$));}; // change the poutype_identifier_c into an identifier_c, as it will be taking the place of an identifier! /**/ | 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 derived_datatype_identifier_c($1, locloc(@$));}; -prev_declared_subrange_type_name : prev_declared_subrange_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +/* NOTE: Notice that the symbol classes: + * - derived_datatype_identifier_c + * - poutype_identifier_c + * are only inserted into the AST when referencing a derived dataype or a POU + * (e.g. when declaring a variable, making a function call, instantiating a program in a resource, + * or delaring a derived datatype that derives from another previously delcared datatype). + * + * In the declaration of the datatype or POU itself, the name of the datatype or POU will be stored + * inside an identifier_c instead!! + */ +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 derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_subrange_type_name: prev_declared_subrange_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; prev_declared_enumerated_type_name: prev_declared_enumerated_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; -prev_declared_array_type_name : prev_declared_array_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; -prev_declared_structure_type_name : prev_declared_structure_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; -prev_declared_string_type_name : prev_declared_string_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; -prev_declared_ref_type_name : prev_declared_ref_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; /* defined in IEC 61131-3 v3 */ - -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(@$));}; +prev_declared_array_type_name: prev_declared_array_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_structure_type_name: prev_declared_structure_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_string_type_name: prev_declared_string_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_ref_type_name: prev_declared_ref_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; /* defined in IEC 61131-3 v3 */ + +prev_declared_derived_function_name: prev_declared_derived_function_name_token {$$ = new poutype_identifier_c($1, locloc(@$));}; +prev_declared_derived_function_block_name: prev_declared_derived_function_block_name_token {$$ = new poutype_identifier_c($1, locloc(@$));}; +prev_declared_program_type_name: prev_declared_program_type_name_token {$$ = new poutype_identifier_c($1, locloc(@$));}; +/* NOTE: The poutype_identifier_c was introduced to allow the implementation of remove_forward_dependencies_c */ + @@ -2607,12 +2623,30 @@ simple_type_declaration: /* simple_type_name ':' simple_spec_init */ /* To understand why simple_spec_init was brocken up into its consituent components in the following rules, please see note in the definition of 'enumerated_type_declaration'. */ +/* PRE_PARSING or SINGLE_PHASE_PARSING */ +/* The following rules will be run either by: + * - the pre_parsing phase of two phase parsing (when preparsing command line option is chosen). + * - the standard single phase parser (when preparsing command line option is not chosen). + */ identifier ':' simple_specification {library_element_symtable.insert($1, prev_declared_simple_type_name_token);} + {if (!get_preparse_state()) $$ = new simple_type_declaration_c($1, $3, locloc(@$));} +| identifier ':' elementary_type_name {library_element_symtable.insert($1, prev_declared_simple_type_name_token);} ASSIGN constant + {if (!get_preparse_state()) $$ = new simple_type_declaration_c($1, new simple_spec_init_c($3, $6, locf(@3), locl(@5)), locloc(@$));} +| identifier ':' prev_declared_simple_type_name {library_element_symtable.insert($1, prev_declared_simple_type_name_token);} ASSIGN constant + {if (!get_preparse_state()) $$ = new simple_type_declaration_c($1, new simple_spec_init_c($3, $6, locf(@3), locl(@5)), locloc(@$));} +/* POST_PARSING */ +/* These rules will be run after the preparser phase of two phase parsing has finished (only gets to execute if preparsing command line option is chosen). */ +| prev_declared_simple_type_name ':' simple_spec_init + {$$ = new simple_type_declaration_c(new identifier_c(((token_c *)$1)->value, locloc(@1)), $3, locloc(@$));} // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! +/* These three rules can now be safely replaced by the original rule abvoe!! */ +/* +| prev_declared_simple_type_name ':' simple_specification {$$ = new simple_type_declaration_c($1, $3, locloc(@$));} -| identifier ':' elementary_type_name {library_element_symtable.insert($1, prev_declared_simple_type_name_token);} ASSIGN constant - {$$ = new simple_type_declaration_c($1, new simple_spec_init_c($3, $6, locf(@3), locl(@6)), locloc(@$));} -| identifier ':' prev_declared_simple_type_name {library_element_symtable.insert($1, prev_declared_simple_type_name_token);} ASSIGN constant - {$$ = new simple_type_declaration_c($1, new simple_spec_init_c($3, $6, locf(@3), locl(@6)), locloc(@$));} +| prev_declared_simple_type_name ':' elementary_type_name ASSIGN constant + {$$ = new simple_type_declaration_c($1, new simple_spec_init_c($3, $5, locf(@3), locl(@5)), locloc(@$));} +| prev_declared_simple_type_name ':' prev_declared_simple_type_name ASSIGN constant + {$$ = new simple_type_declaration_c($1, new simple_spec_init_c($3, $5, locf(@3), locl(@5)), locloc(@$));} +*/ /* ERROR_CHECK_BEGIN */ | error ':' simple_spec_init {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for data type declaration.");yyerrok;} @@ -2685,10 +2719,17 @@ 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); - } +/* PRE_PARSING or SINGLE_PHASE_PARSING */ +/* The following rules will be run either by: + * - the pre_parsing phase of two phase parsing (when preparsing command line option is chosen). + * - the standard single phase parser (when preparsing command line option is not chosen). + */ + identifier ':' subrange_spec_init {library_element_symtable.insert($1, prev_declared_subrange_type_name_token);} + {if (!get_preparse_state()) $$ = new subrange_type_declaration_c($1, $3, locloc(@$));} +/* POST_PARSING */ +/* These rules will be run after the preparser phase of two phase parsing has finished (only gets to execute if preparsing command line option is chosen). */ +| prev_declared_subrange_type_name ':' subrange_spec_init + {$$ = new subrange_type_declaration_c(new identifier_c(((token_c *)$1)->value, locloc(@1)), $3, locloc(@$));} // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! /* ERROR_CHECK_BEGIN */ | error ':' subrange_spec_init {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for subrange type declaration."); yyerrok;} @@ -2784,10 +2825,27 @@ * identifier ':' enumerated_spec_init * and include the library_element_symtable.insert(...) code in the rule actions! */ +/* PRE_PARSING or SINGLE_PHASE_PARSING */ +/* The following rules will be run either by: + * - the pre_parsing phase of two phase parsing (when preparsing command line option is chosen). + * - the standard single phase parser (when preparsing command line option is not chosen). + */ identifier ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} + {if (!get_preparse_state()) $$ = new enumerated_type_declaration_c($1, new enumerated_spec_init_c($3, NULL, locloc(@3)), locloc(@$));} +| identifier ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} ASSIGN enumerated_value + {if (!get_preparse_state()) $$ = new enumerated_type_declaration_c($1, new enumerated_spec_init_c($3, $6, locf(@3), locl(@6)), locloc(@$));} +/* POST_PARSING */ +/* These rules will be run after the preparser phase of two phase parsing has finished (only gets to execute if preparsing command line option is chosen). */ +/* Since the enumerated type name is placed in the library_element_symtable during preparsing, we can now safely use the single rule: */ +| prev_declared_enumerated_type_name ':' enumerated_spec_init + {$$ = new enumerated_type_declaration_c(new identifier_c(((token_c *)$1)->value, locloc(@1)), $3, locloc(@$));} // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! + /* These two rules are equivalent to the above rule */ +/* +| prev_declared_enumerated_type_name ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} {$$ = new enumerated_type_declaration_c($1, new enumerated_spec_init_c($3, NULL, locloc(@3)), locloc(@$));} -| identifier ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} ASSIGN enumerated_value +| prev_declared_enumerated_type_name ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} ASSIGN enumerated_value {$$ = new enumerated_type_declaration_c($1, new enumerated_spec_init_c($3, $6, locf(@3), locl(@6)), locloc(@$));} +*/ /* ERROR_CHECK_BEGIN */ | error ':' enumerated_spec_init {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for enumerated type declaration."); yyerrok;} @@ -2875,10 +2933,17 @@ 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); - } +/* PRE_PARSING or SINGLE_PHASE_PARSING */ +/* The following rules will be run either by: + * - the pre_parsing phase of two phase parsing (when preparsing command line option is chosen). + * - the standard single phase parser (when preparsing command line option is not chosen). + */ + identifier ':' array_spec_init {library_element_symtable.insert($1, prev_declared_array_type_name_token);} + {if (!get_preparse_state()) $$ = new array_type_declaration_c($1, $3, locloc(@$));} +/* POST_PARSING */ +/* These rules will be run after the preparser phase of two phase parsing has finished (only gets to execute if preparsing command line option is chosen). */ +| prev_declared_array_type_name ':' array_spec_init + {$$ = new array_type_declaration_c(new identifier_c(((token_c *)$1)->value, locloc(@1)), $3, locloc(@$));} // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! /* ERROR_CHECK_BEGIN */ | identifier array_spec_init {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in array type declaration."); yynerrs++;} @@ -3030,10 +3095,17 @@ 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); - } +/* PRE_PARSING or SINGLE_PHASE_PARSING */ +/* The following rules will be run either by: + * - the pre_parsing phase of two phase parsing (when preparsing command line option is chosen). + * - the standard single phase parser (when preparsing command line option is not chosen). + */ + identifier ':' structure_specification {library_element_symtable.insert($1, prev_declared_structure_type_name_token);} + {if (!get_preparse_state()) $$ = new structure_type_declaration_c($1, $3, locloc(@$));} +/* POST_PARSING */ +/* These rules will be run after the preparser phase of two phase parsing has finished (only gets to execute if preparsing command line option is chosen). */ +| prev_declared_structure_type_name ':' structure_specification + {$$ = new structure_type_declaration_c(new identifier_c(((token_c *)$1)->value, locloc(@1)), $3, locloc(@$));} // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! /* ERROR_CHECK_BEGIN */ | identifier structure_specification {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in structure type declaration."); yynerrs++;} @@ -3215,10 +3287,17 @@ 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); - } +/* PRE_PARSING or SINGLE_PHASE_PARSING */ +/* The following rules will be run either by: + * - the pre_parsing phase of two phase parsing (when preparsing command line option is chosen). + * - the standard single phase parser (when preparsing command line option is not chosen). + */ + identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init {library_element_symtable.insert($1, prev_declared_string_type_name_token);} + {if (!get_preparse_state()) $$ = new string_type_declaration_c($1, $3, $4, $5, locloc(@$));} +/* POST_PARSING */ +/* These rules will be run after the preparser phase of two phase parsing has finished (only gets to execute if preparsing command line option is chosen). */ +| prev_declared_string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init + {$$ = new string_type_declaration_c(new identifier_c(((token_c *)$1)->value, locloc(@1)), $3, $4, $5, locloc(@$));} // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! ; @@ -3343,12 +3422,18 @@ ; ref_type_decl: /* defined in IEC 61131-3 v3 */ - identifier ':' ref_spec_init - {$$ = new ref_type_decl_c($1, $3, locloc(@$)); - library_element_symtable.insert($1, prev_declared_ref_type_name_token); - } -; - +/* PRE_PARSING or SINGLE_PHASE_PARSING */ +/* The following rules will be run either by: + * - the pre_parsing phase of two phase parsing (when preparsing command line option is chosen). + * - the standard single phase parser (when preparsing command line option is not chosen). + */ + identifier ':' ref_spec_init {library_element_symtable.insert($1, prev_declared_ref_type_name_token);} + {if (!get_preparse_state()) $$ = new ref_type_decl_c($1, $3, locloc(@$));} +/* POST_PARSING */ +/* These rules will be run after the preparser phase of two phase parsing has finished (only gets to execute if preparsing command line option is chosen). */ +| prev_declared_ref_type_name ':' ref_spec_init + {$$ = new ref_type_decl_c(new identifier_c(((token_c *)$1)->value, locloc(@1)), $3, locloc(@$));} // change the derived_datatype_identifier_c into an identifier_c, as it will be taking the place of an identifier! +; @@ -4781,9 +4866,10 @@ //| standard_function_name_simpleop_only_clashes ; +/* standard_function_name_no_clashes is only used in function invocations, so we use the poutype_identifier_c class! */ standard_function_name_no_clashes: standard_function_name_token - {$$ = new identifier_c($1, locloc(@$));} + {$$ = new poutype_identifier_c($1, locloc(@$));} ; @@ -4792,9 +4878,10 @@ //| standard_function_name_simpleop_only_clashes ; +/* standard_function_name_NOT_clashes is only used in function invocations, so we use the poutype_identifier_c class! */ standard_function_name_NOT_clashes: NOT - {$$ = new identifier_c(strdup("NOT"), locloc(@$));} + {$$ = new poutype_identifier_c(strdup("NOT"), locloc(@$));} ; /* Add here any other IL simple operators that collide @@ -4809,98 +4896,88 @@ ; */ +/* standard_function_name_expression_clashes is only used in function invocations, so we use the poutype_identifier_c class! */ 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 {$$ = new poutype_identifier_c(strdup("AND"), locloc(@$));} +| OR {$$ = new poutype_identifier_c(strdup("OR"), locloc(@$));} +| XOR {$$ = new poutype_identifier_c(strdup("XOR"), locloc(@$));} +| ADD {$$ = new poutype_identifier_c(strdup("ADD"), locloc(@$));} +| SUB {$$ = new poutype_identifier_c(strdup("SUB"), locloc(@$));} +| MUL {$$ = new poutype_identifier_c(strdup("MUL"), locloc(@$));} +| DIV {$$ = new poutype_identifier_c(strdup("DIV"), locloc(@$));} +| MOD {$$ = new poutype_identifier_c(strdup("MOD"), locloc(@$));} +| GT {$$ = new poutype_identifier_c(strdup("GT"), locloc(@$));} +| GE {$$ = new poutype_identifier_c(strdup("GE"), locloc(@$));} +| EQ {$$ = new poutype_identifier_c(strdup("EQ"), locloc(@$));} +| LT {$$ = new poutype_identifier_c(strdup("LT"), locloc(@$));} +| LE {$$ = new poutype_identifier_c(strdup("LE"), locloc(@$));} +| NE {$$ = new poutype_identifier_c(strdup("NE"), locloc(@$));} /* - AND_operator {$$ = il_operator_c_2_identifier_c($1);} + AND_operator {$$ = il_operator_c_2_poutype_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);} +//| AND2_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} +| OR_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} +| XOR_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} +| ADD_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} +| SUB_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} +| MUL_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} +| DIV_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} +| MOD_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} +| GT_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} +| GE_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} +| EQ_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} +| LT_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} +| LE_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} +| NE_operator {$$ = il_operator_c_2_poutype_identifier_c($1);} */ ; derived_function_name: - identifier + identifier /* will never occur during normal parsing, only needed for preparsing to change it to a prev_declared_derived_function_name! */ | prev_declared_derived_function_name - {$$ = $1; - if (!allow_function_overloading) { - fprintf(stderr, "Function overloading not allowed. Invalid identifier %s\n", ((token_c *)($1))->value); - ERROR; - } + {$$ = new identifier_c(((token_c *)$1)->value, locloc(@$)); // transform the poutype_identifier_c into an identifier_c + if (get_preparse_state() && !allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} } | AND {$$ = new identifier_c("AND", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"AND\" not allowed. Invalid identifier\n"); + if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} } | OR {$$ = new identifier_c("OR", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"OR\" not allowed. Invalid identifier\n"); + if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} } | XOR {$$ = new identifier_c("XOR", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"XOR\" not allowed. Invalid identifier\n"); + if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} } | NOT {$$ = new identifier_c("NOT", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"NOT\" not allowed. Invalid identifier\n"); + if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} } | MOD {$$ = new identifier_c("MOD", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"MOD\" not allowed. Invalid identifier\n"); + if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} } ; 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 +/* PRE_PARSING: The rules expected to be applied by the preparser. */ + FUNCTION derived_function_name END_FUNCTION /* rule that is only expected to be used during preparse state => MUST print an error if used outside preparse() state!! */ + {$$ = NULL; + if (get_preparse_state()) {library_element_symtable.insert($2, prev_declared_derived_function_name_token);} + else {print_err_msg(locl(@1), locf(@3), "FUNCTION with no variable declarations and no body."); yynerrs++;} + } +/* POST_PARSING and STANDARD_PARSING: The rules expected to be applied after the preparser has finished. */ +| function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION {$$ = new function_declaration_c($1, $3, $4, $5, locloc(@$)); add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ variable_name_symtable.pop(); direct_variable_symtable.pop(); - if (allow_function_overloading) { - switch (library_element_symtable.find_value($1)) { - case prev_declared_derived_function_name_token: - /* do nothing, already in map. */ - break; - case BOGUS_TOKEN_ID: - /* Not yet in map. Must insert...*/ - library_element_symtable.insert($1, prev_declared_derived_function_name_token); - break; - default: - /* Already in map but associated with something else other than a funtion name! */ - ERROR; - } - } else { - library_element_symtable.insert($1, prev_declared_derived_function_name_token); - } + 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 @@ -4908,15 +4985,7 @@ add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ variable_name_symtable.pop(); direct_variable_symtable.pop(); - if (allow_function_overloading) { - switch (library_element_symtable.find_value($1)) { - case prev_declared_derived_function_name_token: /* do nothing, already in map. */ break; - case BOGUS_TOKEN_ID: library_element_symtable.insert($1, prev_declared_derived_function_name_token); break; - default: ERROR; - } - } else { - library_element_symtable.insert($1, prev_declared_derived_function_name_token); - } + library_element_symtable.insert($1, prev_declared_derived_function_name_token); } /* ERROR_CHECK_BEGIN */ | function_name_declaration elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION @@ -4981,6 +5050,7 @@ * the parser to reduce it, before parsing the function body! */ function_name_declaration: + /* FUNCTION derived_function_name */ FUNCTION derived_function_name {$$ = $2; /* the function name functions as a @@ -5114,14 +5184,29 @@ function_block_declaration: - FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK +/* PRE_PARSING: The rules expected to be applied by the preparser. Will only run if pre-parsing command line option is ON. */ + FUNCTION_BLOCK derived_function_block_name END_FUNCTION_BLOCK /* rule that is only expected to be used during preparse state => MUST print an error if used outside preparse() state!! */ + {$$ = NULL; + if (get_preparse_state()) {library_element_symtable.insert($2, prev_declared_derived_function_block_name_token);} + else {print_err_msg(locl(@1), locf(@3), "FUNCTION_BLOCK with no variable declarations and no body."); yynerrs++;} + } +/* POST_PARSING: The rules expected to be applied after the preparser runs. Will only run if pre-parsing command line option is ON. */ +| FUNCTION_BLOCK prev_declared_derived_function_block_name io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK {$$ = new function_block_declaration_c($2, $3, $4, locloc(@$)); add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ + /* Clear the variable_name_symtable. Since we have finished parsing the function block, + * the variable names are now out of scope, so are no longer valid! + */ + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + } +/* STANDARD_PARSING: The rules expected to be applied in single-phase parsing. Will only run if pre-parsing command line option is OFF. */ +| 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! + add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ + /* Clear the variable_name_symtable. Since we have finished parsing the function block, + * the variable names are now out of scope, so are no longer valid! */ variable_name_symtable.pop(); direct_variable_symtable.pop(); @@ -5135,8 +5220,10 @@ {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared in function declaration."); yynerrs++;} | FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list END_FUNCTION_BLOCK {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no body defined in function block declaration."); yynerrs++;} +/* Rule already covered by the rule to handle the preparse state! | FUNCTION_BLOCK derived_function_block_name END_FUNCTION_BLOCK {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared and body defined in function block declaration."); yynerrs++;} +*/ | FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_OF_INPUT {$$ = NULL; print_err_msg(locf(@1), locl(@2), "no variable(s) declared and body defined in function block declaration."); yynerrs++;} | FUNCTION_BLOCK error END_FUNCTION_BLOCK @@ -5267,13 +5354,26 @@ program_declaration: - PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM +/* PRE_PARSING: The rules expected to be applied by the preparser. Will only run if pre-parsing command line option is ON. */ + PROGRAM program_type_name END_PROGRAM /* rule that is only expected to be used during preparse state => MUST print an error if used outside preparse() state!! */ + {$$ = NULL; + if (get_preparse_state()) {library_element_symtable.insert($2, prev_declared_program_type_name_token);} + else {print_err_msg(locl(@1), locf(@3), "PROGRAM with no variable declarations and no body."); yynerrs++;} + } +/* POST_PARSING: The rules expected to be applied after the preparser runs. Will only run if pre-parsing command line option is ON. */ +| PROGRAM prev_declared_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! + /* Clear the variable_name_symtable. Since we have finished parsing the program declaration, + * the variable names are now out of scope, so are no longer valid! + */ + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + } +/* STANDARD_PARSING: The rules expected to be applied in single-phase parsing. Will only run if pre-parsing command line option is OFF. */ +| PROGRAM program_type_name {library_element_symtable.insert($2, prev_declared_program_type_name_token);} program_var_declarations_list function_block_body END_PROGRAM + {$$ = new program_declaration_c($2, $4, $5, locloc(@$)); + /* Clear the variable_name_symtable. Since we have finished parsing the program declaration, + * the variable names are now out of scope, so are no longer valid! */ variable_name_symtable.pop(); direct_variable_symtable.pop(); @@ -5283,13 +5383,15 @@ {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no program name defined in program declaration.");} | PROGRAM error program_var_declarations_list function_block_body END_PROGRAM {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid program name in program declaration."); yyerrok;} -| PROGRAM program_type_name function_block_body END_PROGRAM +| PROGRAM prev_declared_program_type_name function_block_body END_PROGRAM {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared in program declaration."); yynerrs++;} -| PROGRAM program_type_name program_var_declarations_list END_PROGRAM +| PROGRAM prev_declared_program_type_name program_var_declarations_list END_PROGRAM {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no body defined in program declaration."); yynerrs++;} -| PROGRAM program_type_name END_PROGRAM +/* Rule already covered by the rule to handle the preparse state! +| PROGRAM prev_declared_program_type_name END_PROGRAM {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared and body defined in program declaration."); yynerrs++;} -| PROGRAM program_type_name program_var_declarations_list function_block_body END_OF_INPUT +*/ +| PROGRAM prev_declared_program_type_name program_var_declarations_list function_block_body END_OF_INPUT {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed program declaration."); yynerrs++;} | PROGRAM error END_PROGRAM {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in program declaration."); yyerrok;} @@ -5768,10 +5870,11 @@ * 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(@$));}; +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_configuration_name: prev_declared_configuration_name_token {$$ = new identifier_c($1, locloc(@$));}; +// prev_declared_task_name: prev_declared_task_name_token {$$ = new identifier_c($1, locloc(@$));}; @@ -5795,7 +5898,14 @@ resource_type_name: any_identifier; configuration_declaration: - CONFIGURATION configuration_name +/* PRE_PARSING: The rules expected to be applied by the preparser. Will only run if pre-parsing command line option is ON. */ + CONFIGURATION configuration_name END_CONFIGURATION /* rule that is only expected to be used during preparse state */ + {$$ = NULL; + if (get_preparse_state()) {library_element_symtable.insert($2, prev_declared_configuration_name_token);} + else {print_err_msg(locl(@1), locf(@3), "no resource(s) nor program(s) defined in configuration declaration."); yynerrs++;} + } +/* POST_PARSING: The rules expected to be applied after the preparser runs. Will only run if pre-parsing command line option is ON. */ +| CONFIGURATION prev_declared_configuration_name global_var_declarations_list single_resource_declaration {variable_name_symtable.pop(); @@ -5804,10 +5914,33 @@ optional_instance_specific_initializations END_CONFIGURATION {$$ = new configuration_declaration_c($2, $3, $4, $6, $7, locloc(@$)); - library_element_symtable.insert($2, prev_declared_configuration_name_token); variable_name_symtable.pop(); direct_variable_symtable.pop(); } +| CONFIGURATION prev_declared_configuration_name + global_var_declarations_list + resource_declaration_list + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = new configuration_declaration_c($2, $3, $4, $5, $6, locloc(@$)); + variable_name_symtable.pop(); + direct_variable_symtable.pop(); +} +/* STANDARD_PARSING: The rules expected to be applied in single-phase parsing. Will only run if pre-parsing command line option is OFF. */ +| CONFIGURATION configuration_name + global_var_declarations_list + single_resource_declaration + {variable_name_symtable.pop(); + direct_variable_symtable.pop();} + optional_access_declarations + optional_instance_specific_initializations + END_CONFIGURATION + {$$ = new configuration_declaration_c($2, $3, $4, $6, $7, locloc(@$)); + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + library_element_symtable.insert($2, prev_declared_configuration_name_token); + } | CONFIGURATION configuration_name global_var_declarations_list resource_declaration_list @@ -5815,9 +5948,9 @@ optional_instance_specific_initializations END_CONFIGURATION {$$ = new configuration_declaration_c($2, $3, $4, $5, $6, locloc(@$)); - library_element_symtable.insert($2, prev_declared_configuration_name_token); variable_name_symtable.pop(); direct_variable_symtable.pop(); + library_element_symtable.insert($2, prev_declared_configuration_name_token); } /* ERROR_CHECK_BEGIN */ | CONFIGURATION @@ -5852,12 +5985,14 @@ optional_instance_specific_initializations END_CONFIGURATION {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid configuration name defined in configuration declaration."); yyerrok;} +/* Rule already covered by the rule to handle the preparse state! | CONFIGURATION configuration_name global_var_declarations_list optional_access_declarations optional_instance_specific_initializations END_CONFIGURATION {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no resource(s) defined in configuration declaration."); yynerrs++;} +*/ | CONFIGURATION configuration_name global_var_declarations_list error @@ -6601,7 +6736,7 @@ * those whose names coincide with operators !! */ | function_name_no_clashes - {$$ = new il_function_call_c($1, NULL, locloc(@$));} + {$$ = new il_function_call_c($1, NULL, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c /* NOTE: the line * | il_simple_operator il_operand * already contains the 'NOT', 'MOD', etc. operators, followed by a single il_operand. @@ -6629,9 +6764,9 @@ * 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(@$));} + {$$ = new il_function_call_c($1, $2, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c | il_simple_operator_clash il_operand_list2 - {$$ = new il_function_call_c(il_operator_c_2_identifier_c($1), $2, locloc(@$));} + {$$ = new il_function_call_c(il_operator_c_2_poutype_identifier_c($1), $2, locloc(@$));} ; @@ -6790,9 +6925,9 @@ * (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(@$));} + {$$ = new il_formal_funct_call_c($1, NULL, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c | function_name_simpleop_clashes '(' eol_list ')' - {$$ = new il_formal_funct_call_c($1, NULL, locloc(@$));} + {$$ = new il_formal_funct_call_c($1, NULL, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c /* | 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! @@ -6807,9 +6942,9 @@ * 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(@$));} + {$$ = new il_formal_funct_call_c($1, $4, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c | function_name_simpleop_clashes '(' eol_list il_param_list ')' - {$$ = new il_formal_funct_call_c($1, $4, locloc(@$));} + {$$ = new il_formal_funct_call_c($1, $4, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c /* The following line should read: * * | function_name_expression_clashes '(' eol_list il_param_list ')' @@ -6829,10 +6964,10 @@ * 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() + * at the end of this file... il_operator_c_2_poutype_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(@$));} + {$$ = new il_formal_funct_call_c(il_operator_c_2_poutype_identifier_c($1), $2, locloc(@$));} /* ERROR_CHECK_BEGIN */ | function_name_no_clashes '(' eol_list error ')' {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid parameter list defined in IL formal function call."); yyerrok;} @@ -7647,9 +7782,9 @@ function_invocation: /* function_name '(' [param_assignment_list] ')' */ function_name_no_NOT_clashes '(' param_assignment_formal_list ')' - {$$ = new function_invocation_c($1, $3, NULL, locloc(@$));} + {$$ = new function_invocation_c($1, $3, NULL, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c | function_name_no_NOT_clashes '(' param_assignment_nonformal_list ')' - {$$ = new function_invocation_c($1, NULL, $3, locloc(@$));} + {$$ = new function_invocation_c($1, NULL, $3, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c /* ERROR_CHECK_BEGIN */ | function_name_no_NOT_clashes param_assignment_formal_list ')' {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function name in ST expression."); yynerrs++;} @@ -8403,7 +8538,17 @@ /* 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) { +poutype_identifier_c *il_operator_c_2_poutype_identifier_c(symbol_c *il_operator) { + identifier_c * id = il_operator_c_2_identifier_c(il_operator); + poutype_identifier_c *pou_id = new poutype_identifier_c(strdup(id->value)); + + *(symbol_c *)pou_id = *(symbol_c *)id; + delete id; + return pou_id; +} + + +identifier_c *il_operator_c_2_identifier_c(symbol_c *il_operator) { const char *name = NULL; identifier_c *res; @@ -8469,7 +8614,7 @@ if (name == NULL) ERROR; - +/* res = new identifier_c(strdup(name), il_operator->first_line, il_operator->first_column, @@ -8481,6 +8626,11 @@ il_operator->last_order ); free(il_operator); +*/ + res = new identifier_c(strdup(name)); + *(symbol_c *)res = *(symbol_c *)il_operator; + delete il_operator; + return res; } @@ -8513,28 +8663,13 @@ extern const char *INCLUDE_DIRECTORIES[]; -int stage2__(const char *filename, - symbol_c **tree_root_ref - ) { - char *libfilename = NULL; - - if (runtime_options.includedir != NULL) { - INCLUDE_DIRECTORIES[0] = runtime_options.includedir; - } - - /* first parse the standard library file... */ - /* Do not debug the standard library, even if debug flag is set! */ - /* +static int parse_files(const char *libfilename, const char *filename) { + /* first parse the standard library file... */ + /* Do not debug the standard library, even if debug flag is set! #if YYDEBUG yydebug = 1; #endif */ - - if ((libfilename = strdup3(INCLUDE_DIRECTORIES[0], "/", LIBFILE)) == NULL) { - fprintf (stderr, "Out of memory. Bailing out!\n"); - return -1; - } - FILE *libfile = NULL; if((libfile = parse_file(libfilename)) == NULL) { char *errmsg = strdup2("Error opening library file ", libfilename); @@ -8551,19 +8686,19 @@ allow_ref_dereferencing = runtime_options.ref_standard_extensions; allow_ref_to_any = runtime_options.ref_nonstand_extensions; allow_ref_to_in_derived_datatypes = runtime_options.ref_nonstand_extensions; - if (yyparse() != 0) - ERROR; + if (yyparse() != 0) { + fprintf (stderr, "\nParsing failed because of too many consecutive syntax errors in standard library. Bailing out!\n"); + exit(EXIT_FAILURE); + } fclose(libfile); - if (yynerrs > 0) { - fprintf (stderr, "\n%d error(s) found in %s. Bailing out!\n", yynerrs /* global variable */, libfilename); - ERROR; + if (yynerrs > 0) { /* NOTE: yynerrs is a global variable */ + /* Hopefully the libraries do not contain any errors, so this should not occur! */ + fprintf (stderr, "\n%d error(s) found in %s. Bailing out!\n", yynerrs, libfilename); + return -2; } - free(libfilename); - - /* if by any chance the library is not complete, we - * now add the missing reserved keywords to the list!!! - */ + + /* if by any chance the library is not complete, we now add the missing reserved keywords to the list!!! */ for(int i = 0; standard_function_block_names[i] != NULL; i++) if (library_element_symtable.find_value(standard_function_block_names[i]) == library_element_symtable.end_value()) @@ -8578,7 +8713,7 @@ char *errmsg = strdup2("Error opening main file ", filename); perror(errmsg); free(errmsg); - return -1; + return -3; } allow_function_overloading = false; @@ -8600,7 +8735,80 @@ fprintf (stderr, "\n%d error(s) found. Bailing out!\n", yynerrs /* global variable */); exit(EXIT_FAILURE); } + + return 0; +} + + + + + +/* We parse the input source code twice!! + * 1st pass --> Pre-parsing + * ------------------------- + * The intention of the first pass is to fill up the library_element_symtable with the names of all + * the POUs (Functions, FBs, Programs and Configurations), as well as all the Derived Datatypes. + * + * During this pass POUs are only parsed until their name is obtained, and the remaining source + * code (variable declarations and body) is completely thrown away by flex. Datatype declarations + * however are parsed normally! + * + * At the end of the pre-parsing, the AST will contain only the derived datatype declarations, + * and this tree will be trown away (by simply resetting tree_root = NULL). + * More importantly, the library_element_symtable will contain the names of all the POUs and + * derived datatypes. + * + * 2st pass --> Normal parsing + * ---------------------------- + * In this second parse the whole source code is parsed correctly, and the AST is generated + * completely. + * + * However, if the pre-parsing has been done before this normal parsing, the POUs may appear + * in the source code in any order, as calling a POU (e.g. calling a function) that has not yet + * been declared will no longer generate a parsing error because the name of the function being + * called is already in the library_element_symtable. + * + * Declaring variables of datatypes that have not yet been declared will also be possible, as the + * datatypes will also already be in the library_element_symtable! + */ + +int stage2__(const char *filename, + symbol_c **tree_root_ref + ) { + char *libfilename = NULL; + + /* Determine the full path name of the standard library file... */ + if (runtime_options.includedir != NULL) + INCLUDE_DIRECTORIES[0] = runtime_options.includedir; + + if ((libfilename = strdup3(INCLUDE_DIRECTORIES[0], "/", LIBFILE)) == NULL) { + fprintf (stderr, "Out of memory. Bailing out!\n"); + exit(EXIT_FAILURE); + } + + /*******************************/ + /* Do the PRE parsing run...! */ + /*******************************/ + if (runtime_options.pre_parsing) { + // fprintf (stderr, "----> Starting pre-parsing!\n"); + tree_root = NULL; + set_preparse_state(); + if (parse_files(libfilename, filename) < 0) + exit(EXIT_FAILURE); + // TODO: delete the current AST. For the moment, we leave all the objects in memory (not much of an issue in a program that always runs to completion). + } + /*******************************/ + /* Do the main parsing run...! */ + /*******************************/ + // fprintf (stderr, "----> Starting normal parsing!\n"); + tree_root = NULL; + rst_preparse_state(); + if (parse_files(libfilename, filename) < 0) + exit(EXIT_FAILURE); + + /* Final clean-up... */ + free(libfilename); if (tree_root_ref != NULL) *tree_root_ref = tree_root; diff -r 27063736913f -r b05f63d9d0fa stage1_2/iec_flex.ll --- a/stage1_2/iec_flex.ll Sat Nov 22 19:30:47 2014 +0000 +++ b/stage1_2/iec_flex.ll Wed Dec 10 11:57:43 2014 +0000 @@ -347,8 +347,31 @@ * Unfortunately, flex will join '_' and '4h' to create a legal {identifier} '_4h', * and return that identifier instead! So, we added this state! * - * There is a main state machine... + * The ignore_pou_state state is only used when bison says it is doing the pre-parsing. + * During pre-parsing, the main state machine will only transition between + * INITIAL and ignore_pou_state, and from here back to INITIAL. All other + * transitions are inhibited. This inhibition is actually just enforced by making + * sure that the INITIAL ---> ignore_pou_state transition is tested before all other + * transitions coming out of INITIAL state. All other transitions are unaffected, as they + * never get a chance to be evaluated when bison is doing pre-parsing. + * Pre-parsing is a first quick scan through the whole input source code simply + * to determine the list of POUs and datatypes that will be defined in that + * code. Basically, the objective is to fill up the previously_declared_xxxxx + * maps, without processing the code itself. Once these maps have been filled up, + * bison will throw away the AST (abstract syntax tree) created up to that point, + * and scan through the same source code again, but this time creating a correct AST. + * This pre-scan allows the source code to reference POUs and datatypes that are + * only declared after they are used! * + * + * Here is a main state machine... + * --+ + * | these states are + * +------------> get_pou_name_state ----> ignore_pou_state | only active + * | | | when bison is + * | ------------------------------------------+ | doing the + * | | | pre-parsing!! + * | v --+ * +---> INITIAL <-------> config * | \ * | V @@ -379,11 +402,17 @@ * * * Possible state changes are: + * INITIAL -> goto(ignore_pou_state) + * (This transition state is only used when bison says it is doing the pre-parsing.) + * (This transition takes precedence over all other transitions!) + * (when a FUNCTION, FUNCTION_BLOCK, PROGRAM or CONFIGURATION is found) + * * INITIAL -> goto(config_state) * (when a CONFIGURATION is found) * * INITIAL -> goto(header_state) * (when a FUNCTION, FUNCTION_BLOCK, or PROGRAM is found) + * * header_state -> goto(vardecl_list_state) * (When the first VAR token is found, i.e. at begining of first VAR .. END_VAR declaration) * @@ -410,10 +439,12 @@ * sfc_state -> pop() to vardecl_list_state * (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found) * + * ignore_pou_state -> goto(INITIAL) + * (when a END_FUNCTION, END_FUNCTION_BLOCK, END_PROGRAM or END_CONFIGURATION is found) * vardecl_list_state -> goto(INITIAL) - * (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found) - * config_state -> goto(INITIAL) - * (when a END_CONFIGURATION is found) + * (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found) + * config_state -> goto(INITIAL) + * (when a END_CONFIGURATION is found) * * * sfc_state -> push current state(sfc_state); goto(body_state) @@ -434,6 +465,10 @@ */ +/* Bison is in the pre-parsing stage, and we are parsing a POU. Ignore everything up to the end of the POU! */ +%x ignore_pou_state +%x get_pou_name_state + /* we are parsing a configuration. */ %s config_state @@ -1052,10 +1087,24 @@ * continue in the state, untill the end of the FUNCTION, FUNCTION_BLOCK * or PROGAM. */ -FUNCTION yy_push_state(header_state); return FUNCTION; -FUNCTION_BLOCK yy_push_state(header_state); return FUNCTION_BLOCK; -PROGRAM yy_push_state(header_state); return PROGRAM; -CONFIGURATION BEGIN(config_state); return CONFIGURATION; + +FUNCTION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return FUNCTION; +FUNCTION_BLOCK{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return FUNCTION_BLOCK; +PROGRAM{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return PROGRAM; +CONFIGURATION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(config_state); return CONFIGURATION; +} + +{ +{identifier} BEGIN(ignore_pou_state); yylval.ID=strdup(yytext); return identifier_token; +. BEGIN(ignore_pou_state); unput_text(0); +} + +{ +END_FUNCTION unput_text(0); BEGIN(INITIAL); +END_FUNCTION_BLOCK unput_text(0); BEGIN(INITIAL); +END_PROGRAM unput_text(0); BEGIN(INITIAL); +END_CONFIGURATION unput_text(0); BEGIN(INITIAL); +.|\n {}/* Ignore text inside POU! (including the '\n' character!)) */ } /* INITIAL -> body_state */ @@ -1108,7 +1157,7 @@ /* vardecl_list_state -> pop to $previous_state (vardecl_list_state) */ { -END_VAR yy_pop_state(); return END_VAR; /* pop back to header_state */ +END_VAR yy_pop_state(); return END_VAR; /* pop back to vardecl_list_state */ } @@ -1180,7 +1229,7 @@ {il_whitespace} /* Eat any whitespace */ /* The comments */ -{comment_beg} yy_push_state(comment_state); +{comment_beg} yy_push_state(comment_state); {comment_beg} yy_push_state(comment_state); { {comment_beg} {if (get_opt_nested_comments()) yy_push_state(comment_state);} diff -r 27063736913f -r b05f63d9d0fa stage1_2/stage1_2.cc --- a/stage1_2/stage1_2.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/stage1_2/stage1_2.cc Wed Dec 10 11:57:43 2014 +0000 @@ -73,6 +73,15 @@ bool get_opt_ref_standard_extensions() {return runtime_options.ref_standard_extensions;} +/**********************************************************************************************/ +/* whether bison is doing the pre-parsing, where POU bodies and var declarations are ignored! */ +/**********************************************************************************************/ +static bool preparse_state__ = false; + +void set_preparse_state(void) {preparse_state__ = true; } +void rst_preparse_state(void) {preparse_state__ = false;} +bool get_preparse_state(void) {return preparse_state__;} // returns true if bison is in preparse state + /****************************************************/ /* Controlling the entry to the body_state in flex. */ diff -r 27063736913f -r b05f63d9d0fa stage1_2/stage1_2_priv.hh --- a/stage1_2/stage1_2_priv.hh Sat Nov 22 19:30:47 2014 +0000 +++ b/stage1_2/stage1_2_priv.hh Wed Dec 10 11:57:43 2014 +0000 @@ -142,6 +142,12 @@ FILE *parse_file(const char *filename); +/**********************************************************************************************/ +/* whether bison is doing the pre-parsing, where POU bodies and var declarations are ignored! */ +/**********************************************************************************************/ +void set_preparse_state(void); +void rst_preparse_state(void); +bool get_preparse_state(); // returns true if bison is in preparse state /****************************************************/ /* Controlling the entry to the body_state in flex. */ diff -r 27063736913f -r b05f63d9d0fa stage3/Makefile.am --- a/stage3/Makefile.am Sat Nov 22 19:30:47 2014 +0000 +++ b/stage3/Makefile.am Wed Dec 10 11:57:43 2014 +0000 @@ -14,5 +14,6 @@ array_range_check.cc \ constant_folding.cc \ declaration_check.cc \ - enum_declaration_check.cc + enum_declaration_check.cc \ + remove_forward_dependencies.cc diff -r 27063736913f -r b05f63d9d0fa stage3/fill_candidate_datatypes.cc --- a/stage3/fill_candidate_datatypes.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/stage3/fill_candidate_datatypes.cc Wed Dec 10 11:57:43 2014 +0000 @@ -987,7 +987,7 @@ /* enumerated_specification ASSIGN enumerated_value */ // SYM_REF2(enumerated_spec_init_c, enumerated_specification, enumerated_value) -// NOTE: enumerated_specification is either an enumerated_value_list_c or identifier_c. +// NOTE: enumerated_specification is either an enumerated_value_list_c or derived_datatype_identifier_c. void *fill_candidate_datatypes_c::visit(enumerated_spec_init_c *symbol) {return fill_spec_init(symbol, symbol->enumerated_specification, symbol->enumerated_value);} diff -r 27063736913f -r b05f63d9d0fa stage3/print_datatypes_error.cc --- a/stage3/print_datatypes_error.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/stage3/print_datatypes_error.cc Wed Dec 10 11:57:43 2014 +0000 @@ -164,14 +164,14 @@ /* Check if there are duplicate parameter values */ if(fcp_iterator.search_f(param_name) != param_value) { function_invocation_error = true; - STAGE3_ERROR(0, param_name, param_name, "Duplicate parameter '%s' when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + STAGE3_ERROR(0, param_name, param_name, "Duplicate parameter '%s' when invoking %s '%s'", ((token_c *)param_name)->value, POU_str, ((token_c *)fcall_data.function_name)->value); continue; /* jump to next parameter */ } /* Find the corresponding parameter in function declaration */ if (NULL == fp_iterator.search(param_name)) { function_invocation_error = true; - STAGE3_ERROR(0, param_name, param_name, "Invalid parameter '%s' when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + STAGE3_ERROR(0, param_name, param_name, "Invalid parameter '%s' when invoking %s '%s'", ((token_c *)param_name)->value, POU_str, ((token_c *)fcall_data.function_name)->value); continue; /* jump to next parameter */ } @@ -184,20 +184,20 @@ if ((function_param_iterator_c::direction_in != param_dir) && (function_param_iterator_c::direction_inout != param_dir)) { function_invocation_error = true; - STAGE3_ERROR(0, param_name, param_name, "Invalid assignment syntax ':=' used for parameter '%s', when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + STAGE3_ERROR(0, param_name, param_name, "Invalid assignment syntax ':=' used for parameter '%s', when invoking %s '%s'", ((token_c *)param_name)->value, POU_str, ((token_c *)fcall_data.function_name)->value); continue; /* jump to next parameter */ } } else if (function_call_param_iterator_c::assign_out == call_param_dir) { if ((function_param_iterator_c::direction_out != param_dir)) { function_invocation_error = true; - STAGE3_ERROR(0, param_name, param_name, "Invalid assignment syntax '=>' used for parameter '%s', when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + STAGE3_ERROR(0, param_name, param_name, "Invalid assignment syntax '=>' used for parameter '%s', when invoking %s '%s'", ((token_c *)param_name)->value, POU_str, ((token_c *)fcall_data.function_name)->value); continue; /* jump to next parameter */ } } else ERROR; if (!get_datatype_info_c::is_type_valid(param_value->datatype)) { function_invocation_error = true; - STAGE3_ERROR(0, param_value, param_value, "Data type incompatibility between parameter '%s' and value being passed, when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value); + STAGE3_ERROR(0, param_value, param_value, "Data type incompatibility between parameter '%s' and value being passed, when invoking %s '%s'", ((token_c *)param_name)->value, POU_str, ((token_c *)fcall_data.function_name)->value); continue; /* jump to next parameter */ } } @@ -223,7 +223,7 @@ * We will iterate through all the real previous IL instructions, and analyse each of them one by one */ if (il_instruction_symbol->prev_il_instruction.size() == 0) { function_invocation_error = true; - STAGE3_ERROR(0, fcall, fcall, "No available data to pass to first parameter of IL function %s. Missing a previous LD instruction?", ((identifier_c *)fcall_data.function_name)->value); + STAGE3_ERROR(0, fcall, fcall, "No available data to pass to first parameter of IL function %s. Missing a previous LD instruction?", ((token_c *)fcall_data.function_name)->value); } #if 0 /* NOTE: We currently comment out this code... @@ -237,14 +237,14 @@ symbol_c *value = il_instruction_symbol->prev_il_instruction[p]; if (!get_datatype_info_c::is_type_valid(value->datatype)) { function_invocation_error = true; - STAGE3_ERROR(0, fcall, fcall, "Data type incompatibility for value passed to first parameter when invoking function '%s'", ((identifier_c *)fcall_data.function_name)->value); - STAGE3_ERROR(0, value, value, "This is the IL instruction producing the incompatible data type to first parameter of function '%s'", ((identifier_c *)fcall_data.function_name)->value); + STAGE3_ERROR(0, fcall, fcall, "Data type incompatibility for value passed to first parameter when invoking function '%s'", ((token_c *)fcall_data.function_name)->value); + STAGE3_ERROR(0, value, value, "This is the IL instruction producing the incompatible data type to first parameter of function '%s'", ((token_c *)fcall_data.function_name)->value); } } #else if (!get_datatype_info_c::is_type_valid(il_instruction_symbol->datatype)) { function_invocation_error = true; - STAGE3_ERROR(0, fcall, fcall, "Data type incompatibility between value in IL 'accumulator' and first parameter of function '%s'", ((identifier_c *)fcall_data.function_name)->value); + STAGE3_ERROR(0, fcall, fcall, "Data type incompatibility between value in IL 'accumulator' and first parameter of function '%s'", ((token_c *)fcall_data.function_name)->value); } #endif if (function_invocation_error) @@ -253,7 +253,7 @@ } else { if (!get_datatype_info_c::is_type_valid(param_value->datatype)) { function_invocation_error = true; - STAGE3_ERROR(0, param_value, param_value, "Data type incompatibility for value passed in position %d when invoking %s '%s'", i, POU_str, ((identifier_c *)fcall_data.function_name)->value); + STAGE3_ERROR(0, param_value, param_value, "Data type incompatibility for value passed in position %d when invoking %s '%s'", i, POU_str, ((token_c *)fcall_data.function_name)->value); } param_value->accept(*this); } @@ -262,12 +262,12 @@ if (NULL == fcall_data.called_function_declaration) { function_invocation_error = true; - STAGE3_ERROR(0, fcall, fcall, "Unable to resolve which overloaded %s '%s' is being invoked.", POU_str, ((identifier_c *)fcall_data.function_name)->value); + STAGE3_ERROR(0, fcall, fcall, "Unable to resolve which overloaded %s '%s' is being invoked.", POU_str, ((token_c *)fcall_data.function_name)->value); } if (function_invocation_error) { /* No compatible function exists */ - STAGE3_ERROR(2, fcall, fcall, "Invalid parameters when invoking %s '%s'", POU_str, ((identifier_c *)fcall_data.function_name)->value); + STAGE3_ERROR(2, fcall, fcall, "Invalid parameters when invoking %s '%s'", POU_str, ((token_c *)fcall_data.function_name)->value); } return; diff -r 27063736913f -r b05f63d9d0fa stage3/remove_forward_dependencies.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage3/remove_forward_dependencies.cc Wed Dec 10 11:57:43 2014 +0000 @@ -0,0 +1,303 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2014 Mario de Sousa (msousa@fe.up.pt) + * + * 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) + * + */ + +/* + * Re-oder the POUs in te library so that no forward references occur. + * + * Since stage1_2 now suppport POUs that contain references to POUS that are only declared later, + * (e.g. a variable of FB1_t is declared, before the FB1_T function block is itself declared!) + * we may need to re-order all the POUs in the library so that these forward references do not occur. + * + * This utility function will do just that. However, it does not destroy the original abstract syntax + * tree (AST). It instead creates a new re-ordered AST, by instantiating a new library_c object. + * This new library_c object will however point to the *same* objects of the original AST, just in + * a new order. + * This means that the new and original AST share all the object instances, and only use a distinct + * library_c object! + */ + +#include "remove_forward_dependencies.hh" +#include "../main.hh" // required for ERROR() and ERROR_MSG() macros. +#include "../absyntax_utils/absyntax_utils.hh" + + + + + +#define FIRST_(symbol1, symbol2) (((symbol1)->first_order < (symbol2)->first_order) ? (symbol1) : (symbol2)) +#define LAST_(symbol1, symbol2) (((symbol1)->last_order > (symbol2)->last_order) ? (symbol1) : (symbol2)) + +#define FIRST_(symbol1, symbol2) (((symbol1)->first_order < (symbol2)->first_order) ? (symbol1) : (symbol2)) +#define LAST_(symbol1, symbol2) (((symbol1)->last_order > (symbol2)->last_order) ? (symbol1) : (symbol2)) + +#define STAGE3_ERROR(error_level, symbol1, symbol2, ...) { \ + if (current_display_error_level >= error_level) { \ + fprintf(stderr, "%s:%d-%d..%d-%d: error: ", \ + FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column,\ + LAST_(symbol1,symbol2) ->last_line, LAST_(symbol1,symbol2) ->last_column);\ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + error_count++; \ + } \ +} + + +#define STAGE3_WARNING(symbol1, symbol2, ...) { \ + fprintf(stderr, "%s:%d-%d..%d-%d: warning: ", \ + FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column,\ + LAST_(symbol1,symbol2) ->last_line, LAST_(symbol1,symbol2) ->last_column);\ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + warning_found = true; \ +} + + + +/* NOTE: We create an independent visitor for this task instead of having this done by the remove_forward_dependencies_c + * because we do not want to handle the ***_pragma_c classes while doing this search. + * (remove_forward_dependencies_c needs to visit those classes when handling all the possible entries in + * library_c, and must have those visitors) + * + * NOTE: + * This class could have been written by visiting all the AST objects that could _reference_ a + * - FB type + * - Program type + * - Function type + * and by checking whether those references are in the declared_identifiers list. + * However, one of those objects, the ref_spec_c, may reference an FB type, or any other datatype, so we must have a way + * of knowing what is being referenced in this case. I have opted to introduce a new object type in the AST, the + * poutype_identifier_c, that will be used anywhere in the AST that references either a PROGRAM name or a FB type name + * or a FUNCTION name (previously a simple identifier_c was used!). + * This means that we merely need to visit the new poutype_identifier_c object in this visitor. + */ +class find_forward_dependencies_c: public search_visitor_c { + private: + identifiers_symbtable_t *declared_identifiers; // list of identifiers already declared by the symbols in the new tree + public: + find_forward_dependencies_c(identifiers_symbtable_t *declared_identifiers_) {declared_identifiers = declared_identifiers_;} + /*******************************************/ + /* B 1.1 - Letters, digits and identifiers */ + /*******************************************/ + // return NULL if the symbol is already in the declared_identifiers symbol table, otherwise return the missing symbol! + void *visit( poutype_identifier_c *symbol) + {if (declared_identifiers->find_value(symbol) != declared_identifiers->end_value()) return NULL; else return symbol;} +}; /* class find_forward_dependencies_c */ + + + + +/* A class to count the number of POUs (Function, FBs Programs and Configurations) in a library. + * This will be used to make sure whether we have copied all the POUs from the original AST (abstract + * syntax tree) to the new AST. + * Note that we can't simply use the number of 'elements' in the AST, as it may contain unknown/unsupported pragmas. + */ +class pou_count_c: public search_visitor_c { + private: + static pou_count_c *singleton; + long long int count; + + public: + static long long int get_count(library_c *library) { + if (NULL == singleton) singleton = new pou_count_c; + if (NULL == singleton) ERROR; + singleton->count = 0; + library->accept(*singleton); + return singleton->count; + } + + /**************************************/ + /* B.1.5 - Program organization units */ + /**************************************/ + void *visit( function_declaration_c *symbol) {count++; return NULL;} + void *visit(function_block_declaration_c *symbol) {count++; return NULL;} + void *visit( program_declaration_c *symbol) {count++; return NULL;} + void *visit( configuration_declaration_c *symbol) {count++; return NULL;} +}; /* class pou_count_c */ + +pou_count_c *pou_count_c::singleton = NULL; +symbol_c remove_forward_dependencies_c_null_symbol; + + + + + + + + +/************************************************************/ +/************************************************************/ +/****** The main class: Remove Forward Depencies *******/ +/************************************************************/ +/************************************************************/ + +// constructor & destructor +remove_forward_dependencies_c:: remove_forward_dependencies_c(void) { + find_forward_dependencies = new find_forward_dependencies_c(&declared_identifiers); + current_display_error_level = error_level_default; + error_count = 0; +} + +remove_forward_dependencies_c::~remove_forward_dependencies_c(void) { + delete find_forward_dependencies; +} + + +int remove_forward_dependencies_c::get_error_count(void) { + return error_count; +} + + + +library_c *remove_forward_dependencies_c::create_new_tree(symbol_c *tree) { + library_c *old_tree = dynamic_cast(tree); + if (NULL == old_tree) ERROR; + new_tree = new library_c; + *((symbol_c *)new_tree) = *((symbol_c *)tree); // copy any annotations from tree to new_tree; + new_tree->clear(); // remove all elements from list. + tree->accept(*this); + return new_tree; +} + + + +void *remove_forward_dependencies_c::handle_library_symbol(symbol_c *symbol, symbol_c *name, symbol_c *search1, symbol_c *search2, symbol_c *search3) { + if (inserted_symbols.find(symbol) != inserted_symbols.end()) return NULL; // already previously inserted into new_tree and declared_identifiers. Do not handle again! + if ((search1 != NULL) && (search1->accept(*find_forward_dependencies) != NULL)) return NULL; // A forward depency has not yet been satisfied. Wait for a later iteration to try again! + if ((search2 != NULL) && (search2->accept(*find_forward_dependencies) != NULL)) return NULL; // A forward depency has not yet been satisfied. Wait for a later iteration to try again! + if ((search3 != NULL) && (search3->accept(*find_forward_dependencies) != NULL)) return NULL; // A forward depency has not yet been satisfied. Wait for a later iteration to try again! + /* no forward dependencies found => insert into new AST, and add to the 'defined identifiers' and 'inserted symbol' lists */ + if (declared_identifiers.find_value(name) == declared_identifiers.end_value()) + declared_identifiers.insert(name, NULL); // only add if not yet in the symbol table (an overloaded version of this same POU could have been inderted previously!) + inserted_symbols.insert(symbol); + new_tree->add_element(current_code_generation_pragma); + new_tree->add_element(symbol); + return NULL; +} + + +/* Tell the user that the source code contains a circular dependency */ +void remove_forward_dependencies_c::print_circ_error(library_c *symbol) { + /* Note that we only print Functions and FBs, as Programs and Configurations cannot contain circular references due to syntax rules */ + /* Note too that circular references in derived datatypes is also not possible due to sytax! */ + int initial_error_count = error_count; + for (int i = 0; i < symbol->n; i++) + if ( (inserted_symbols.find(symbol->elements[i]) == inserted_symbols.end()) // if not copied to new AST + &&( (NULL != dynamic_cast (symbol->elements[i])) // and (is a FB + ||(NULL != dynamic_cast < function_declaration_c *>(symbol->elements[i])))) // or a Function) + STAGE3_ERROR(0, symbol->elements[i], symbol->elements[i], "POU (%s) contains a self-reference and/or belongs in a circular referencing loop", get_datatype_info_c::get_id_str(symbol->elements[i])); + if (error_count == initial_error_count) ERROR; // We were unable to determine which POUs contain the circular references!! +} + + +/***************************/ +/* B 0 - Programming Model */ +/***************************/ +/* enumvalue_symtable is filled in by enum_declaration_check_c, during stage3 semantic verification, with a list of all enumerated constants declared inside this POU */ +// SYM_LIST(library_c, enumvalue_symtable_t enumvalue_symtable;) +void *remove_forward_dependencies_c::visit(library_c *symbol) { + /* this method is the expected entry point for this visitor, and implements the main algorithm of the visitor */ + + /* first insert all the derived datatype declarations, in the same order by which they are delcared in the original AST */ + /* Since IEC 61131-3 does not allow FBs in arrays or structures, it is actually safe to place all the datatypes before all the POUs! */ + for (int i = 0; i < symbol->n; i++) + if (NULL != dynamic_cast (symbol->elements[i])) + new_tree->add_element(symbol->elements[i]); + + /* now do the POUs, in whatever order is necessary to guarantee no forward references. */ + long long int old_tree_pou_count = pou_count_c::get_count(symbol); + // if no code generation pragma exists before the first entry in the library, the default is to enable code generation. + enable_code_generation_pragma_c *default_code_generation_pragma = new enable_code_generation_pragma_c; + int prev_n; + cycle_count = 0; + do { + cycle_count++; + prev_n = new_tree->n; + current_code_generation_pragma = default_code_generation_pragma; + for (int i = 0; i < symbol->n; i++) symbol->elements[i]->accept(*this); + } while (prev_n != new_tree->n); // repeat while new elementns are still being added to the new AST + + if (old_tree_pou_count != pou_count_c::get_count(new_tree)) + print_circ_error(symbol); + + return NULL; +} + + +/**************************************/ +/* B.1.5 - Program organization units */ +/**************************************/ +/***********************/ +/* B 1.5.1 - Functions */ +/***********************/ +// SYM_REF4(function_declaration_c, derived_function_name, type_name, var_declarations_list, function_body, enumvalue_symtable_t enumvalue_symtable;) +void *remove_forward_dependencies_c::visit(function_declaration_c *symbol) + {return handle_library_symbol(symbol, symbol->derived_function_name, symbol->type_name, symbol->var_declarations_list, symbol->function_body);} +/*****************************/ +/* B 1.5.2 - Function Blocks */ +/*****************************/ +/* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */ +// SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body, enumvalue_symtable_t enumvalue_symtable;) +void *remove_forward_dependencies_c::visit(function_block_declaration_c *symbol) + {return handle_library_symbol(symbol, symbol->fblock_name, symbol->var_declarations, symbol->fblock_body);} +/**********************/ +/* B 1.5.3 - Programs */ +/**********************/ +/* PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */ +// SYM_REF3(program_declaration_c, program_type_name, var_declarations, function_block_body, enumvalue_symtable_t enumvalue_symtable;) +void *remove_forward_dependencies_c::visit(program_declaration_c *symbol) + {return handle_library_symbol(symbol, symbol->program_type_name, symbol->var_declarations, symbol->function_block_body);} +/********************************/ +/* B 1.7 Configuration elements */ +/********************************/ +/* CONFIGURATION configuration_name (...) END_CONFIGURATION */ +// SYM_REF5(configuration_declaration_c, configuration_name, global_var_declarations, resource_declarations, access_declarations, instance_specific_initializations, enumvalue_symtable_t enumvalue_symtable;) +void *remove_forward_dependencies_c::visit(configuration_declaration_c *symbol) + {return handle_library_symbol(symbol, symbol->configuration_name, symbol->global_var_declarations, symbol->resource_declarations, symbol->access_declarations);} +/********************/ +/* 2.1.6 - Pragmas */ +/********************/ +void *remove_forward_dependencies_c::visit(disable_code_generation_pragma_c *symbol) {current_code_generation_pragma = symbol; return NULL;} +void *remove_forward_dependencies_c::visit( enable_code_generation_pragma_c *symbol) {current_code_generation_pragma = symbol; return NULL;} +/* I have no ideia what this pragma is. Where should we place it in the re-ordered tree? + * Without knowing the semantics of the pragma, it is not possible to hande it correctly. + * We therefore print out an error message, and abort! + */ +// TODO: print error message! +void *remove_forward_dependencies_c::visit(pragma_c *symbol) { + if (1 != cycle_count) return NULL; // only handle unknown pragmas in the first cycle! + STAGE3_WARNING(symbol, symbol, "Unrecognized pragma. Including the pragma when using the '-p' command line option for 'allow use of forward references' may result in unwanted behaviour."); + new_tree->add_element(symbol); + return NULL; +} + + + + diff -r 27063736913f -r b05f63d9d0fa stage3/remove_forward_dependencies.hh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage3/remove_forward_dependencies.hh Wed Dec 10 11:57:43 2014 +0000 @@ -0,0 +1,115 @@ +/* + * matiec - a compiler for the programming languages defined in IEC 61131-3 + * + * Copyright (C) 2014 Mario de Sousa (msousa@fe.up.pt) + * + * 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) + * + */ + + +/* + * Re-oder the POUs in te library so that no forward references occur. + * + * Since stage1_2 now suppport POUs that contain references to POUS that are only declared later, + * (e.g. a variable of FB1_t is declared, before the FB1_T function block is itself declared!) + * we may need to re-order all the POUs in the library so that these forward references do not occur. + * + * This utility class will do just that. However, it does not destroy the original abstract syntax + * tree (AST). It instead creates a new re-ordered AST, by instantiating a new library_c object. + * This new library_c object will however point to the *same* objects of the original AST, just in + * a new order. + * This means that the new and original AST share all the object instances, and only use a distinct + * library_c object! + */ + +#include "../absyntax/absyntax.hh" +#include "../absyntax/visitor.hh" +#include "../util/symtable.hh" +#include + + +class find_forward_dependencies_c; +extern symbol_c remove_forward_dependencies_c_null_symbol; +typedef symtable_c identifiers_symbtable_t; + + + + + + + +class remove_forward_dependencies_c: public search_visitor_c { + + private: + /* The level of detail that the user wants us to display error messages. */ + #define error_level_default (1) + #define error_level_nagging (4) + unsigned int current_display_error_level; + int error_count; + bool warning_found; + library_c *new_tree; + int cycle_count; // main algorithm runs in a loop. The nuber of the current cycle... + // NOTE: we need two lists in order to correctly handle overloaded functions + identifiers_symbtable_t declared_identifiers; // list of identifiers already declared by the symbols in the new tree + std::set inserted_symbols; // list of symbols already inserted in the new tree + symbol_c *current_code_generation_pragma; // points to any currently 'active' enable_code_generation_pragma_c + find_forward_dependencies_c *find_forward_dependencies; + + public: + remove_forward_dependencies_c(void); + ~remove_forward_dependencies_c(void); + library_c *create_new_tree(symbol_c *old_tree); // create a new tree with POUs ordered so it does not contain forward dependencies... + int get_error_count(void); + + private: + void *handle_library_symbol(symbol_c *symbol, symbol_c *name, symbol_c *search1, symbol_c *search2 = NULL, symbol_c *search3 = NULL); + void print_circ_error(library_c *symbol); + + /***************************/ + /* B 0 - Programming Model */ + /***************************/ + void *visit(library_c *symbol); + /**************************************/ + /* B.1.5 - Program organization units */ + /**************************************/ + void *visit(function_declaration_c *symbol); + void *visit(function_block_declaration_c *symbol); + void *visit(program_declaration_c *symbol); + /********************************/ + /* B 1.7 Configuration elements */ + /********************************/ + void *visit(configuration_declaration_c *symbol); + /********************/ + /* 2.1.6 - Pragmas */ + /********************/ + void *visit(disable_code_generation_pragma_c *symbol); + void *visit(enable_code_generation_pragma_c *symbol); + void *visit(pragma_c *symbol); + +}; /* class remove_forward_dependencies_c */ + + + diff -r 27063736913f -r b05f63d9d0fa stage3/stage3.cc --- a/stage3/stage3.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/stage3/stage3.cc Wed Dec 10 11:57:43 2014 +0000 @@ -44,6 +44,8 @@ #include "constant_folding.hh" #include "declaration_check.hh" #include "enum_declaration_check.hh" +#include "remove_forward_dependencies.hh" + static int enum_declaration_check(symbol_c *tree_root){ @@ -114,7 +116,26 @@ } -int stage3(symbol_c *tree_root){ + +/* Removing forward dependencies only makes sense when stage1_2 is run with the pre-parsing option. + * This algorithm has no dependencies on other stage 3 algorithms. + * Typically this is run last, just to show that the remaining algorithms also do not depend on the fact that + * the library_c (i.e. the source code) does not contain forward dependencies. + */ +static int remove_forward_dependencies(symbol_c *tree_root, symbol_c **ordered_tree_root) { + if (NULL != ordered_tree_root) *ordered_tree_root = tree_root; // by default, consider tree_root already ordered + if (!runtime_options.pre_parsing) return 0; // No re-ordering necessary, just return + + /* We need to re-order the elements in the library, to fix any forward references! */ + remove_forward_dependencies_c remove_forward_dependencies; + symbol_c *new_tree_root = remove_forward_dependencies.create_new_tree(tree_root); + if (NULL == new_tree_root) ERROR; + if (NULL != ordered_tree_root) *ordered_tree_root = new_tree_root; + return remove_forward_dependencies.get_error_count(); +} + + +int stage3(symbol_c *tree_root, symbol_c **ordered_tree_root) { int error_count = 0; error_count += enum_declaration_check(tree_root); error_count += declaration_safety(tree_root); @@ -123,6 +144,7 @@ error_count += type_safety(tree_root); error_count += lvalue_check(tree_root); error_count += array_range_check(tree_root); + error_count += remove_forward_dependencies(tree_root, ordered_tree_root); if (error_count > 0) { fprintf(stderr, "%d error(s) found. Bailing out!\n", error_count); diff -r 27063736913f -r b05f63d9d0fa stage3/stage3.hh --- a/stage3/stage3.hh Sat Nov 22 19:30:47 2014 +0000 +++ b/stage3/stage3.hh Wed Dec 10 11:57:43 2014 +0000 @@ -36,6 +36,6 @@ #include "../util/symtable.hh" -int stage3(symbol_c *tree_root); +int stage3(symbol_c *tree_root, symbol_c **ordered_tree_root); #endif /* _STAGE3_HH */ diff -r 27063736913f -r b05f63d9d0fa stage4/generate_c/generate_c.cc --- a/stage4/generate_c/generate_c.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/stage4/generate_c/generate_c.cc Wed Dec 10 11:57:43 2014 +0000 @@ -1614,13 +1614,10 @@ /*******************************************/ /* B 1.1 - Letters, digits and identifiers */ /*******************************************/ - void *visit(identifier_c *symbol) { - if (configuration_name) - s4o.print(symbol->value); - else - generate_c_base_c::visit(symbol); - return NULL; + if (configuration_name) s4o.print(symbol->value); + else generate_c_base_c::visit(symbol); + return NULL; } /********************/ @@ -1821,8 +1818,11 @@ print_retain(); s4o.print(");\n"); break; - case run_dt: - current_program_name = ((identifier_c*)(symbol->program_name))->value; + case run_dt: + { identifier_c *tmp_id = dynamic_cast(symbol->program_name); + if (NULL == tmp_id) ERROR; + current_program_name = tmp_id->value; + } if (symbol->task_name != NULL) { s4o.print(s4o.indent_spaces); s4o.print("if ("); @@ -2144,10 +2144,11 @@ /*******************************************/ /* B 1.1 - Letters, digits and identifiers */ /*******************************************/ - void *visit(identifier_c *symbol) { - current_name = symbol->value; - return NULL; - } + void *visit(identifier_c *symbol) {current_name = symbol->value; return NULL;} + /* In the derived datatype and POUs declarations, the names are stored as identfier_c, so the following visitors are not required! */ + void *visit(derived_datatype_identifier_c *symbol) {ERROR; return NULL;} + void *visit( poutype_identifier_c *symbol) {ERROR; return NULL;} + /********************************/ /* B 1.3.3 - Derived data types */ @@ -2167,6 +2168,9 @@ /**************************************/ /* B.1.5 - Program organization units */ /**************************************/ +/* WARNING: The following code is buggy when generating an independent pair of files for each POU, as the + * specially created stage4out_c (s4o_c and s4o_h) will not comply with the enable/disable_code_generation_pragma_c + */ #define handle_pou(fname,pname) \ if (!allow_output) return NULL;\ if (generate_pou_filepairs__) {\ diff -r 27063736913f -r b05f63d9d0fa stage4/generate_c/generate_c_base.cc --- a/stage4/generate_c/generate_c_base.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/stage4/generate_c/generate_c_base.cc Wed Dec 10 11:57:43 2014 +0000 @@ -327,7 +327,8 @@ /*******************************************/ /* B 1.1 - Letters, digits and identifiers */ /*******************************************/ - void *visit(identifier_c *symbol) {return print_token(symbol);} + void *visit( identifier_c *symbol) {return print_token(symbol);} + void *visit( poutype_identifier_c *symbol) {return print_token(symbol);} /* If you need the derived_datatype_identifier_c visitor, then you should probably be * inheriting from generate_c_base_and_typeid_c and not generate_c_base_c !! */ @@ -951,7 +952,7 @@ if (1 < implicit_id_count) ERROR; if (1 == implicit_id_count) return symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(*this); - return symbol->ref_spec->accept(*this); // this is probably pointing to an identifier_c !! + return symbol->ref_spec->accept(*this); // this is probably pointing to an ***_identifier_c !! } /* ref_type_decl: identifier ':' ref_spec_init */ diff -r 27063736913f -r b05f63d9d0fa stage4/generate_c/generate_c_typedecl.cc --- a/stage4/generate_c/generate_c_typedecl.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/stage4/generate_c/generate_c_typedecl.cc Wed Dec 10 11:57:43 2014 +0000 @@ -233,23 +233,33 @@ * This method of handling arrays is needed when the relaxed datatype model is used * (see get_datatype_info_c for explanation on the relaxed datatype model). */ -/* Notice that this class inherits from generate_c_base_c, and not from generate_c_base_and_typeid_c. - * This is intentional! - * Whenever this class needs to print out the id of a datatype, it will explicitly use a private instance - * (generate_c_typeid) of generate_c_base_and_typeid_c! +/* The generate_c_typedecl_c inherits from generate_c_base_and_typeid_c because it will need the visitor's() to + * identifier_c, derived_datatype_identifier_c, and enumerated_value_c */ -class generate_c_typedecl_c: public generate_c_base_c { +class generate_c_typedecl_c: public generate_c_base_and_typeid_c { protected: + /* The following member variable is completely useless - the s4o variable inherited from generate_c_base_and_typeid_c + * could be used to the same effect. We keep it here merely because this generate_c_typedecl_c will typically be called + * with s4o referencing an include file (typically POUS.h), and using s4o_incl throughout this code will help the reader + * of the code to keep this fact in mind. + */ stage4out_c &s4o_incl; private: symbol_c* current_type_name; + std::map datatypes_already_defined; + /* Although this generate_c_typedecl_c inherits directly from generate_c_base_and_typeid_c, we still need an independent + * instance of that base class. This is because generate_c_typedecl_c will overload some of the visitors in the base class + * generate_c_base_and_typeid_c. + * When we want the to use the version of these visitors() in generate_c_typedecl_c, we call accept(*this); + * When we want the to use the version of these visitors() in generate_c_base_and_typeid_c, we call accept(*generate_c_typeid); + */ generate_c_base_and_typeid_c *generate_c_typeid; - std::map datatypes_already_defined; + public: - generate_c_typedecl_c(stage4out_c *s4o_ptr): generate_c_base_c(s4o_ptr), s4o_incl(*s4o_ptr) /*, generate_c_print_typename(s4o_ptr) */{ + generate_c_typedecl_c(stage4out_c *s4o_ptr): generate_c_base_and_typeid_c(s4o_ptr), s4o_incl(*s4o_ptr) /*, generate_c_print_typename(s4o_ptr) */{ current_typedefinition = none_td; current_basetypedeclaration = none_bd; current_type_name = NULL; @@ -281,18 +291,16 @@ void *print_list_incl(list_c *list, std::string pre_elem_str = "", std::string inter_elem_str = "", - std::string post_elem_str = "", - visitor_c *visitor = NULL) { - if (visitor == NULL) visitor = this; + std::string post_elem_str = "") { if (list->n > 0) { s4o_incl.print(pre_elem_str); - list->elements[0]->accept(*visitor); + list->elements[0]->accept(*this); } for(int i = 1; i < list->n; i++) { s4o_incl.print(inter_elem_str); - list->elements[i]->accept(*visitor); + list->elements[i]->accept(*this); } if (list->n > 0) @@ -368,12 +376,12 @@ current_type_name->accept(*generate_c_typeid); s4o_incl.print(","); current_basetypedeclaration = subrangebasetype_bd; - symbol->subrange_spec_init->accept(*this); + symbol->subrange_spec_init->accept(*this); // always calls subrange_spec_init_c current_basetypedeclaration = none_bd; s4o_incl.print(")\n"); current_basetypedeclaration = subrangetest_bd; - symbol->subrange_spec_init->accept(*this); + symbol->subrange_spec_init->accept(*this); // always calls subrange_spec_init_c current_basetypedeclaration = none_bd; current_type_name = NULL; @@ -385,7 +393,7 @@ /* subrange_specification ASSIGN signed_integer */ void *visit(subrange_spec_init_c *symbol) { TRACE("subrange_spec_init_c"); - symbol->subrange_specification->accept(*this); + symbol->subrange_specification->accept(*this); // always calls subrange_specification_c return NULL; } @@ -421,7 +429,7 @@ } */ - symbol->subrange->accept(*this); + symbol->subrange->accept(*this); // always calls subrange_c s4o_incl.indent_left(); s4o_incl.print("}\n"); @@ -454,7 +462,7 @@ s4o_incl.print("]"); } else - symbol->lower_limit->accept(*this); + symbol->lower_limit->accept(*this); // always calls neg_integer_c or integer_c break; case subrange_td: s4o_incl.print(s4o_incl.indent_spaces + "if (value < "); @@ -494,7 +502,7 @@ current_type_name->accept(*generate_c_typeid); s4o_incl.print(",\n"); s4o_incl.indent_right(); - symbol->enumerated_spec_init->accept(*this); + symbol->enumerated_spec_init->accept(*this); // always calls enumerated_spec_init_c s4o_incl.indent_left(); s4o_incl.print(")\n"); @@ -508,7 +516,7 @@ void *visit(enumerated_spec_init_c *symbol) { TRACE("enumerated_spec_init_c"); if (current_typedefinition == enumerated_td) - symbol->enumerated_specification->accept(*this); + symbol->enumerated_specification->accept(*this); // always calls enumerated_value_list_c or derived_datatype_identifier_c else symbol->enumerated_specification->accept(*generate_c_typeid); return NULL; @@ -518,7 +526,7 @@ /* enumerated_value_list ',' enumerated_value */ void *visit(enumerated_value_list_c *symbol) { TRACE("enumerated_value_list_c"); - print_list_incl(symbol, s4o_incl.indent_spaces, ",\n"+s4o_incl.indent_spaces, "\n"); + print_list_incl(symbol, s4o_incl.indent_spaces, ",\n"+s4o_incl.indent_spaces, "\n"); // will always call enumerated_value_c return NULL; } @@ -531,7 +539,7 @@ void *visit(array_type_declaration_c *symbol) { TRACE("array_type_declaration_c"); - // NOTE: remeber that symbol->array_spec_init may point to an identifier_c, which is why we use symbol->array_spec_init->datatype instead! + // NOTE: remeber that symbol->array_spec_init may point to a derived_datatype_identifier_c, which is why we use symbol->array_spec_init->datatype instead! if (NULL == symbol->array_spec_init->datatype) ERROR; identifier_c *id = generate_datatypes_aliasid_c::create_id(symbol->array_spec_init->datatype); @@ -553,7 +561,7 @@ s4o_incl.print("__DECLARE_ARRAY_TYPE("); current_type_name->accept(*generate_c_typeid); s4o_incl.print(","); - symbol->array_spec_init->accept(*this); + symbol->array_spec_init->accept(*this); // always calls array_spec_init_c s4o_incl.print(")\n"); current_type_name = NULL; @@ -573,7 +581,7 @@ /* array_initialization may be NULL ! */ void *visit(array_spec_init_c *symbol) { TRACE("array_spec_init_c"); - symbol->array_specification->accept(*this); + symbol->array_specification->accept(*this); // always calls array_specification_c or derived_datatype_identifier_c return NULL; } @@ -584,7 +592,7 @@ symbol->non_generic_type_name->accept(/*generate_c_print_typename*/*generate_c_typeid); s4o_incl.print(","); current_basetypedeclaration = arraysubrange_bd; - symbol->array_subrange_list->accept(*this); + symbol->array_subrange_list->accept(*this); // always calls array_subrange_list_c, which the iterator_visitor_c base class will call subrange_c current_basetypedeclaration = none_bd; return NULL; } @@ -593,7 +601,7 @@ /* TYPE type_declaration_list END_TYPE */ void *visit(data_type_declaration_c *symbol) { TRACE("data_type_declaration_c"); - symbol->type_declaration_list->accept(*this); + symbol->type_declaration_list->accept(*this); // will always call type_declaration_list_c s4o_incl.print("\n\n"); return NULL; } @@ -601,7 +609,7 @@ /* helper symbol for data_type_declaration */ void *visit(type_declaration_list_c *symbol) { TRACE("type_declaration_list_c"); - return print_list_incl(symbol, "", "\n", "\n"); + return print_list_incl(symbol, "", "\n", "\n"); // will always call string_type_declaration_c, structure_type_declaration_c, array_type_declaration_c, simple_type_declaration_c, subrange_type_declaration_c, enumerated_type_declaration_c, ref_type_decl_c } /* simple_type_name ':' simple_spec_init */ @@ -611,14 +619,14 @@ s4o_incl.print("__DECLARE_DERIVED_TYPE("); symbol->simple_type_name->accept(*generate_c_typeid); s4o_incl.print(","); - symbol->simple_spec_init->accept(*this); + symbol->simple_spec_init->accept(*this); // always calls simple_spec_init_c s4o_incl.print(")\n"); if (get_datatype_info_c::is_subrange(symbol->simple_type_name)) { s4o_incl.print("#define __CHECK_"); current_type_name->accept(*generate_c_typeid); s4o_incl.print(" __CHECK_"); - symbol->simple_spec_init->accept(*this); + symbol->simple_spec_init->accept(*this); // always calls simple_spec_init_c s4o_incl.print("\n"); } @@ -694,7 +702,7 @@ s4o_incl.print("__DECLARE_STRUCT_TYPE("); symbol->structure_type_name->accept(*generate_c_typeid); s4o_incl.print(","); - symbol->structure_specification->accept(*this); + symbol->structure_specification->accept(*this); // always calls initialized_structure_c or structure_element_declaration_list s4o_incl.print(")\n"); current_typedefinition = none_td; @@ -721,7 +729,7 @@ s4o_incl.indent_right(); s4o_incl.print(s4o_incl.indent_spaces); - print_list_incl(symbol, "", s4o_incl.indent_spaces, ""); + print_list_incl(symbol, "", s4o_incl.indent_spaces, ""); // will always call structure_element_declaration_c s4o_incl.indent_left(); s4o_incl.print(s4o_incl.indent_spaces); @@ -863,9 +871,12 @@ * we will keep track of the datatypes that have already been declared, and henceforth * only declare the datatypes that have not been previously defined. */ - if (datatypes_already_defined.find(((identifier_c *)(symbol->ref_type_name))->value) != datatypes_already_defined.end()) + identifier_c *tmp_id; + tmp_id = dynamic_cast(symbol->ref_type_name); + if (NULL == tmp_id) ERROR; + if (datatypes_already_defined.find(tmp_id->value) != datatypes_already_defined.end()) return NULL; // already defined. No need to define it again!! - datatypes_already_defined[((identifier_c *)(symbol->ref_type_name))->value] = 1; // insert this datatype into the list of already defined arrays! + datatypes_already_defined[tmp_id->value] = 1; // insert this datatype into the list of already defined arrays! current_type_name = NULL; current_typedefinition = none_td; @@ -873,7 +884,7 @@ s4o_incl.print("__DECLARE_REFTO_TYPE("); symbol->ref_type_name->accept(*generate_c_typeid); s4o_incl.print(", "); - symbol->ref_spec_init->accept(*this); + symbol->ref_spec_init->accept(*this); // always calls ref_spec_init_c s4o_incl.print(")\n"); current_type_name = NULL; @@ -897,7 +908,7 @@ TRACE("direct_variable_c"); /* Do not use print_token() as it will change everything into uppercase */ if (strlen(symbol->value) == 0) ERROR; - return s4o.printlocation(symbol->value + 1); + return s4o_incl.printlocation(symbol->value + 1); } @@ -1066,7 +1077,7 @@ /* NOTE: ref_initialization may be NULL!! */ // SYM_REF2(ref_spec_init_c, ref_spec, ref_initialization) void *visit(ref_spec_init_c *symbol) { - symbol->ref_spec->accept(*this); + symbol->ref_spec->accept(*this); //--> always calls ref_spec_c or derived_datatype_identifier_c int implicit_id_count = symbol->ref_spec->anotations_map.count("generate_c_annotaton__implicit_type_id"); if (implicit_id_count > 1) ERROR; if (implicit_id_count == 1) @@ -1087,7 +1098,7 @@ /* array_specification [ASSIGN array_initialization] */ /* array_initialization may be NULL ! */ void *visit(array_spec_init_c *symbol) { - symbol->array_specification->accept(*this); + symbol->array_specification->accept(*this); //--> always calls array_specification_c or derived_datatype_identifier_c int implicit_id_count = symbol->array_specification->anotations_map.count("generate_c_annotaton__implicit_type_id"); if (implicit_id_count > 1) ERROR; if (implicit_id_count == 1) @@ -1130,7 +1141,7 @@ /***********************/ void *visit(function_declaration_c *symbol) { prefix = symbol->derived_function_name; - symbol->var_declarations_list->accept(*this); + symbol->var_declarations_list->accept(*this); //--> always calls var_declarations_list_c prefix = NULL; return NULL; } @@ -1139,7 +1150,7 @@ /*****************************/ void *visit(function_block_declaration_c *symbol) { prefix = symbol->fblock_name; - symbol->var_declarations->accept(*this); + symbol->var_declarations->accept(*this); //--> always calls var_declarations_list_c prefix = NULL; return NULL; } @@ -1148,7 +1159,7 @@ /**********************/ void *visit(program_declaration_c *symbol) { prefix = symbol->program_type_name; - symbol->var_declarations->accept(*this); + symbol->var_declarations->accept(*this); //--> always calls var_declarations_list_c prefix = NULL; return NULL; } diff -r 27063736913f -r b05f63d9d0fa stage4/generate_c/generate_c_vardecl.cc --- a/stage4/generate_c/generate_c_vardecl.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/stage4/generate_c/generate_c_vardecl.cc Wed Dec 10 11:57:43 2014 +0000 @@ -59,7 +59,7 @@ }; -// Does this class really need to derive from generate_c_typedecl_c ??? + class generate_c_array_initialization_c: public generate_c_base_and_typeid_c { public: @@ -194,7 +194,6 @@ /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */ void *visit(array_specification_c *symbol) { - identifier_c* type_name; switch (current_mode) { case arraysize_am: symbol->array_subrange_list->accept(*this); diff -r 27063736913f -r b05f63d9d0fa stage4/generate_c/generate_var_list.cc --- a/stage4/generate_c/generate_var_list.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/stage4/generate_c/generate_var_list.cc Wed Dec 10 11:57:43 2014 +0000 @@ -90,7 +90,10 @@ /***********************************************************************/ /***********************************************************************/ - +/* TODO: Delete this helper class search_type_symbol_c, as well as the search_fb_typedecl_c + * in the absyntac_utils directory. They are no longer usefull, now that we have + * datatype analysis working! + */ class search_type_symbol_c: public iterator_visitor_c { public: @@ -143,7 +146,23 @@ return (this->current_var_type_name); } - void *visit(identifier_c* symbol) { + void *visit(derived_datatype_identifier_c* symbol) { + if (this->current_var_type_name == NULL) { + this->current_var_type_name = symbol; + + this->current_var_type_symbol = search_fb_typedecl->get_decl(this->current_var_type_name); + if (this->current_var_type_symbol != NULL) + this->current_var_type_category = function_block_vtc; + + else { + this->current_var_type_symbol = search_base_type_c::get_basetype_decl(this->current_var_type_name); + this->current_var_type_symbol->accept(*this); + } + } + return NULL; + } + + void *visit(poutype_identifier_c* symbol) { if (this->current_var_type_name == NULL) { this->current_var_type_name = symbol; diff -r 27063736913f -r b05f63d9d0fa stage4/generate_iec/generate_iec.cc --- a/stage4/generate_iec/generate_iec.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/stage4/generate_iec/generate_iec.cc Wed Dec 10 11:57:43 2014 +0000 @@ -255,6 +255,7 @@ /*******************************************/ void *visit( identifier_c *symbol) {return print_token(symbol);} void *visit(derived_datatype_identifier_c *symbol) {return print_token(symbol);} +void *visit( poutype_identifier_c *symbol) {return print_token(symbol);} /*********************/ /* B 1.2 - Constants */ diff -r 27063736913f -r b05f63d9d0fa util/symtable.cc --- a/util/symtable.cc Sat Nov 22 19:30:47 2014 +0000 +++ b/util/symtable.cc Wed Dec 10 11:57:43 2014 +0000 @@ -116,12 +116,13 @@ } // std::cout << "store_identifier(" << identifier_str << "): \n"; + iterator i = _base.find(identifier_str); + if ((i != _base.end()) && (i->second != new_value)) {ERROR;} /* error inserting new identifier: identifier already in map associated to a different value */ + if ((i != _base.end()) && (i->second == new_value)) {return;} /* identifier already in map associated with the same value */ + std::pair new_element(identifier_str, new_value); std::pair res = _base.insert(new_element); - if (!res.second) - /* error inserting new identifier... */ - /* identifier already in map? */ - ERROR; + if (!res.second) {ERROR;} /* unknown error inserting new identifier */ } template diff -r 27063736913f -r b05f63d9d0fa util/symtable.hh --- a/util/symtable.hh Sat Nov 22 19:30:47 2014 +0000 +++ b/util/symtable.hh Wed Dec 10 11:57:43 2014 +0000 @@ -96,18 +96,21 @@ value_t find_value(const char *identifier_str); value_t find_value(const symbol_c *symbol); - iterator find(const char *identifier_str) {return _base.find(identifier_str);} - /* iterators pointing to beg/end of map... */ - iterator begin() {return _base.begin();} - const_iterator begin() const {return _base.begin();} - iterator end() {return _base.end();} - const_iterator end() const {return _base.end();} - reverse_iterator rbegin() {return _base.rbegin();} - const_reverse_iterator rbegin() const {return _base.rbegin();} - reverse_iterator rend() {return _base.rend();} - const_reverse_iterator rend() const {return _base.rend();} - + /* iterators ... */ + /* NOTE: These member functions are incorrect, as the returned iterator will not iterate through the inner_scopes!! */ + /* We simply comment it all out, as they are not currently needed! */ + #if 0 + iterator find (const char *identifier_str) {return _base.find(identifier_str);} + iterator begin() {return _base.begin();} + const_iterator begin() const {return _base.begin();} + iterator end() {return _base.end();} + const_iterator end() const {return _base.end();} + reverse_iterator rbegin() {return _base.rbegin();} + const_reverse_iterator rbegin() const {return _base.rbegin();} + reverse_iterator rend() {return _base.rend();} + const_reverse_iterator rend() const {return _base.rend();} + #endif /* debuging function... */ void print(void); };