--- 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( \
--- 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)
/*********************/
--- 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);
};
--- 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<identifier_c *>(current_fcall_name);
- if (identifier == NULL) ERROR;
- return identifier;
+token_c *function_call_iterator_c::fname(void) {
+ token_c *fname_sym = dynamic_cast<token_c *>(current_fcall_name);
+ if (fname_sym == NULL) ERROR;
+ return fname_sym;
}
--- 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:
/***************************************/
--- 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;
--- 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-/****
- * 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;
-}
-
--- 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);}
/*********************/
--- 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 */
/*********************/
--- 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;
+
}
--- 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 */
--- 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 */
--- 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 */
--- 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 */
--- 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 */
--- 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 */
--- 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 */
/**********************/
--- 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 <leaf> prev_declared_resource_name
%token <ID> prev_declared_resource_name_token
+%type <leaf> prev_declared_configuration_name
%token <ID> prev_declared_configuration_name_token
// %type <leaf> 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<poutype_identifier_c*>($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<poutype_identifier_c*>($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<poutype_identifier_c*>($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<poutype_identifier_c*>($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<poutype_identifier_c*>($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<poutype_identifier_c*>($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<poutype_identifier_c*>($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<poutype_identifier_c*>($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;
--- 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 <vardecl_state> 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;
+}
+
+<get_pou_name_state>{
+{identifier} BEGIN(ignore_pou_state); yylval.ID=strdup(yytext); return identifier_token;
+. BEGIN(ignore_pou_state); unput_text(0);
+}
+
+<ignore_pou_state>{
+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) */
<vardecl_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_state>{il_whitespace} /* Eat any whitespace */
/* The comments */
-<body_state,vardecl_list_state>{comment_beg} yy_push_state(comment_state);
+<get_pou_name_state,ignore_pou_state,body_state,vardecl_list_state>{comment_beg} yy_push_state(comment_state);
{comment_beg} yy_push_state(comment_state);
<comment_state>{
{comment_beg} {if (get_opt_nested_comments()) yy_push_state(comment_state);}
--- 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. */
--- 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. */
--- 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
--- 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);}
--- 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;
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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<library_c *>(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 <function_block_declaration_c *>(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 <data_type_declaration_c *>(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;
+}
+
+
+
+
--- /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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * 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 <set>
+
+
+class find_forward_dependencies_c;
+extern symbol_c remove_forward_dependencies_c_null_symbol;
+typedef symtable_c<symbol_c *, &remove_forward_dependencies_c_null_symbol> 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 <symbol_c *> 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 */
+
+
+
--- 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);
--- 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 */
--- 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<identifier_c*>(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__) {\
--- 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 */
--- 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<std::string, int> 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<std::string, int> 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<identifier_c *>(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;
}
--- 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);
--- 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;
--- 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 */
--- 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<const char *, value_t> new_element(identifier_str, new_value);
std::pair<iterator, bool> 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<typename value_type, value_type null_value>
--- 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);
};