merge
authormjsousa
Wed, 10 Dec 2014 11:57:43 +0000
changeset 961 b05f63d9d0fa
parent 959 8bfcc8e62bd6 (diff)
parent 960 27063736913f (current diff)
child 962 98e7a0d3af21
merge
stage1_2/iec_bison.yy
--- 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);
 };