Merge with c2546c6e0cfa5ad55b288895f17f1b9f2a228f3b
authorLaurent Bessard
Wed, 22 Aug 2012 16:46:17 +0200
changeset 625 c0bda77b37a0
parent 412 aad38592bdde (current diff)
parent 624 c2546c6e0cfa (diff)
child 626 9f2cefb98e60
Merge with c2546c6e0cfa5ad55b288895f17f1b9f2a228f3b
absyntax_utils/function_type_decl.h
absyntax_utils/get_function_type.cc
absyntax_utils/get_function_type.h
absyntax_utils/search_base_type.cc
absyntax_utils/search_base_type.hh
absyntax_utils/search_var_instance_decl.cc
absyntax_utils/search_varfb_instance_type.cc
absyntax_utils/search_varfb_instance_type.hh
configure
lib/iec_std_lib.h
stage3/array_range_check.cc
stage3/visit_expression_type.cc
stage3/visit_expression_type.hh
stage4/generate_c/generate_c.cc
stage4/generate_c/generate_c_il.cc
stage4/generate_c/generate_c_inlinefcall.cc
stage4/generate_c/generate_c_st.cc
--- a/absyntax/absyntax.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax/absyntax.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -40,12 +40,7 @@
 #include "absyntax.hh"
 //#include "../stage1_2/iec.hh" /* required for BOGUS_TOKEN_ID, etc... */
 #include "visitor.hh"
-
-#define ERROR error_exit(__FILE__,__LINE__)
-/* function defined in main.cc */
-extern void error_exit(const char *file_name, int line_no);
-
-#define ABORT(str) {printf("ERROR: %s\n", str); ERROR;}
+#include "../main.hh" // required for ERROR() and ERROR_MSG() macros.
 
 
 
@@ -61,6 +56,11 @@
   this->last_line    = last_line;
   this->last_column  = last_column;
   this->last_order   = last_order;
+  this->datatype     = NULL;
+  this->const_value._real64.status   = cs_undefined;
+  this->const_value._int64.status    = cs_undefined;
+  this->const_value._uint64.status   = cs_undefined;
+  this->const_value._bool.status     = cs_undefined;
 }
 
 
@@ -101,7 +101,7 @@
   n++;
   elements = (symbol_c **)realloc(elements, n * sizeof(symbol_c *));
   if (elements == NULL)
-    ABORT("Out of memory");
+    ERROR_MSG("Out of memory");
   elements[n - 1] = elem;
  
   if (elem == NULL)
@@ -130,18 +130,27 @@
 /* To insert into the begining of list, call with pos=0  */
 /* To insert into the end of list, call with pos=list->n */
 void list_c::insert_element(symbol_c *elem, int pos) {
-  int i;
   if (pos > n) ERROR;
   
   /* add new element to end of list. Basically alocate required memory... */
   /* will also increment n by 1 ! */
   add_element(elem);
   /* if not inserting into end position, shift all elements up one position, to open up a slot in pos for new element */
-  if (pos < (n-1)) for (i = n-2; i >= pos; i--) elements[i+1] = elements[i];
+  if (pos < (n-1)) for (int i = n-2; i >= pos; i--) elements[i+1] = elements[i];
   elements[pos] = elem;
 }
 
 
+/* remove element at position pos. */
+void list_c::remove_element(int pos) {
+  if (pos > n) ERROR;
+  
+  /* Shift all elements down one position, starting at the entry to delete. */
+  for (int i = pos; i < n-1; i++) elements[i] = elements[i+1];
+  /* corrent the new size, and free unused memory */
+  n--;
+  elements = (symbol_c **)realloc(elements, n * sizeof(symbol_c *));
+}
 
 #define SYM_LIST(class_name_c, ...)								\
 class_name_c::class_name_c(									\
--- a/absyntax/absyntax.def	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax/absyntax.def	Wed Aug 22 16:46:17 2012 +0200
@@ -97,6 +97,12 @@
 SYM_REF0(eno_param_c)
 */
 
+/* A class used to identify an entry (literal, variable, etc...) in the abstract syntax tree with an invalid data type */
+/* This is only used from stage3 onwards. Stages 1 and 2 will never create any instances of invalid_type_name_c */
+SYM_REF0(invalid_type_name_c)
+
+
+
 /********************/
 /* 2.1.6 - Pragmas  */
 /********************/
@@ -158,34 +164,15 @@
  *                OR
  *          neg_literal_c -> real_literal_c
  *
- *      In the semantic verification and code generation stages of the compiler,
- *      the integer_c is treated as a basic (undefined) data type, since an integer
- *      constant may be used as a BYTE, BOOLEAN, REAL, etc..., depending on the
- *      context in which it is used.
- *      However, an integer_c that is preceded by a '-' may not be used
- *      as an ANY_BIT data type (BYTE, BOOLEAN, WORD, ...).
- *      We must therefore be able to determine, holding a simple pointer
- *      to an integer_c, if that integer_c value is preceded by a '-'.
- *      However, since the neg_literal_c points to the integer_c, and not
- *      vice-versa, we can't determine that.
- *      There are 3 simple ways of working around this:
- *        - change the order of the pointers: 
- *              have the integer_c and real_c point to the neg_literal_c
- *        - maintain the order of the pointers, and
- *              add redundant info to the integer_c and real_c
+ *       However, this has since been changed to...
  *        - replace the neg_literal_c with two distinc classes
  *              (neg_integer_c and neg_real_c), one for each
- *              lietral type. This means that we can now treat
- *              each of these classes as an unknown data type
- *              just as we do with the integer_c and real_c.
- *
- *      The second option is simply ugly.
- *      and the first has a serious drawback: when generating code it is
- *      easier to encapsulate the real or integer values inside prefix
- *      and postfix symbols (e.g. NEG(<value>) - with postfix ')' )
- *      if we keep the pointer order as is.
- *
- *      For the above reasoning, we use the third option.
+ *              lietral type. 
+ *
+ *       This change was done in order to ease the writing of semantic verification (stage3) code.
+ *       However, that version of the code has since been replaced by a newer and better algoritm.
+ *       This means the above change can now be undone, but there is really no need to undo it,
+ *       so we leave it as it is.
  */  
 SYM_REF1(neg_real_c, exp)
 SYM_REF1(neg_integer_c, exp)
@@ -223,13 +210,15 @@
 /************************/
 SYM_REF0(neg_time_c)
 SYM_REF3(duration_c, type_name, neg, interval)
+SYM_REF5(interval_c, days, hours, minutes, seconds, milliseconds)
 SYM_TOKEN(fixed_point_c)
+/*
 SYM_REF2(days_c, days, hours)
 SYM_REF2(hours_c, hours, minutes)
 SYM_REF2(minutes_c, minutes, seconds)
 SYM_REF2(seconds_c, seconds, milliseconds)
 SYM_REF1(milliseconds_c, milliseconds)
-
+*/
 
 /************************************/
 /* B 1.2.3.2 - Time of day and Date */
@@ -326,7 +315,8 @@
 SYM_REF2(subrange_specification_c, integer_type_name, subrange)
 
 /*  signed_integer DOTDOT signed_integer */
-SYM_REF2(subrange_c, lower_limit, upper_limit)
+/* dimension will be filled in during stage 3 (array_range_check_c) with the number of elements in this subrange */
+SYM_REF2(subrange_c, lower_limit, upper_limit, unsigned long long int dimension;)
 
 /*  enumerated_type_name ':' enumerated_spec_init */
 SYM_REF2(enumerated_type_declaration_c, enumerated_type_name, enumerated_spec_init)
@@ -476,8 +466,13 @@
 /*  record_variable '.' field_selector */
 /*  WARNING: input and/or output variables of function blocks
  *           may be accessed as fields of a structured variable!
- *           Code handling a structured_variable_c must take
- *           this into account!
+ *           Code handling a structured_variable_c must take this into account!
+ *           (i.e. that a FB instance may be accessed as a structured variable)!
+ *
+ *  WARNING: Status bit (.X) and activation time (.T) of STEPS in SFC diagrams
+ *           may be accessed as fields of a structured variable!
+ *           Code handling a structured_variable_c must take this into account 
+ *           (i.e. that an SFC STEP may be accessed as a structured variable)!
  */
 SYM_REF2(structured_variable_c, record_variable, field_selector)
 
@@ -913,18 +908,22 @@
 SYM_LIST(instruction_list_c)
 
 /* | label ':' [il_incomplete_instruction] eol_list */
-SYM_REF2(il_instruction_c, label, il_instruction)
+/* NOTE: The parameter 'prev_il_instruction' is used to point to all previous il instructions that may be executed imedaitely before this instruction.
+ *       In case of an il instruction preceded by a label, this will include all IL instructions that jump to this label!
+ *       It is filled in by the flow_control_analysis_c during stage 3.
+ */
+SYM_REF2(il_instruction_c, label, il_instruction, std::vector <symbol_c *> prev_il_instruction;)
 
 
 /* | il_simple_operator [il_operand] */
 SYM_REF2(il_simple_operation_c, il_simple_operator, il_operand)
 
 /* | function_name [il_operand_list] */
-/* NOTE: The parameters 'called_function_declaration' is used to pass 
+/* NOTE: The parameter 'called_function_declaration', 'extensible_param_count' and 'candidate_functions' are used to pass data between the stage 3 and stage 4.
  *       data between the stage 3 and stage 4.
  *       See the comment above function_invocation_c for more details 
  */
-SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;)
+SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count; std::vector <symbol_c *> candidate_functions;)
 
 
 /* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */
@@ -939,15 +938,15 @@
  * | il_call_operator prev_declared_fb_name '(' il_operand_list ')'
  * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')'
  */
-SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list)
+/* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */
+SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration;)
 
 
 /* | function_name '(' eol_list [il_param_list] ')' */
-/* NOTE: The parameters 'called_function_declaration' is used to pass 
- *       data between the stage 3 and stage 4.
- *       See the comment above function_invocation_c for more details 
- */
-SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;)
+/* NOTE: The parameter 'called_function_declaration', 'extensible_param_count' and 'candidate_functions' are used to pass data between the stage 3 and stage 4.
+ *       See the comment above function_invocation_c for more details. 
+ */
+SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count; std::vector <symbol_c *> candidate_functions;)
 
 /* | il_operand_list ',' il_operand */
 SYM_LIST(il_operand_list_c)
@@ -955,6 +954,15 @@
 /* | simple_instr_list il_simple_instruction */
 SYM_LIST(simple_instr_list_c)
 
+
+/* il_simple_instruction:
+ *   il_simple_operation eol_list
+ * | il_expression eol_list
+ * | il_formal_funct_call eol_list
+ */
+/* NOTE: The parameter 'prev_il_instruction' is used to point to all previous il instructions that may be executed imedaitely before this instruction. */
+SYM_REF1(il_simple_instruction_c, il_simple_instruction, std::vector <symbol_c *> prev_il_instruction;)
+
 /* | il_initial_param_list il_param_instruction */
 SYM_LIST(il_param_list_c)
 
@@ -971,31 +979,36 @@
 /*******************/
 /* B 2.2 Operators */
 /*******************/
+/* NOTE: The parameter 'called_fb_declaration' is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */
+/* NOTE: The parameter 'deprecated_operation' indicates that the operation, with the specific data types being used, is currently defined
+ *       in the standard as being deprecated. This variable is filled in with the correct value in stage 3 (narrow_candidate_datatypes_c) 
+ *       and currently only used in stage 3 (print_datatypes_error_c).
+ */ 
 SYM_REF0(LD_operator_c)
 SYM_REF0(LDN_operator_c)
 SYM_REF0(ST_operator_c)
 SYM_REF0(STN_operator_c)
 SYM_REF0(NOT_operator_c)
-SYM_REF0(S_operator_c)
-SYM_REF0(R_operator_c)
-SYM_REF0(S1_operator_c)
-SYM_REF0(R1_operator_c)
-SYM_REF0(CLK_operator_c)
-SYM_REF0(CU_operator_c)
-SYM_REF0(CD_operator_c)
-SYM_REF0(PV_operator_c)
-SYM_REF0(IN_operator_c)
-SYM_REF0(PT_operator_c)
+SYM_REF0(S_operator_c, symbol_c *called_fb_declaration;)
+SYM_REF0(R_operator_c, symbol_c *called_fb_declaration;)
+SYM_REF0(S1_operator_c, symbol_c *called_fb_declaration;)
+SYM_REF0(R1_operator_c, symbol_c *called_fb_declaration;)
+SYM_REF0(CLK_operator_c, symbol_c *called_fb_declaration;)
+SYM_REF0(CU_operator_c, symbol_c *called_fb_declaration;)
+SYM_REF0(CD_operator_c, symbol_c *called_fb_declaration;)
+SYM_REF0(PV_operator_c, symbol_c *called_fb_declaration;)
+SYM_REF0(IN_operator_c, symbol_c *called_fb_declaration;)
+SYM_REF0(PT_operator_c, symbol_c *called_fb_declaration;)
 SYM_REF0(AND_operator_c)
 SYM_REF0(OR_operator_c)
 SYM_REF0(XOR_operator_c)
 SYM_REF0(ANDN_operator_c)
 SYM_REF0(ORN_operator_c)
 SYM_REF0(XORN_operator_c)
-SYM_REF0(ADD_operator_c)
-SYM_REF0(SUB_operator_c)
-SYM_REF0(MUL_operator_c)
-SYM_REF0(DIV_operator_c)
+SYM_REF0(ADD_operator_c, bool deprecated_operation;)
+SYM_REF0(SUB_operator_c, bool deprecated_operation;)
+SYM_REF0(MUL_operator_c, bool deprecated_operation;)
+SYM_REF0(DIV_operator_c, bool deprecated_operation;)
 SYM_REF0(MOD_operator_c)
 SYM_REF0(GT_operator_c)
 SYM_REF0(GE_operator_c)
@@ -1036,10 +1049,10 @@
 SYM_REF2(gt_expression_c, l_exp, r_exp)
 SYM_REF2(le_expression_c, l_exp, r_exp)
 SYM_REF2(ge_expression_c, l_exp, r_exp)
-SYM_REF2(add_expression_c, l_exp, r_exp)
-SYM_REF2(sub_expression_c, l_exp, r_exp)
-SYM_REF2(mul_expression_c, l_exp, r_exp)
-SYM_REF2(div_expression_c, l_exp, r_exp)
+SYM_REF2(add_expression_c, l_exp, r_exp, bool deprecated_operation;)
+SYM_REF2(sub_expression_c, l_exp, r_exp, bool deprecated_operation;)
+SYM_REF2(mul_expression_c, l_exp, r_exp, bool deprecated_operation;)
+SYM_REF2(div_expression_c, l_exp, r_exp, bool deprecated_operation;)
 SYM_REF2(mod_expression_c, l_exp, r_exp)
 SYM_REF2(power_expression_c, l_exp, r_exp)
 SYM_REF1(neg_expression_c, exp)
@@ -1047,18 +1060,36 @@
 
 /*    formal_param_list -> may be NULL ! */
 /* nonformal_param_list -> may be NULL ! */
-/* NOTE: The parameters 'called_function_declaration' is used to pass 
- *        data between the stage 3 and stage 4.
+/* NOTES:
+ *    The parameter 'called_function_declaration'... 
+ *       ...is used to pass data between the stage 3 and stage 4.
  *       The IEC 61131-3 standard allows for overloaded standard functions. This means that some
- *       function calls are not compeletely defined by the name of the function being called,
+ *       function calls are not completely defined by the name of the function being called,
  *       and need to be disambiguated with using the data types of the parameters being passed.
- *       Stage 3 does this to verify semantic correctnes.
+ *       Stage 3 does this to verify semantic correctness.
  *       Stage 4 also needs to do this in order to determine which function to call.
  *       It does not make sense to determine the exact function being called twice (once in stage 3,
- *       and again in stage 4), so stage 3 will store this infor in the parameter called_function_declaration
+ *       and again in stage 4), so stage 3 will store this info in the parameter called_function_declaration
  *       for stage 4 to use it later on.
- */
-SYM_REF3(function_invocation_c, function_name, formal_param_list, nonformal_param_list, symbol_c *called_function_declaration; int extensible_param_count;)
+ *    The parameter 'candidate_functions'... 
+ *       ...is used to pass data between two passes within stage 3
+ *       (actually between fill_candidate_datatypes_c and narrow_candidate_datatypes_c).
+ *       It is used to store all the functions that may be legally called with the current parameters
+ *       being used in this function invocation. Note that the standard includes some standard functions
+ *       that have the exact same input parameter types, but return different data types.
+ *       In order to determine which of these functions should be called, we first create a list
+ *       of all possible functions, and then narrow down the list (hopefully down to 1 function)
+ *       once we know the data type that the function invocation must return (this will take into 
+ *       account the expression in which the function invocation is inserted/occurs).
+ *       The 'called_function_declaration' will eventually be set (in stage 3) to one of
+ *       the functions in the 'candidate_functions' list!
+ *    The parameter 'extensible_param_count'... 
+ *       ...is used to pass data between the stage 3 and stage 4.
+ *       The IEC 61131-3 standard allows for extensible standard functions. This means that some
+ *       standard functions may be called with a variable number of paramters. Stage 3 will store
+ *       in extensible_param_count the number of parameters being passed to the extensible parameter.
+ */
+SYM_REF3(function_invocation_c, function_name, formal_param_list, nonformal_param_list, symbol_c *called_function_declaration; int extensible_param_count; std::vector <symbol_c *> candidate_functions;)
 
 
 /********************/
@@ -1083,7 +1114,8 @@
 /* fb_name '(' [param_assignment_list] ')' */
 /*    formal_param_list -> may be NULL ! */
 /* nonformal_param_list -> may be NULL ! */
-SYM_REF3(fb_invocation_c, fb_name, formal_param_list, nonformal_param_list)
+/* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */
+SYM_REF3(fb_invocation_c, fb_name, formal_param_list, nonformal_param_list, symbol_c *called_fb_declaration;)
 
 /* helper symbol for fb_invocation */
 /* param_assignment_list ',' param_assignment */
--- a/absyntax/absyntax.hh	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax/absyntax.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -47,9 +47,16 @@
 
 
 #include <stdio.h> // required for NULL
+#include <vector>
+#include <string>
+#include <stdint.h>  // required for uint64_t, etc...
+#include "../main.hh" // required for uint8_t, real_64_t, ..., and the macros INT8_MAX, REAL32_MAX, ... */
+
+
+
 
 /* Forward declaration of the visitor interface
- * dclared in the visitor.hh file
+ * declared in the visitor.hh file
  * We cannot include the visitor.hh file, as it will
  * include this same file first, as it too requires references
  * to the abstract syntax classes defined here.
@@ -61,12 +68,21 @@
 
 
 
+
+
+
+
+
+
+
+
 /* The base class of all symbols */
 class symbol_c {
 
   public:
     /*
-     * Line number for the purposes of error checking
+     * Line number for the purposes of error checking.
+     * Annotated (inserted) by stage1_2
      */
     int first_line;
     int first_column;
@@ -77,6 +93,49 @@
     const char *last_file;  /* filename referenced by last line/column */
     long int last_order;    /* relative order in which it is read by lexcial analyser */
 
+
+    /*
+     * Annotations produced during stage 3
+     */
+    /*** Data type analysis ***/
+    std::vector <symbol_c *> candidate_datatypes; /* All possible data types the expression/literal/etc. may take. Filled in stage3 by fill_candidate_datatypes_c class */
+    /* Data type of the expression/literal/etc. Filled in stage3 by narrow_candidate_datatypes_c 
+     * If set to NULL, it means it has not yet been evaluated.
+     * If it points to an object of type invalid_type_name_c, it means it is invalid.
+     * Otherwise, it points to an object of the apropriate data type (e.g. int_type_name_c, bool_type_name_c, ...)
+     */
+    symbol_c *datatype;
+
+    /*** constant folding ***/
+    /* During stage 3 (semantic analysis/checking) we will be doing constant folding.
+     * That algorithm will anotate the abstract syntax tree with the result of operations
+     * on literals (i.e. 44 + 55 will store the result 99).
+     * Since the same source code (e.g. 1 + 0) may actually be a BOOL or an ANY_INT,
+     * or an ANY_BIT, we need to handle all possibilities, and determine the result of the
+     * operation assuming each type.
+     * For this reason, we have one entry for each possible type, with some expressions
+     * having more than one entry filled in!
+     */
+    typedef enum { cs_undefined,   /* not defined/not yet evaluated --> const_value is not valid! */
+                   cs_non_const,   /* we have deternmined that expression is not a const value --> const_value is not valid! */
+                   cs_const_value, /* const value is valid */
+                   cs_overflow     /* result produced overflow or underflow --> const_value is not valid! */
+                 } const_status_t;
+ 
+    typedef struct {const_status_t status;  real64_t  value; } const_value_real64_t;
+    typedef struct {const_status_t status;   int64_t  value; } const_value_int64_t;
+    typedef struct {const_status_t status;  uint64_t  value; } const_value_uint64_t;
+    typedef struct {const_status_t status;      bool  value; } const_value_bool_t;
+
+    typedef struct {
+      const_value_real64_t _real64; /* status is initialised to UNDEFINED */
+      const_value_int64_t   _int64; /* status is initialised to UNDEFINED */
+      const_value_uint64_t _uint64; /* status is initialised to UNDEFINED */
+      const_value_bool_t     _bool; /* status is initialised to UNDEFINED */
+    } const_value_t;
+    const_value_t const_value;
+    
+
   public:
     /* default constructor */
     symbol_c(int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, /* order in which it is read by lexcial analyser */
@@ -125,12 +184,14 @@
      /* To insert into the begining of list, call with pos=0  */
      /* To insert into the end of list, call with pos=list->n */
     virtual void insert_element(symbol_c *elem, int pos = 0);
-};
-
-
-
-
-#define SYM_LIST(class_name_c, ...)												\
+     /* remove element at position pos. */
+    virtual void remove_element(int pos = 0);
+};
+
+
+
+
+#define SYM_LIST(class_name_c, ...)											\
 class class_name_c:	public list_c {											\
   public:														\
     __VA_ARGS__														\
@@ -145,7 +206,7 @@
 };
 
 
-#define SYM_TOKEN(class_name_c, ...)												\
+#define SYM_TOKEN(class_name_c, ...)											\
 class class_name_c: 	public token_c {										\
   public:														\
     __VA_ARGS__														\
@@ -157,7 +218,7 @@
 };
 
 
-#define SYM_REF0(class_name_c, ...)												\
+#define SYM_REF0(class_name_c, ...)											\
 class class_name_c: public symbol_c {											\
   public:														\
     __VA_ARGS__														\
@@ -233,7 +294,7 @@
 };
 
 
-#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5, ...)								\
+#define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5, ...)							\
 class class_name_c: public symbol_c {											\
   public:														\
     symbol_c *ref1;													\
@@ -291,6 +352,4 @@
 #undef SYM_REF5
 #undef SYM_REF6
 
-
-
 #endif /*  _ABSYNTAX_HH */
--- a/absyntax/visitor.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax/visitor.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -73,13 +73,13 @@
 #define SYM_LIST(class_name_c)	\
   void *null_visitor_c::visit(class_name_c *symbol) {return NULL;}
 
-#define SYM_TOKEN(class_name_c)	\
-  void *null_visitor_c::visit(class_name_c *symbol) {return NULL;}
-
-#define SYM_REF0(class_name_c)	\
-  void *null_visitor_c::visit(class_name_c *symbol) {return NULL;}
-
-#define SYM_REF1(class_name_c, ref1)	\
+#define SYM_TOKEN(class_name_c, ...)	\
+  void *null_visitor_c::visit(class_name_c *symbol) {return NULL;}
+
+#define SYM_REF0(class_name_c, ...)	\
+  void *null_visitor_c::visit(class_name_c *symbol) {return NULL;}
+
+#define SYM_REF1(class_name_c, ref1, ...)	\
   void *null_visitor_c::visit(class_name_c *symbol) {return NULL;}
 
 #define SYM_REF2(class_name_c, ref1, ref2, ...)	\
@@ -136,13 +136,13 @@
 #define SYM_LIST(class_name_c)	\
   void *iterator_visitor_c::visit(class_name_c *symbol) {return visit_list(symbol);}
 
-#define SYM_TOKEN(class_name_c)	\
+#define SYM_TOKEN(class_name_c, ...)	\
   void *iterator_visitor_c::visit(class_name_c *symbol) {return NULL;}
 
-#define SYM_REF0(class_name_c)	\
+#define SYM_REF0(class_name_c, ...)	\
   void *iterator_visitor_c::visit(class_name_c *symbol) {return NULL;}
 
-#define SYM_REF1(class_name_c, ref1)			\
+#define SYM_REF1(class_name_c, ref1, ...)			\
 void *iterator_visitor_c::visit(class_name_c *symbol) {	\
   if (symbol->ref1!=NULL) symbol->ref1->accept(*this);	\
   return NULL;						\
@@ -238,13 +238,13 @@
 #define SYM_LIST(class_name_c)	\
   void *search_visitor_c::visit(class_name_c *symbol) {return visit_list(symbol);}
 
-#define SYM_TOKEN(class_name_c)	\
+#define SYM_TOKEN(class_name_c, ...)	\
   void *search_visitor_c::visit(class_name_c *symbol) {return NULL;}
 
-#define SYM_REF0(class_name_c)	\
+#define SYM_REF0(class_name_c, ...)	\
   void *search_visitor_c::visit(class_name_c *symbol) {return NULL;}
 
-#define SYM_REF1(class_name_c, ref1)				\
+#define SYM_REF1(class_name_c, ref1, ...)				\
 void *search_visitor_c::visit(class_name_c *symbol) {		\
   if (symbol->ref1) return symbol->ref1->accept(*this);		\
   return NULL;							\
--- a/absyntax_utils/Makefile.am	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/Makefile.am	Wed Aug 22 16:46:17 2012 +0200
@@ -11,8 +11,9 @@
 	function_call_iterator.cc \
 	function_call_param_iterator.cc \
 	function_param_iterator.cc \
-	get_function_type.cc \
 	get_sizeof_datatype.cc \
+	get_var_name.cc \
+	search_il_label.cc \
 	search_base_type.cc \
 	search_constant_type.cc \
 	search_expression_type.cc \
--- a/absyntax_utils/Makefile.in	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/Makefile.in	Wed Aug 22 16:46:17 2012 +0200
@@ -77,8 +77,9 @@
 	case_element_iterator.$(OBJEXT) \
 	function_call_iterator.$(OBJEXT) \
 	function_call_param_iterator.$(OBJEXT) \
-	function_param_iterator.$(OBJEXT) get_function_type.$(OBJEXT) \
-	get_sizeof_datatype.$(OBJEXT) search_base_type.$(OBJEXT) \
+	function_param_iterator.$(OBJEXT) \
+	get_sizeof_datatype.$(OBJEXT) get_var_name.$(OBJEXT) \
+	search_il_label.$(OBJEXT) search_base_type.$(OBJEXT) \
 	search_constant_type.$(OBJEXT) \
 	search_expression_type.$(OBJEXT) \
 	search_fb_instance_decl.$(OBJEXT) search_fb_typedecl.$(OBJEXT) \
@@ -211,8 +212,9 @@
 	function_call_iterator.cc \
 	function_call_param_iterator.cc \
 	function_param_iterator.cc \
-	get_function_type.cc \
 	get_sizeof_datatype.cc \
+	get_var_name.cc \
+	search_il_label.cc \
 	search_base_type.cc \
 	search_constant_type.cc \
 	search_expression_type.cc \
@@ -312,13 +314,14 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/function_call_iterator.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/function_call_param_iterator.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/function_param_iterator.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/get_function_type.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/get_sizeof_datatype.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/get_var_name.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search_base_type.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search_constant_type.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search_expression_type.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search_fb_instance_decl.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search_fb_typedecl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search_il_label.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search_var_instance_decl.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search_varfb_instance_type.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spec_init_separator.Po@am__quote@
--- a/absyntax_utils/absyntax_utils.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/absyntax_utils.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -50,12 +50,14 @@
 #include <typeinfo>
 #include <list>
 #include <strings.h>
-#include <string.h>  /* required for strlen() */
-#include <stdlib.h>  /* required for atoi() */
+// #include <string.h>  /* required for strlen() */
+// #include <stdlib.h>  /* required for atoi() */
+// #include <errno.h>   /* required for errno */
 
 #include "../util/symtable.hh"
 #include "../util/dsymtable.hh"
 #include "../absyntax/visitor.hh"
+#include "../main.hh" // required for ERROR() and ERROR_MSG() macros.
 
 
 
@@ -66,9 +68,6 @@
 #define TRACE(classname)
 #endif
 
-#define ERROR error_exit(__FILE__,__LINE__)
-/* function defined in main.cc */
-extern void error_exit(const char *file_name, int line_no);
 
 
 /***********************************************************************/
@@ -96,25 +95,6 @@
 }
 
 
-/* extract the value of an integer from an integer_c object !! */
-/* NOTE: it must ignore underscores! */
-int extract_integer(symbol_c *sym) {
-  std::string str = "";
-  integer_c *integer;
-  neg_integer_c * neg_integer;
-
-  if ((neg_integer = dynamic_cast<neg_integer_c *>(sym)) != NULL)
-    return - extract_integer((integer_c *)neg_integer->exp);
-  
-  if ((integer = dynamic_cast<integer_c *>(sym)) == NULL) ERROR;
-
-  for(unsigned int i = 0; i < strlen(integer->value); i++)
-    if (integer->value[i] != '_')  str += integer->value[i];
-
-  return atoi(str.c_str());
-}
-
-
 
 /***********************************************************************/
 /***********************************************************************/
@@ -294,7 +274,17 @@
   }
   
   
-  
+  /*  string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */
+  // SYM_REF4(string_type_declaration_c,	string_type_name,
+  //    					elementary_string_type_name,
+  //    					string_type_declaration_size,
+  //    					string_type_declaration_init) /* may be == NULL! */
+  void *visit(string_type_declaration_c *symbol)	{
+    TRACE("string_type_declaration_c");
+    type_symtable.insert(symbol->string_type_name, symbol);
+    return NULL;
+}
+
   /*********************/
   /* B 1.4 - Variables */
   /*********************/
--- a/absyntax_utils/absyntax_utils.hh	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/absyntax_utils.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -55,9 +55,6 @@
 /* returns 0 if the names are equal!! Case is ignored. */
 int compare_identifiers(symbol_c *ident1, symbol_c *ident2);
 
-/* extract the value of an integer from an integer_c object !! */
-int extract_integer(symbol_c *integer);
-  
 /* A symbol table with all globally declared functions... */
 extern function_declaration_c null_symbol1;
 typedef dsymtable_c<function_declaration_c *, &null_symbol1> function_symtable_t;
@@ -119,8 +116,8 @@
 #include "search_expression_type.hh"
 #include "add_en_eno_param_decl.hh"
 #include "get_sizeof_datatype.hh"
-#include "get_function_type.h"
-
+#include "search_il_label.hh"
+#include "get_var_name.hh"
 
 /***********************************************************************/
 /***********************************************************************/
--- a/absyntax_utils/add_en_eno_param_decl.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/add_en_eno_param_decl.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -44,6 +44,7 @@
 
 #include "add_en_eno_param_decl.hh"
 #include <strings.h>
+#include "../main.hh" // required for ERROR() and ERROR_MSG() macros.
 
 
 // #define DEBUG
@@ -54,9 +55,6 @@
 #endif
 
 
-#define ERROR error_exit(__FILE__,__LINE__)
-/* function defined in main.cc */
-extern void error_exit(const char *file_name, int line_no);
 
 
 
--- a/absyntax_utils/array_dimension_iterator.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/array_dimension_iterator.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -49,6 +49,7 @@
 
 
 #include "array_dimension_iterator.hh"
+#include "../main.hh" // required for ERROR() and ERROR_MSG() macros.
 
 
 //#define DEBUG
@@ -59,9 +60,6 @@
 #endif
 
 
-#define ERROR error_exit(__FILE__,__LINE__)
-/* function defined in main.cc */
-extern void error_exit(const char *file_name, int line_no);
 
 void* array_dimension_iterator_c::iterate_list(list_c *list) {
   void *res;
@@ -102,7 +100,7 @@
  *
  * Returns the subrange symbol!
  */
-symbol_c *array_dimension_iterator_c::next(void) {
+subrange_c *array_dimension_iterator_c::next(void) {
   void *res = array_specification->accept(*this);
   if (res == NULL) 
     return NULL;
--- a/absyntax_utils/array_dimension_iterator.hh	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/array_dimension_iterator.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -54,7 +54,7 @@
     /* a pointer to the array_specification_c currently being analyzed */
     symbol_c *array_specification;
     /* used when called to iterate() for a parameter */
-    symbol_c *current_array_dimension;
+    subrange_c *current_array_dimension;
 
   private:
     void* iterate_list(list_c *list);
@@ -64,7 +64,7 @@
     void reset(void);
 
     /* initialize the iterator object.
-     * We must be given a reference to a case_list_c that will be analyzed...
+     * We must be given a reference to a array_specification_c that will be analyzed...
      */
     array_dimension_iterator_c(symbol_c *symbol);
 
@@ -75,7 +75,8 @@
      *
      * Returns the subrange symbol!
      */
-    symbol_c *next(void);
+    subrange_c *next(void);
+    
 
     private:
     
--- a/absyntax_utils/case_element_iterator.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/case_element_iterator.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -49,6 +49,7 @@
 
 
 #include "case_element_iterator.hh"
+#include "../main.hh" // required for ERROR() and ERROR_MSG() macros.
 
 
 //#define DEBUG
@@ -59,9 +60,6 @@
 #endif
 
 
-#define ERROR error_exit(__FILE__,__LINE__)
-/* function defined in main.cc */
-extern void error_exit(const char *file_name, int line_no);
 
 
 void* case_element_iterator_c::handle_case_element(symbol_c *case_element) {
--- a/absyntax_utils/function_call_iterator.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/function_call_iterator.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -45,6 +45,7 @@
 
 
 #include "function_call_iterator.hh"
+#include "../main.hh" // required for ERROR() and ERROR_MSG() macros.
 
 
 //#define DEBUG
@@ -54,10 +55,6 @@
 #define TRACE(classname)
 #endif
 
-#define ERROR error_exit(__FILE__,__LINE__)
-/* function defined in main.cc */
-extern void error_exit(const char *file_name, int line_no);
-
 
 
 
--- a/absyntax_utils/function_call_param_iterator.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/function_call_param_iterator.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -48,6 +48,7 @@
 
 #include "function_call_param_iterator.hh"
 #include <strings.h>
+#include "../main.hh" // required for ERROR() and ERROR_MSG() macros.
 
 
 //#define DEBUG
@@ -57,9 +58,6 @@
 #define TRACE(classname)
 #endif
 
-#define ERROR error_exit(__FILE__,__LINE__)
-/* function defined in main.cc */
-extern void error_exit(const char *file_name, int line_no);
 
 
 
@@ -184,6 +182,7 @@
  */
 symbol_c *function_call_param_iterator_c::next_f(void) {
   current_value = NULL;
+  current_assign_direction = assign_none;
   param_count = 0;
   iterate_f_next_param++;
   current_operation = function_call_param_iterator_c::iterate_f_op;
@@ -201,6 +200,7 @@
  */
 symbol_c *function_call_param_iterator_c::next_nf(void) {
   current_value = NULL;
+  current_assign_direction = assign_none;
   param_count = 0;
   iterate_nf_next_param++;
   current_operation = function_call_param_iterator_c::iterate_nf_op;
@@ -212,6 +212,7 @@
 /* Search for the value passed to the parameter named <param_name>...  */
 symbol_c *function_call_param_iterator_c::search_f(symbol_c *param_name) {
   current_value = NULL;
+  current_assign_direction = assign_none;
   if (NULL == param_name) ERROR;
   search_param_name = dynamic_cast<identifier_c *>(param_name);
   if (NULL == search_param_name) ERROR;
@@ -233,6 +234,12 @@
   return current_value;
 }
 
+/* Returns the value being passed to the current parameter. */
+function_call_param_iterator_c::assign_direction_t function_call_param_iterator_c::get_assign_direction(void) {
+  return current_assign_direction;
+}
+
+
 /********************************/
 /* B 1.7 Configuration elements */
 /********************************/
@@ -339,6 +346,7 @@
   if (NULL == symb_var)
     ERROR;
 
+  current_assign_direction = assign_in;
   return handle_parameter_assignment(symb_var->var_name, symbol->prog_data_source);
 }
 
@@ -355,6 +363,7 @@
   if (NULL == symb_var)
     ERROR;
 
+  current_assign_direction = assign_out;
   return handle_parameter_assignment(symb_var->var_name, symbol->data_sink);
 }
 
@@ -459,6 +468,7 @@
   // since we do not yet support it, it is best to simply stop than to fail silently...
   if (NULL != symbol->simple_instr_list) ERROR;
 
+  current_assign_direction = assign_in;
   return handle_parameter_assignment((symbol_c *)symbol->il_assign_operator->accept(*this), symbol->il_operand);
 }
 
@@ -466,6 +476,7 @@
 // SYM_REF2(il_param_out_assignment_c, il_assign_out_operator, variable);
 void *function_call_param_iterator_c::visit(il_param_out_assignment_c *symbol) {
   TRACE("il_param_out_assignment_c");
+  current_assign_direction = assign_out;
   return handle_parameter_assignment((symbol_c *)symbol->il_assign_out_operator->accept(*this), symbol->variable);
 }
 
@@ -564,6 +575,7 @@
 // SYM_REF2(input_variable_param_assignment_c, variable_name, expression)
 void *function_call_param_iterator_c::visit(input_variable_param_assignment_c *symbol) {
   TRACE("input_variable_param_assignment_c");
+  current_assign_direction = assign_in;
   return handle_parameter_assignment(symbol->variable_name, symbol->expression);
 }
 
@@ -574,6 +586,7 @@
   // TODO : Handle not_param !!!
   if (NULL != symbol->not_param) ERROR;  // we do not yet support it, so it is best to simply stop than to fail silently...
 
+  current_assign_direction = assign_out;
   return handle_parameter_assignment(symbol->variable_name, symbol->variable);
 }
 
--- a/absyntax_utils/function_call_param_iterator.hh	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/function_call_param_iterator.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -51,6 +51,58 @@
 class function_call_param_iterator_c : public null_visitor_c {
 
   private:
+    void *search_list(list_c *list);
+    void *handle_parameter_assignment(symbol_c *variable_name, symbol_c *expression) ;
+
+
+  public:
+    /* start off at the first parameter once again... */
+    void reset(void);
+
+    /* initialise the iterator object.
+     * We must be given a reference to the function/program/function block call
+     * that will be analysed...
+     */
+    function_call_param_iterator_c(symbol_c *f_call);
+
+    /* Skip to the next formal parameter. After object creation,
+     * the object references on parameter _before_ the first, so
+     * this function must be called once to get the object to
+     * reference the first parameter...
+     *
+     * Returns the paramater name to which a value is being passed!
+     * You can determine the value being passed by calling 
+     * function_call_param_iterator_c::search_f()
+     */
+    symbol_c *next_f(void);
+
+    /* Skip to the next non-formal parameter. After object creation,
+     * the object references on parameter _before_ the first, so
+     * this function must be called once to get the object to
+     * reference the first parameter...
+     *
+     * Returns whatever is being passed to the parameter!
+     */
+    symbol_c *next_nf(void);
+
+    /* Search for the value passed to the parameter named <param_name>...  */
+    symbol_c *search_f(symbol_c *param_name);
+    symbol_c *search_f(const char *param_name);
+
+    /* Returns the value being passed to the current parameter. */
+    symbol_c *get_current_value(void);
+    
+    /* A type to specify how the current parameter was assigned.
+     * param_name := var   -> assign_in
+     * param_name => var   -> assign_out
+     *                     -> assign_none  (used when handling non formal calls, when no assignment type is used)
+     */
+    typedef enum {assign_in, assign_out, assign_none} assign_direction_t ;
+    /* Returns the assignment direction of the current parameter. */
+    assign_direction_t get_assign_direction(void);
+
+
+  private:
       /* a pointer to the function call
        * (or function block or program call!)
        */
@@ -58,6 +110,7 @@
     int iterate_f_next_param, iterate_nf_next_param, param_count;
     identifier_c *search_param_name;
     symbol_c *current_value;
+    assign_direction_t current_assign_direction;
 
     /* Which operation of the class was called:
      *  - iterate to the next non-formal parameter. 
@@ -67,49 +120,7 @@
     typedef enum {iterate_nf_op, iterate_f_op, search_f_op} operation_t;
     operation_t current_operation;
 
-  private:
-    void *search_list(list_c *list);
-    void *handle_parameter_assignment(symbol_c *variable_name, symbol_c *expression) ;
-
-
-  public:
-    /* start off at the first parameter once again... */
-    void reset(void);
-
-    /* initialise the iterator object.
-     * We must be given a reference to the function/program/function block call
-     * that will be analysed...
-     */
-    function_call_param_iterator_c(symbol_c *f_call);
-
-    /* Skip to the next formal parameter. After object creation,
-     * the object references on parameter _before_ the first, so
-     * this function must be called once to get the object to
-     * reference the first parameter...
-     *
-     * Returns the paramater name to which a value is being passed!
-     * You can determine the value being passed by calling 
-     * function_call_param_iterator_c::search_f()
-     */
-    symbol_c *next_f(void);
-
-    /* Skip to the next non-formal parameter. After object creation,
-     * the object references on parameter _before_ the first, so
-     * this function must be called once to get the object to
-     * reference the first parameter...
-     *
-     * Returns whatever is being passed to the parameter!
-     */
-    symbol_c *next_nf(void);
-
-    /* Search for the value passed to the parameter named <param_name>...  */
-    symbol_c *search_f(symbol_c *param_name);
-    symbol_c *search_f(const char *param_name);
-
-    /* Returns the value being passed to the current parameter. */
-    symbol_c *get_current_value(void);
-
-
+    
   private:
   /********************************/
   /* B 1.7 Configuration elements */
--- a/absyntax_utils/function_param_iterator.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/function_param_iterator.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -47,14 +47,14 @@
  */
 
 
-
-#include "absyntax_utils.hh"  /* required for extract_integer() */
-// #include "function_param_iterator.hh"  /* no longer required, aready included by absyntax_utils.hh */
-// #include "spec_init_separator.hh"  /* no longer required, aready included by absyntax_utils.hh */
+#include "function_param_iterator.hh"  /* no longer required, aready included by absyntax_utils.hh */
+#include "spec_init_separator.hh"  /* no longer required, aready included by absyntax_utils.hh */
 #include <stdlib.h>  /* required for strtol() */
 #include <string.h>
 #include <strings.h>
-
+#include <limits> // required for std::numeric_limits< XXX >::max()
+#include <errno.h> // required for errno
+#include "../main.hh" // required for ERROR() and ERROR_MSG() macros.
 
 //#define DEBUG
 #ifdef DEBUG
@@ -64,9 +64,59 @@
 #endif
 
 
-#define ERROR error_exit(__FILE__,__LINE__)
-/* function defined in main.cc */
-extern void error_exit(const char *file_name, int line_no);
+
+
+
+/* NOTE: The following function is not really needed, as we could get the value that constant_folding_c determined for this
+ *       integer. Remember that currently constant_folding_c runs before this class is ever used/called!
+ *       However, I (Mario) do not currently feel it would be a good idea to restrict the use of this
+ *       abstract syntax utility to only after the constant_folding_c has had a chance to fill in the constant value
+ *       of this symbol. 
+ *       For this reason only, I have opted to let this abstract syntax utility have its own private copy of the
+ *       extract_integer() function.
+ *       Another aspect that makes this OK is that this function will only be used to extract the integer value of the
+ *       index for the first extensible paramater (examples follow shortly). Since this is an extension to IEC 61131-3 
+ *       that we created to allow us to handle extensible functions with very little hard coding, it is OK if we
+ *       impose extra/different limits on how an integer may be legally be formated in this case. This will also 
+ *       only show up in code that describes the interface to the standard function of IEC 61131-3, which the user
+ *       will not ever get to see. We write that IEC 61131-3 code ourselves!
+ *
+ *      Example of source code we will be parsing and analysing:
+ *
+ *      FUNCTION ADD : REAL VAR_INPUT IN 1 .. : REAL; END_VAR RETURN; END_FUNCTION
+ *                                      ^^^
+ *
+ *      FUNCTION MUX : REAL VAR_INPUT K : USINT; IN 0 .. : REAL; END_VAR RETURN; END_FUNCTION
+ *                                                 ^^^
+ *
+ *      Basically, currently this will only be either a '0' or a '1' !!
+ */
+
+/* NOTE: it must ignore underscores! */
+static int extract_first_index_value(symbol_c *sym) {
+  std::string str = "";
+  integer_c *integer;
+  long int ret;
+
+  if ((integer = dynamic_cast<integer_c *>(sym)) == NULL) ERROR;
+  for(unsigned int i = 0; i < strlen(integer->value); i++)
+    if (integer->value[i] != '_')  str += integer->value[i];
+
+  errno = 0; // since strtoXX() may legally return 0, we must set errno to 0 to detect errors correctly!
+  ret = strtol(str.c_str(), NULL, 10);
+  if (errno != 0) ERROR;
+  if (ret < 0) ERROR; // the following code assumes that the first index will never be negative!
+  if (ret > std::numeric_limits< int >::max()) ERROR; // output of this function is only an int!!
+
+  return ret;
+}
+
+
+
+
+
+
+
 
 
 
@@ -130,7 +180,7 @@
         if (extensible_parameter != NULL) {
           sym = extensible_parameter->var_name;
           current_param_is_extensible = true;
-          _first_extensible_param_index = extract_integer(extensible_parameter->first_index);
+          _first_extensible_param_index = extract_first_index_value(extensible_parameter->first_index);
         }
         identifier_c *variable_name = dynamic_cast<identifier_c *>(sym);
         if (variable_name == NULL) ERROR;
@@ -167,7 +217,7 @@
       if (extensible_parameter != NULL) {
         var_name = extensible_parameter->var_name;
         current_param_is_extensible = true;
-        _first_extensible_param_index = extract_integer(extensible_parameter->first_index);
+        _first_extensible_param_index = extract_first_index_value(extensible_parameter->first_index);
       }
       identifier_c *variable_name = dynamic_cast<identifier_c *>(var_name);
       if (variable_name == NULL) ERROR;
@@ -206,7 +256,9 @@
   _first_extensible_param_index = -1;
   current_param_is_extensible = false;
   current_param_name = NULL;
-  current_param_type = current_param_default_value = NULL;
+  current_param_type = NULL;
+  current_param_default_value = NULL;
+  last_returned_parameter = NULL; /* the last parameter returned by search() or next() */
 }
 
 
@@ -223,7 +275,8 @@
   function_block_declaration_c *fb_decl = dynamic_cast<function_block_declaration_c *>(pou_decl);
   program_declaration_c        * p_decl = dynamic_cast<program_declaration_c        *>(pou_decl);
 
-  if ((NULL == f_decl) && (NULL == fb_decl) && (NULL == p_decl)) ERROR;
+  if ((NULL == f_decl) && (NULL == fb_decl) && (NULL == p_decl)) 
+    ERROR;
 
   /* OK. Now initialise this object... */
   this->f_decl = pou_decl;
@@ -248,6 +301,7 @@
     return current_param_name;
   }
   
+  last_returned_parameter = NULL; 
   param_count = 0;
   en_eno_param_implicit = false;
   next_param++;
@@ -261,13 +315,14 @@
   if (extensible_parameter != NULL) {
     sym = extensible_parameter->var_name;
     current_param_is_extensible = true;
-    _first_extensible_param_index = extract_integer(extensible_parameter->first_index);
+    _first_extensible_param_index = extract_first_index_value(extensible_parameter->first_index);
     current_extensible_param_index = _first_extensible_param_index;
   }
   identifier = dynamic_cast<identifier_c *>(sym);
   if (identifier == NULL)
     ERROR;
   current_param_name = identifier;
+  last_returned_parameter = current_param_name; 
   return current_param_name;
 }
 
@@ -281,35 +336,53 @@
   current_operation = function_param_iterator_c::search_op;
   void *res = f_decl->accept(*this);
   identifier_c *res_param_name = dynamic_cast<identifier_c *>((symbol_c *)res);
+  last_returned_parameter = res_param_name; 
   return res_param_name;
 }
 
+identifier_c *function_param_iterator_c::search(const char *param_name) {
+  identifier_c   param_name_id(param_name);
+  return search(&param_name_id);
+}
+
+
+
 /* Returns the currently referenced parameter's default value,
  * or NULL if none is specified in the function declrataion itself.
  */
 symbol_c *function_param_iterator_c::default_value(void) {
+  if (NULL == last_returned_parameter) 
+    return NULL;
   return current_param_default_value;
 }
 
 /* Returns the currently referenced parameter's type name. */
 symbol_c *function_param_iterator_c::param_type(void) {
+  if (NULL == last_returned_parameter) 
+    return NULL;
   return current_param_type;
 }
 
 /* Returns if currently referenced parameter is an implicit defined EN/ENO parameter. */
 bool function_param_iterator_c::is_en_eno_param_implicit(void) {
+  if (NULL == last_returned_parameter) 
+    ERROR;
   return en_eno_param_implicit;
 }
 
 /* Returns if currently referenced parameter is an extensible parameter. */
 /* extensible paramters only occur in some standard functions, e.g. AND(word#34, word#44, word#65); */
 bool function_param_iterator_c::is_extensible_param(void) {
+  if (NULL == last_returned_parameter) 
+    ERROR;
   return current_param_is_extensible;
 }
 
 /* Returns the index of the current extensible parameter. */             
 /* If the current parameter is not an extensible paramter, returns -1 */
 int function_param_iterator_c::extensible_param_index(void) {
+  if (NULL == last_returned_parameter) 
+    ERROR;
   return (current_param_is_extensible? current_extensible_param_index : -1);
 }
 
@@ -323,6 +396,8 @@
  * i.e. VAR_INPUT, VAR_OUTPUT or VAR_INOUT
  */
 function_param_iterator_c::param_direction_t function_param_iterator_c::param_direction(void) {
+  if (NULL == last_returned_parameter) 
+    ERROR;
   return current_param_direction;
 }
 
--- a/absyntax_utils/function_param_iterator.hh	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/function_param_iterator.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -105,7 +105,10 @@
      */
     typedef enum {iterate_op, search_op} operation_t;
     operation_t current_operation;
-
+    
+    /* the last parameter/value returned by search() or next() */
+    symbol_c *last_returned_parameter; 
+    
   private:
     int   cmp_extparam_names(const char* s1, const char* s2);
     void* handle_param_list(list_c *list);
@@ -143,6 +146,7 @@
      * of the found parameter.
      */
     identifier_c *search(symbol_c *param_name);
+    identifier_c *search(const char *param_name);
 
     /* Returns the currently referenced parameter's default value,
      * or NULL if none is specified in the function declrataion itself.
--- a/absyntax_utils/function_type_decl.h	Tue Aug 14 19:40:01 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,461 +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
- */
- 
- 
-typedef enum {
-    function_real_to_sint,
-    function_real_to_lint,
-    function_real_to_dint,
-    function_real_to_date,
-    function_real_to_dword,
-    function_real_to_dt,
-    function_real_to_tod,
-    function_real_to_udint,
-    function_real_to_word,
-    function_real_to_string,
-    function_real_to_lword,
-    function_real_to_uint,
-    function_real_to_lreal,
-    function_real_to_byte,
-    function_real_to_usint,
-    function_real_to_ulint,
-    function_real_to_bool,
-    function_real_to_time,
-    function_real_to_int,
-    function_sint_to_real,
-    function_sint_to_lint,
-    function_sint_to_dint,
-    function_sint_to_date,
-    function_sint_to_dword,
-    function_sint_to_dt,
-    function_sint_to_tod,
-    function_sint_to_udint,
-    function_sint_to_word,
-    function_sint_to_string,
-    function_sint_to_lword,
-    function_sint_to_uint,
-    function_sint_to_lreal,
-    function_sint_to_byte,
-    function_sint_to_usint,
-    function_sint_to_ulint,
-    function_sint_to_bool,
-    function_sint_to_time,
-    function_sint_to_int,
-    function_lint_to_real,
-    function_lint_to_sint,
-    function_lint_to_dint,
-    function_lint_to_date,
-    function_lint_to_dword,
-    function_lint_to_dt,
-    function_lint_to_tod,
-    function_lint_to_udint,
-    function_lint_to_word,
-    function_lint_to_string,
-    function_lint_to_lword,
-    function_lint_to_uint,
-    function_lint_to_lreal,
-    function_lint_to_byte,
-    function_lint_to_usint,
-    function_lint_to_ulint,
-    function_lint_to_bool,
-    function_lint_to_time,
-    function_lint_to_int,
-    function_dint_to_real,
-    function_dint_to_sint,
-    function_dint_to_lint,
-    function_dint_to_date,
-    function_dint_to_dword,
-    function_dint_to_dt,
-    function_dint_to_tod,
-    function_dint_to_udint,
-    function_dint_to_word,
-    function_dint_to_string,
-    function_dint_to_lword,
-    function_dint_to_uint,
-    function_dint_to_lreal,
-    function_dint_to_byte,
-    function_dint_to_usint,
-    function_dint_to_ulint,
-    function_dint_to_bool,
-    function_dint_to_time,
-    function_dint_to_int,
-    function_date_to_real,
-    function_date_to_sint,
-    function_date_to_lint,
-    function_date_to_dint,
-    function_date_to_dword,
-    function_date_to_udint,
-    function_date_to_word,
-    function_date_to_string,
-    function_date_to_lword,
-    function_date_to_uint,
-    function_date_to_lreal,
-    function_date_to_byte,
-    function_date_to_usint,
-    function_date_to_ulint,
-    function_date_to_int,
-    function_dword_to_real,
-    function_dword_to_sint,
-    function_dword_to_lint,
-    function_dword_to_dint,
-    function_dword_to_date,
-    function_dword_to_dt,
-    function_dword_to_tod,
-    function_dword_to_udint,
-    function_dword_to_word,
-    function_dword_to_string,
-    function_dword_to_lword,
-    function_dword_to_uint,
-    function_dword_to_lreal,
-    function_dword_to_byte,
-    function_dword_to_usint,
-    function_dword_to_ulint,
-    function_dword_to_bool,
-    function_dword_to_time,
-    function_dword_to_int,
-    function_dt_to_real,
-    function_dt_to_sint,
-    function_dt_to_lint,
-    function_dt_to_dint,
-    function_dt_to_dword,
-    function_dt_to_udint,
-    function_dt_to_word,
-    function_dt_to_string,
-    function_dt_to_lword,
-    function_dt_to_uint,
-    function_dt_to_lreal,
-    function_dt_to_byte,
-    function_dt_to_usint,
-    function_dt_to_ulint,
-    function_dt_to_int,
-    function_tod_to_real,
-    function_tod_to_sint,
-    function_tod_to_lint,
-    function_tod_to_dint,
-    function_tod_to_dword,
-    function_tod_to_udint,
-    function_tod_to_word,
-    function_tod_to_string,
-    function_tod_to_lword,
-    function_tod_to_uint,
-    function_tod_to_lreal,
-    function_tod_to_byte,
-    function_tod_to_usint,
-    function_tod_to_ulint,
-    function_tod_to_int,
-    function_udint_to_real,
-    function_udint_to_sint,
-    function_udint_to_lint,
-    function_udint_to_dint,
-    function_udint_to_date,
-    function_udint_to_dword,
-    function_udint_to_dt,
-    function_udint_to_tod,
-    function_udint_to_word,
-    function_udint_to_string,
-    function_udint_to_lword,
-    function_udint_to_uint,
-    function_udint_to_lreal,
-    function_udint_to_byte,
-    function_udint_to_usint,
-    function_udint_to_ulint,
-    function_udint_to_bool,
-    function_udint_to_time,
-    function_udint_to_int,
-    function_word_to_real,
-    function_word_to_sint,
-    function_word_to_lint,
-    function_word_to_dint,
-    function_word_to_date,
-    function_word_to_dword,
-    function_word_to_dt,
-    function_word_to_tod,
-    function_word_to_udint,
-    function_word_to_string,
-    function_word_to_lword,
-    function_word_to_uint,
-    function_word_to_lreal,
-    function_word_to_byte,
-    function_word_to_usint,
-    function_word_to_ulint,
-    function_word_to_bool,
-    function_word_to_time,
-    function_word_to_int,
-    function_string_to_real,
-    function_string_to_sint,
-    function_string_to_lint,
-    function_string_to_dint,
-    function_string_to_date,
-    function_string_to_dword,
-    function_string_to_dt,
-    function_string_to_tod,
-    function_string_to_udint,
-    function_string_to_word,
-    function_string_to_lword,
-    function_string_to_uint,
-    function_string_to_lreal,
-    function_string_to_byte,
-    function_string_to_usint,
-    function_string_to_ulint,
-    function_string_to_bool,
-    function_string_to_time,
-    function_string_to_int,
-    function_lword_to_real,
-    function_lword_to_sint,
-    function_lword_to_lint,
-    function_lword_to_dint,
-    function_lword_to_date,
-    function_lword_to_dword,
-    function_lword_to_dt,
-    function_lword_to_tod,
-    function_lword_to_udint,
-    function_lword_to_word,
-    function_lword_to_string,
-    function_lword_to_uint,
-    function_lword_to_lreal,
-    function_lword_to_byte,
-    function_lword_to_usint,
-    function_lword_to_ulint,
-    function_lword_to_bool,
-    function_lword_to_time,
-    function_lword_to_int,
-    function_uint_to_real,
-    function_uint_to_sint,
-    function_uint_to_lint,
-    function_uint_to_dint,
-    function_uint_to_date,
-    function_uint_to_dword,
-    function_uint_to_dt,
-    function_uint_to_tod,
-    function_uint_to_udint,
-    function_uint_to_word,
-    function_uint_to_string,
-    function_uint_to_lword,
-    function_uint_to_lreal,
-    function_uint_to_byte,
-    function_uint_to_usint,
-    function_uint_to_ulint,
-    function_uint_to_bool,
-    function_uint_to_time,
-    function_uint_to_int,
-    function_lreal_to_real,
-    function_lreal_to_sint,
-    function_lreal_to_lint,
-    function_lreal_to_dint,
-    function_lreal_to_date,
-    function_lreal_to_dword,
-    function_lreal_to_dt,
-    function_lreal_to_tod,
-    function_lreal_to_udint,
-    function_lreal_to_word,
-    function_lreal_to_string,
-    function_lreal_to_lword,
-    function_lreal_to_uint,
-    function_lreal_to_byte,
-    function_lreal_to_usint,
-    function_lreal_to_ulint,
-    function_lreal_to_bool,
-    function_lreal_to_time,
-    function_lreal_to_int,
-    function_byte_to_real,
-    function_byte_to_sint,
-    function_byte_to_lint,
-    function_byte_to_dint,
-    function_byte_to_date,
-    function_byte_to_dword,
-    function_byte_to_dt,
-    function_byte_to_tod,
-    function_byte_to_udint,
-    function_byte_to_word,
-    function_byte_to_string,
-    function_byte_to_lword,
-    function_byte_to_uint,
-    function_byte_to_lreal,
-    function_byte_to_usint,
-    function_byte_to_ulint,
-    function_byte_to_bool,
-    function_byte_to_time,
-    function_byte_to_int,
-    function_usint_to_real,
-    function_usint_to_sint,
-    function_usint_to_lint,
-    function_usint_to_dint,
-    function_usint_to_date,
-    function_usint_to_dword,
-    function_usint_to_dt,
-    function_usint_to_tod,
-    function_usint_to_udint,
-    function_usint_to_word,
-    function_usint_to_string,
-    function_usint_to_lword,
-    function_usint_to_uint,
-    function_usint_to_lreal,
-    function_usint_to_byte,
-    function_usint_to_ulint,
-    function_usint_to_bool,
-    function_usint_to_time,
-    function_usint_to_int,
-    function_ulint_to_real,
-    function_ulint_to_sint,
-    function_ulint_to_lint,
-    function_ulint_to_dint,
-    function_ulint_to_date,
-    function_ulint_to_dword,
-    function_ulint_to_dt,
-    function_ulint_to_tod,
-    function_ulint_to_udint,
-    function_ulint_to_word,
-    function_ulint_to_string,
-    function_ulint_to_lword,
-    function_ulint_to_uint,
-    function_ulint_to_lreal,
-    function_ulint_to_byte,
-    function_ulint_to_usint,
-    function_ulint_to_bool,
-    function_ulint_to_time,
-    function_ulint_to_int,
-    function_bool_to_real,
-    function_bool_to_sint,
-    function_bool_to_lint,
-    function_bool_to_dint,
-    function_bool_to_date,
-    function_bool_to_dword,
-    function_bool_to_dt,
-    function_bool_to_tod,
-    function_bool_to_udint,
-    function_bool_to_word,
-    function_bool_to_string,
-    function_bool_to_lword,
-    function_bool_to_uint,
-    function_bool_to_lreal,
-    function_bool_to_byte,
-    function_bool_to_usint,
-    function_bool_to_ulint,
-    function_bool_to_time,
-    function_bool_to_int,
-    function_time_to_real,
-    function_time_to_sint,
-    function_time_to_lint,
-    function_time_to_dint,
-    function_time_to_dword,
-    function_time_to_udint,
-    function_time_to_word,
-    function_time_to_string,
-    function_time_to_lword,
-    function_time_to_uint,
-    function_time_to_lreal,
-    function_time_to_byte,
-    function_time_to_usint,
-    function_time_to_ulint,
-    function_time_to_int,
-    function_int_to_real,
-    function_int_to_sint,
-    function_int_to_lint,
-    function_int_to_dint,
-    function_int_to_date,
-    function_int_to_dword,
-    function_int_to_dt,
-    function_int_to_tod,
-    function_int_to_udint,
-    function_int_to_word,
-    function_int_to_string,
-    function_int_to_lword,
-    function_int_to_uint,
-    function_int_to_lreal,
-    function_int_to_byte,
-    function_int_to_usint,
-    function_int_to_ulint,
-    function_int_to_bool,
-    function_int_to_time,
-    function_trunc,
-    function_bcd_to_udint,
-    function_bcd_to_uint,
-    function_bcd_to_ulint,
-    function_bcd_to_usint,
-    function_udint_to_bcd,
-    function_uint_to_bcd,
-    function_usint_to_bcd,
-    function_ulint_to_bcd,
-    function_date_and_time_to_time_of_day,
-    function_date_and_time_to_date,
-    function_abs,
-    function_sqrt,
-    function_ln,
-    function_log,
-    function_exp,
-    function_sin,
-    function_cos,
-    function_tan,
-    function_asin,
-    function_acos,
-    function_atan,
-    function_add,
-    function_mul,
-    function_sub,
-    function_div,
-    function_mod,
-    function_expt,
-    function_move,
-    function_add_time,
-    function_add_tod_time,
-    function_add_dt_time,
-    function_multime,
-    function_sub_time,
-    function_sub_date_date,
-    function_sub_tod_time,
-    function_sub_tod_tod,
-    function_sub_dt_time,
-    function_divtime,
-    function_shl,
-    function_shr,
-    function_ror,
-    function_rol,
-    function_and,
-    function_or,
-    function_xor,
-    function_not,
-    function_sel,
-    function_max,
-    function_min,
-    function_limit,
-    function_mux,
-    function_gt,
-    function_ge,
-    function_eq,
-    function_lt,
-    function_le,
-    function_ne,
-    function_len,
-    function_left,
-    function_right,
-    function_mid,
-    function_concat,
-    function_concat_dat_tod,
-    function_insert,
-    function_delete,
-    function_replace,
-    function_find,
-    function_none
-} function_type_t;
--- a/absyntax_utils/get_function_type.cc	Tue Aug 14 19:40:01 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-/*
- *  matiec - a compiler for the programming languages defined in IEC 61131-3
- *
- *  Copyright (C) 2003-2011  Mario de Sousa (msousa@fe.up.pt)
- *  Copyright (C) 2007-2011  Laurent Bessard and Edouard Tisserant
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <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 IL and ST compiler.
- *
- * Based on the
- * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
- *
- */
-
-
-#include "../absyntax/absyntax.hh"
-#include "function_type_decl.h"
-#include <strings.h>
-
-
-#include "get_function_type_decl.c"
--- a/absyntax_utils/get_function_type.h	Tue Aug 14 19:40:01 2012 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- *  matiec - a compiler for the programming languages defined in IEC 61131-3
- *
- *  Copyright (C) 2008 Edouard TISSERANT
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <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 IL and ST compiler.
- *
- * Based on the
- * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
- *
- */
-
-#include "function_type_decl.h"
-
-function_type_t get_function_type(identifier_c *function_name);
-
--- a/absyntax_utils/get_sizeof_datatype.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/get_sizeof_datatype.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -45,8 +45,10 @@
  *       NOTE: for base 10 numeric literals, any number taking up more than 64 bits
  *             will only return a bitsize of 1024!
  *
- *       For numeric literals, we return the minimum number of bits
- *       required to store the value.
+ *       NOTE: The code that does the following has been commented out, since we no longer need it!
+ *             It has been superceded by the constant_folding.cc class.
+ *       // For numeric literals, we return the minimum number of bits
+ *       // required to store the value.
  *
  * E.g. TYPE new_int_t : INT; END_TYPE;
  *      TYPE new_int2_t : INT = 2; END_TYPE;
@@ -57,19 +59,21 @@
  *    sizeof(DINT) -> 32
  *    sizeof(LINT) -> 64
  *
- *    sizeof('1')       ->  1
- *    sizeof('015')     ->  4    # Leading zeros are ignored!
- *    sizeof('0')       ->  1    # This is a special case! Even the value 0 needs at least 1 bit to store!
- *    sizeof('16')      ->  5
- *    sizeof('2#00101') ->  3
- *    sizeof('8#334')   ->  9
- *    sizeof('16#2A')   ->  8
- *
- *    sizeof('7.4')     ->  32   # all real literals return 32 bits, the size of a 'REAL'
- *                               # TODO: study IEC 60559 for the range of values that may be
- *                               #       stored in a REAL (basic single width floating point format)
- *                               #       and in a LREAL (basic double width floating point format)
- *                               #       and see if some real literals need to return 64 instead!
+ *       NOTE: The code that does the following has been commented out, since we no longer need it!
+ *             It has been superceded by the constant_folding.cc class.
+ *    // sizeof('1')       ->  1
+ *    // sizeof('015')     ->  4    # Leading zeros are ignored!
+ *    // sizeof('0')       ->  1    # This is a special case! Even the value 0 needs at least 1 bit to store!
+ *    // sizeof('16')      ->  5
+ *    // sizeof('2#00101') ->  3
+ *    // sizeof('8#334')   ->  9
+ *    // sizeof('16#2A')   ->  8
+ *
+ *    // sizeof('7.4')     ->  32   # all real literals return 32 bits, the size of a 'REAL'
+ *    //                            # TODO: study IEC 60559 for the range of values that may be
+ *    //                            #       stored in a REAL (basic single width floating point format)
+ *    //                            #       and in a LREAL (basic double width floating point format)
+ *    //                            #       and see if some real literals need to return 64 instead!
  */
 
 #include "get_sizeof_datatype.hh"
@@ -77,14 +81,10 @@
 #include <stdlib.h>
 #include <string.h>
 #include <limits.h>  // get definition of ULLONG_MAX
-/* tell stdint.h we want the definition of UINT64_MAX */
-#define __STDC_LIMIT_MACROS
-#include <stdint.h>  // get definition of uint64_t and UINT64_MAX
-
-
-#define ERROR error_exit(__FILE__,__LINE__)
-/* function defined in main.cc */
-extern void error_exit(const char *file_name, int line_no);
+#include <errno.h>
+
+#include "../main.hh" // required for ERROR() and ERROR_MSG() macros, and uint64_t and UINT64_MAX
+
 
 
 /* This class is a singleton.
@@ -97,8 +97,7 @@
 #define _decode_int(ptr)     (((char *)ptr) - ((char *)NULL))
 
 
-
-
+#if 0   /* We no longer need the code for handling numeric literals. But keep it around for a little while longer... */
 /* divide a base 10 literal in a string by 2 */
 /* returns remainder of division (0 or 1)    */
 static int strdivby2(char **strptr) {
@@ -121,7 +120,7 @@
 
   return carry;
 }
-
+#endif
 
 /* Constructor for the singleton class */
 int get_sizeof_datatype_c::getsize(symbol_c *data_type_symbol) {
@@ -139,7 +138,7 @@
       singleton = NULL;
     }
 
-
+#if 0   /* We no longer need the code for handling numeric literals. But keep it around for a little while longer... */
 /*********************/
 /* B 1.2 - Constants */
 /*********************/
@@ -158,8 +157,60 @@
 /* NOTE: all integer_c and real_c tokens will always be positive (i.e. no leading '-')
  * due to the way the source code is parsed by iec.flex.
  */
+
+/*
+ * IEC6113-3 and C++ use IEC 60559 to rappresent floating point data types
+ * REAL  => float       => single precision 	32 bit
+ * LREAL => double      => double precision 	64 bit
+ * ????? => long double => quadruple precision 128 bit
+ */
 void *get_sizeof_datatype_c::visit(real_c *symbol) {
-  return _encode_int(32);
+  char *endp;
+  long double ld_test;
+  double d_test;
+  float  f_test;
+
+  /* copy the original string, but leave out any underscores... */
+  char *sval, *oval;
+  const char *pval;
+  oval = sval = (char *)malloc(strlen(symbol->value)+1);
+  if (NULL ==  sval) ERROR;
+  
+  for (pval = symbol->value, sval = oval; *pval != '\0'; pval++) {
+    if ('_' != *pval) {*sval = *pval; sval++;}
+  }  
+  *sval = '\0';  
+  
+  sval = oval;
+  if ('\0' == *sval) ERROR;
+
+  /* now do the conversion using the new string... */
+  f_test = strtof(sval, &endp);
+  if (*endp != '\0') ERROR;
+  if (ERANGE != errno) {
+    /* No overflow/underflow! => It fits in a float! */
+    free(oval);
+    return _encode_int(32);
+  }
+  
+  d_test = strtod(sval, &endp);
+  if (*endp != '\0') ERROR;
+  if (ERANGE != errno) {
+    /* No overflow/underflow! => It fits in a double! */
+    free(oval);
+    return _encode_int(64);
+  }
+  
+  ld_test = strtold(sval, &endp);
+  if (*endp != '\0') ERROR;
+  if (ERANGE != errno) {
+    /* No overflow/underflow! => It fits in a long double! */
+    free(oval);
+    return _encode_int(128);
+  }
+
+  free(oval);
+  return _encode_int(65535); /* a very large number!!! */
 }
 
 void *get_sizeof_datatype_c::visit(neg_real_c *symbol) {
@@ -282,7 +333,7 @@
     if (('0' != *sval) && ('1' != *sval) && ('_' != *sval))
       ERROR;
 
-    if ('_' != *sval) bitsize ++; /* 1 bits per binary digit */
+    if ('_' != *sval) bitsize++; /* 1 bits per binary digit */
   }
 
   /* special case... if (value == 0) <=> (bitsize == 0), return bit size of 1 ! */
@@ -352,7 +403,7 @@
     /* Assumes ASCII */
     if (!(('0' <= *sval) && ('9' >= *sval)) && 
         !(('A' <= *sval) && ('F' >= *sval)) &&
-        !(('a' <= *sval) && ('b' >= *sval)) &&
+        !(('a' <= *sval) && ('f' >= *sval)) &&
         ! ('_' == *sval))
       ERROR;
 
@@ -364,7 +415,7 @@
 
   return _encode_int(bitsize);
 }
-
+#endif
 
 /***********************************/
 /* B 1.3.1 - Elementary Data Types */
--- a/absyntax_utils/get_sizeof_datatype.hh	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/get_sizeof_datatype.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -84,6 +84,7 @@
     static get_sizeof_datatype_c *singleton;
 
   private:
+#if 0   /* We no longer need the code for handling numeric literals. But keep it around for a little while longer... */
     /*********************/
     /* B 1.2 - Constants */
     /*********************/
@@ -105,7 +106,7 @@
     void *visit(binary_integer_c *symbol);
     void *visit(octal_integer_c *symbol);
     void *visit(hex_integer_c *symbol);
-
+#endif
   /***********************************/
   /* B 1.3.1 - Elementary Data Types */
   /***********************************/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax_utils/get_var_name.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -0,0 +1,120 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2012  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)
+ *
+ */
+
+/*
+ *  A small helper visitor class, that will   
+ *  return the name (tokn_c *) of a variable, as it will
+ *  appear in the variable declaration.
+ */
+
+/*  For ex.:
+ *       VAR
+ *          A : int;
+ *          B : ARRAY [1..9] of int;
+ *          C : some_struct_t;
+ *       END_VAR
+ *
+ *          A    := 56;
+ *          B[8] := 99;
+ *          C.e  := 77;
+ *
+ *       Calling this visitor class with symbolic_variable_c instance referencing 'A' in
+ *       the line 'A := 56', will return the string "A".
+ *
+ *       Calling this visitor class with array_variable_c instance referencing 'B[8]' in
+ *       the line 'B[8] := 99', will return the string "B".
+ *
+ *       Calling this visitor class with array_variable_c instance referencing 'C.e' in
+ *       the line 'C.e := 77', will return the string "C".
+ */
+
+
+#include "absyntax_utils.hh"
+
+
+
+   
+    
+
+get_var_name_c *get_var_name_c::singleton_instance_ = NULL;
+
+
+
+
+token_c *get_var_name_c::get_name(symbol_c *symbol) {
+  if (NULL == singleton_instance_) singleton_instance_ = new get_var_name_c(); 
+  if (NULL == singleton_instance_) ERROR; 
+  
+  return (token_c *)(symbol->accept(*singleton_instance_));
+}
+
+
+/*************************/
+/* B.1 - Common elements */
+/*************************/
+/*******************************************/
+/* B 1.1 - Letters, digits and identifiers */
+/*******************************************/
+// SYM_TOKEN(identifier_c)
+void *get_var_name_c::visit(identifier_c *symbol) {return (void *)symbol;}
+
+/*********************/
+/* B 1.4 - Variables */
+/*********************/
+// SYM_REF2(symbolic_variable_c, var_name, unused)
+void *get_var_name_c::visit(symbolic_variable_c *symbol) {return symbol->var_name->accept(*this);}
+
+/********************************************/
+/* B.1.4.1   Directly Represented Variables */
+/********************************************/
+// SYM_TOKEN(direct_variable_c)
+
+/*************************************/
+/* B.1.4.2   Multi-element Variables */
+/*************************************/
+/*  subscripted_variable '[' subscript_list ']' */
+// SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
+void *get_var_name_c::visit(array_variable_c *symbol) {return symbol->subscripted_variable->accept(*this);}
+
+/* subscript_list ',' subscript */
+// SYM_LIST(subscript_list_c)
+
+/*  record_variable '.' field_selector */
+/*  WARNING: input and/or output variables of function blocks
+ *           may be accessed as fields of a tructured variable!
+ *           Code handling a structured_variable_c must take
+ *           this into account!
+ */
+// SYM_REF2(structured_variable_c, record_variable, field_selector)
+void *get_var_name_c::visit(structured_variable_c *symbol) {return symbol->record_variable->accept(*this);}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax_utils/get_var_name.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -0,0 +1,115 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2012  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)
+ *
+ */
+
+/*
+ *  A small helper visitor class, that will   
+ *  return the name (tokn_c *) of a variable, as it will
+ *  appear in the variable declaration.
+ */
+
+/*  For ex.:
+ *       VAR
+ *          A : int;
+ *          B : ARRAY [1..9] of int;
+ *          C : some_struct_t;
+ *       END_VAR
+ *
+ *          A    := 56;
+ *          B[8] := 99;
+ *          C.e  := 77;
+ *
+ *       Calling this visitor class with symbolic_variable_c instance referencing 'A' in
+ *       the line 'A := 56', will return the string "A".
+ *
+ *       Calling this visitor class with array_variable_c instance referencing 'B[8]' in
+ *       the line 'B[8] := 99', will return the string "B".
+ *
+ *       Calling this visitor class with array_variable_c instance referencing 'C.e' in
+ *       the line 'C.e := 77', will return the string "C".
+ */
+
+
+
+
+class get_var_name_c : public search_visitor_c {    
+  public:
+    get_var_name_c(void)  {};
+    ~get_var_name_c(void) {};  
+    static token_c *get_name(symbol_c *symbol);
+
+  private:
+    static get_var_name_c *singleton_instance_;
+    
+  private:  
+    /*************************/
+    /* B.1 - Common elements */
+    /*************************/
+    /*******************************************/
+    /* B 1.1 - Letters, digits and identifiers */
+    /*******************************************/
+    // SYM_TOKEN(identifier_c)
+    void *visit(identifier_c *symbol);
+
+    /*********************/
+    /* B 1.4 - Variables */
+    /*********************/
+    // SYM_REF2(symbolic_variable_c, var_name, unused)
+    void *visit(symbolic_variable_c *symbol);
+
+    /********************************************/
+    /* B.1.4.1   Directly Represented Variables */
+    /********************************************/
+    // SYM_TOKEN(direct_variable_c)
+    // void *visit(direct_variable_c *symbol);
+
+    /*************************************/
+    /* B.1.4.2   Multi-element Variables */
+    /*************************************/
+    /*  subscripted_variable '[' subscript_list ']' */
+    // SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
+    void *visit(array_variable_c *symbol);
+
+    /* subscript_list ',' subscript */
+    // SYM_LIST(subscript_list_c)
+    // void *visit(subscript_list_c *symbol);
+
+    /*  record_variable '.' field_selector */
+    /*  WARNING: input and/or output variables of function blocks
+     *           may be accessed as fields of a tructured variable!
+     *           Code handling a structured_variable_c must take
+     *           this into account!
+     */
+    // SYM_REF2(structured_variable_c, record_variable, field_selector)
+    void *visit(structured_variable_c *symbol);
+};
+
+
+
--- a/absyntax_utils/search_base_type.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/search_base_type.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -1,7 +1,7 @@
 /*
  *  matiec - a compiler for the programming languages defined in IEC 61131-3
  *
- *  Copyright (C) 2003-2011  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2003-2012  Mario de Sousa (msousa@fe.up.pt)
  *  Copyright (C) 2007-2011  Laurent Bessard and Edouard Tisserant
  *
  *  This program is free software: you can redistribute it and/or modify
@@ -46,25 +46,35 @@
  * we may have FB instances declared of a specific FB type.
  */
 #include "absyntax_utils.hh"
-
-#define ERROR error_exit(__FILE__,__LINE__)
-/* function defined in main.cc */
-extern void error_exit(const char *file_name, int line_no);
+#include "../main.hh" // required for ERROR() and ERROR_MSG() macros.
 
 
 
 search_base_type_c::search_base_type_c(void) {current_type_name = NULL;}
 
-void *search_base_type_c::visit(identifier_c *type_name) {
-  this->current_type_name = 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!! */
-    ERROR;
-
-  return type_decl->accept(*this);
-}
+
+
+
+symbol_c *search_base_type_c::get_basetype_decl(symbol_c *symbol) {
+  if (NULL == symbol)
+    return NULL;
+  
+  return (symbol_c *)symbol->accept(*this);
+}
+
+symbol_c *search_base_type_c::get_basetype_id  (symbol_c *symbol) {
+  if (NULL == symbol)
+    return NULL;
+  
+  current_type_name = NULL; /* just to be on the safe side... */
+  symbol->accept(*this);
+  return (symbol_c *)current_type_name;
+}
+
+
+/* Note by MJS: The following two functions definately do not belong in this class!! Maybe create a new utility class?
+ * I will need to clean this up when the opportunity arises!
+ */
 
 bool search_base_type_c::type_is_subrange(symbol_c* type_decl) {
   this->is_subrange = false;
@@ -78,6 +88,35 @@
   return this->is_enumerated;
 }
 
+
+/*************************/
+/* B.1 - Common elements */
+/*************************/
+
+/*******************************************/
+/* B 1.1 - Letters, digits and identifiers */
+/*******************************************/
+void *search_base_type_c::visit(identifier_c *type_name) {
+  symbol_c *type_decl;
+
+  this->current_type_name = type_name;
+  
+  /* look up the type declaration... */
+  type_decl = type_symtable.find_value(type_name);
+  if (type_decl != type_symtable.end_value())
+    return type_decl->accept(*this);
+    
+  type_decl = function_block_type_symtable.find_value(type_name);
+  if (type_decl != function_block_type_symtable.end_value())
+    return type_decl->accept(*this);
+  
+  /* Type declaration not found!! */
+    ERROR;
+    
+  return NULL;
+}
+
+
 /*********************/
 /* B 1.2 - Constants */
 /*********************/
@@ -92,41 +131,41 @@
   * with all inputs of the same data type.
   * If 'x' were a SINT, then the '30' would have to be a SINT too!
   */
-void *search_base_type_c::visit(real_c *symbol)          	{return (void *)symbol;}
-void *search_base_type_c::visit(neg_real_c *symbol)          	{return (void *)symbol;}
-void *search_base_type_c::visit(integer_c *symbol)       	{return (void *)symbol;}
-void *search_base_type_c::visit(neg_integer_c *symbol)       	{return (void *)symbol;}
-void *search_base_type_c::visit(binary_integer_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(octal_integer_c *symbol) 	{return (void *)symbol;}
-void *search_base_type_c::visit(hex_integer_c *symbol)   	{return (void *)symbol;}
-void *search_base_type_c::visit(boolean_true_c *symbol)   	{return (void *)symbol;}
-void *search_base_type_c::visit(boolean_false_c *symbol)   	{return (void *)symbol;}
+void *search_base_type_c::visit(real_c *symbol)                   {return (void *)symbol;}
+void *search_base_type_c::visit(neg_real_c *symbol)               {return (void *)symbol;}
+void *search_base_type_c::visit(integer_c *symbol)                {return (void *)symbol;}
+void *search_base_type_c::visit(neg_integer_c *symbol)            {return (void *)symbol;}
+void *search_base_type_c::visit(binary_integer_c *symbol)         {return (void *)symbol;}
+void *search_base_type_c::visit(octal_integer_c *symbol)          {return (void *)symbol;}
+void *search_base_type_c::visit(hex_integer_c *symbol)            {return (void *)symbol;}
+void *search_base_type_c::visit(boolean_true_c *symbol)           {return (void *)symbol;}
+void *search_base_type_c::visit(boolean_false_c *symbol)          {return (void *)symbol;}
 
 
 /***********************************/
 /* B 1.3.1 - Elementary Data Types */
 /***********************************/
-void *search_base_type_c::visit(time_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(bool_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(sint_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(int_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(dint_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(lint_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(usint_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(uint_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(udint_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(ulint_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(real_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(lreal_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(date_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(tod_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(dt_type_name_c *symbol)		{return (void *)symbol;}
-void *search_base_type_c::visit(byte_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(word_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(dword_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(lword_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(string_type_name_c *symbol)	{return (void *)symbol;}
-void *search_base_type_c::visit(wstring_type_name_c *symbol)	{return (void *)symbol;}
+void *search_base_type_c::visit(time_type_name_c *symbol)         {return (void *)symbol;}
+void *search_base_type_c::visit(bool_type_name_c *symbol)         {return (void *)symbol;}
+void *search_base_type_c::visit(sint_type_name_c *symbol)         {return (void *)symbol;}
+void *search_base_type_c::visit(int_type_name_c *symbol)          {return (void *)symbol;}
+void *search_base_type_c::visit(dint_type_name_c *symbol)         {return (void *)symbol;}
+void *search_base_type_c::visit(lint_type_name_c *symbol)         {return (void *)symbol;}
+void *search_base_type_c::visit(usint_type_name_c *symbol)        {return (void *)symbol;}
+void *search_base_type_c::visit(uint_type_name_c *symbol)         {return (void *)symbol;}
+void *search_base_type_c::visit(udint_type_name_c *symbol)        {return (void *)symbol;}
+void *search_base_type_c::visit(ulint_type_name_c *symbol)        {return (void *)symbol;}
+void *search_base_type_c::visit(real_type_name_c *symbol)         {return (void *)symbol;}
+void *search_base_type_c::visit(lreal_type_name_c *symbol)        {return (void *)symbol;}
+void *search_base_type_c::visit(date_type_name_c *symbol)         {return (void *)symbol;}
+void *search_base_type_c::visit(tod_type_name_c *symbol)          {return (void *)symbol;}
+void *search_base_type_c::visit(dt_type_name_c *symbol)           {return (void *)symbol;}
+void *search_base_type_c::visit(byte_type_name_c *symbol)         {return (void *)symbol;}
+void *search_base_type_c::visit(word_type_name_c *symbol)         {return (void *)symbol;}
+void *search_base_type_c::visit(dword_type_name_c *symbol)        {return (void *)symbol;}
+void *search_base_type_c::visit(lword_type_name_c *symbol)        {return (void *)symbol;}
+void *search_base_type_c::visit(string_type_name_c *symbol)       {return (void *)symbol;}
+void *search_base_type_c::visit(wstring_type_name_c *symbol)      {return (void *)symbol;}
 
 
 /******************************************************/
@@ -188,7 +227,7 @@
 }
 
 /*  signed_integer DOTDOT signed_integer */
-void *search_base_type_c::visit(subrange_c *symbol) {ERROR; return NULL;} /* should never get called... */
+void *search_base_type_c::visit(subrange_c *symbol)                                     {ERROR; return NULL;} /* should never get called... */
 
 /*  enumerated_type_name ':' enumerated_spec_init */
 void *search_base_type_c::visit(enumerated_type_declaration_c *symbol) {
@@ -204,14 +243,11 @@
 
 /* helper symbol for enumerated_specification->enumerated_spec_init */
 /* enumerated_value_list ',' enumerated_value */
-void *search_base_type_c::visit(enumerated_value_list_c *symbol) {
-  if (NULL == this->current_type_name) ERROR;
-  return (void *)this->current_type_name;
-}
+void *search_base_type_c::visit(enumerated_value_list_c *symbol)                        {return (void *)symbol;}
 
 /* enumerated_type_name '#' identifier */
 // SYM_REF2(enumerated_value_c, type, value)
-void *search_base_type_c::visit(enumerated_value_c *symbol) {ERROR; return NULL;} /* should never get called... */
+void *search_base_type_c::visit(enumerated_value_c *symbol)                             {ERROR; return NULL;} /* should never get called... */
 
 /*  identifier ':' array_spec_init */
 void *search_base_type_c::visit(array_type_declaration_c *symbol) {
@@ -222,28 +258,28 @@
 /* array_specification [ASSIGN array_initialization} */
 /* array_initialization may be NULL ! */
 void *search_base_type_c::visit(array_spec_init_c *symbol) {
+  /* Note that the 'array_specification' may be either an identifier of a previsously defined array type, 
+   * or an array_specification_c, so we can not stop here and simply return a array_spec_init_c, 
+   * especially if we are looking for the base class!
+   */  
   return symbol->array_specification->accept(*this);
 }
 
 /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */
-void *search_base_type_c::visit(array_specification_c *symbol)	{
-  if (NULL == this->current_type_name)
-	this->current_type_name = symbol->non_generic_type_name;
-  return symbol->non_generic_type_name->accept(*this);
-}
+void *search_base_type_c::visit(array_specification_c *symbol)                          {return (void *)symbol;}
 
 /* helper symbol for array_specification */
 /* array_subrange_list ',' subrange */
-void *search_base_type_c::visit(array_subrange_list_c *symbol)	{ERROR; return NULL;} /* should never get called... */
+void *search_base_type_c::visit(array_subrange_list_c *symbol)                          {ERROR; return NULL;} /* should never get called... */
 
 /* array_initialization:  '[' array_initial_elements_list ']' */
 /* helper symbol for array_initialization */
 /* array_initial_elements_list ',' array_initial_elements */
-void *search_base_type_c::visit(array_initial_elements_list_c *symbol)	{ERROR; return NULL;} /* should never get called... */
+void *search_base_type_c::visit(array_initial_elements_list_c *symbol)                  {ERROR; return NULL;} /* should never get called... */
 
 /* integer '(' [array_initial_element] ')' */
 /* array_initial_element may be NULL ! */
-void *search_base_type_c::visit(array_initial_elements_c *symbol)	{ERROR; return NULL;} /* should never get called... */
+void *search_base_type_c::visit(array_initial_elements_c *symbol)                       {ERROR; return NULL;} /* should never get called... */
 
 /*  structure_type_name ':' structure_specification */
 /* NOTE: structure_specification will point to either a
@@ -258,7 +294,7 @@
 
 /*  var1_list ':' structure_type_name */
 void *search_base_type_c::visit(structured_var_declaration_c *symbol) {
-	return symbol->structure_type_name->accept(*this);
+	return symbol;
 }
 
 /* structure_type_name ASSIGN structure_initialization */
@@ -270,20 +306,18 @@
 /* helper symbol for structure_declaration */
 /* structure_declaration:  STRUCT structure_element_declaration_list END_STRUCT */
 /* structure_element_declaration_list structure_element_declaration ';' */
-void *search_base_type_c::visit(structure_element_declaration_list_c *symbol)	{
-  return (void *)symbol;
-}
+void *search_base_type_c::visit(structure_element_declaration_list_c *symbol)           {return (void *)symbol;}
 
 /*  structure_element_name ':' *_spec_init */
-void *search_base_type_c::visit(structure_element_declaration_c *symbol) {ERROR; return NULL;} /* should never get called... */
+void *search_base_type_c::visit(structure_element_declaration_c *symbol)                {ERROR; return NULL;} /* should never get called... */
 
 /* helper symbol for structure_initialization */
 /* structure_initialization: '(' structure_element_initialization_list ')' */
 /* structure_element_initialization_list ',' structure_element_initialization */
-void *search_base_type_c::visit(structure_element_initialization_list_c *symbol) {ERROR; return NULL;} /* should never get called... */
+void *search_base_type_c::visit(structure_element_initialization_list_c *symbol)        {ERROR; return NULL;} /* should never get called... */
 
 /*  structure_element_name ASSIGN value */
-void *search_base_type_c::visit(structure_element_initialization_c *symbol) {ERROR; return NULL;} /* should never get called... */
+void *search_base_type_c::visit(structure_element_initialization_c *symbol)             {ERROR; return NULL;} /* should never get called... */
 
 /*  string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */
 /*
@@ -292,7 +326,7 @@
 					string_type_declaration_size,
 					string_type_declaration_init) // may be == NULL!
 */
-void *search_base_type_c::visit(string_type_declaration_c *symbol)	{return symbol;}
+void *search_base_type_c::visit(string_type_declaration_c *symbol)	                {return (void *)symbol;}
 
   
 
@@ -301,7 +335,24 @@
 /*****************************/
 /*  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)
-void *search_base_type_c::visit(function_block_declaration_c *symbol) {
-  return symbol;
-}
-
+void *search_base_type_c::visit(function_block_declaration_c *symbol)                   {return (void *)symbol;}
+
+
+
+/*********************************************/
+/* B.1.6  Sequential function chart elements */
+/*********************************************/
+/* INITIAL_STEP step_name ':' action_association_list END_STEP */
+// SYM_REF2(initial_step_c, step_name, action_association_list)
+void *search_base_type_c::visit(initial_step_c *symbol) {
+  this->current_type_name = NULL; /* this pseudo data type does not have a type name! */
+  return (void *)symbol;
+}
+
+/* STEP step_name ':' action_association_list END_STEP */
+// SYM_REF2(step_c, step_name, action_association_list)
+void *search_base_type_c::visit(step_c *symbol) {
+  this->current_type_name = NULL; /* this pseudo data type does not have a type name! */
+  return (void *)symbol;
+}
+
--- a/absyntax_utils/search_base_type.hh	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/search_base_type.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -1,7 +1,7 @@
 /*
  *  matiec - a compiler for the programming languages defined in IEC 61131-3
  *
- *  Copyright (C) 2003-2011  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2003-2012  Mario de Sousa (msousa@fe.up.pt)
  *  Copyright (C) 2007-2011  Laurent Bessard and Edouard Tisserant
  *
  *  This program is free software: you can redistribute it and/or modify
@@ -60,18 +60,27 @@
     search_base_type_c(void);
 
   public:
-    void *visit(identifier_c *type_name);
+    symbol_c *get_basetype_decl(symbol_c *symbol);
+    symbol_c *get_basetype_id  (symbol_c *symbol);
     bool type_is_subrange(symbol_c* type_decl);
     bool type_is_enumerated(symbol_c* type_decl);
 
   public:
-    /*********************/
-    /* B 1.2 - Constants */
-    /*********************/
-
-    /******************************/
-    /* B 1.2.1 - Numeric Literals */
-    /******************************/
+  /*************************/
+  /* B.1 - Common elements */
+  /*************************/
+  /*******************************************/
+  /* B 1.1 - Letters, digits and identifiers */
+  /*******************************************/
+    void *visit(identifier_c *type_name);
+
+    
+  /*********************/
+  /* B 1.2 - Constants */
+  /*********************/
+  /******************************/
+  /* B 1.2.1 - Numeric Literals */
+  /******************************/
      /* Numeric literals without any explicit type cast have unknown data type, 
       * so we continue considering them as their own basic data types until
       * they can be resolved (for example, when using '30+x' where 'x' is a LINT variable, the
@@ -227,6 +236,18 @@
   // SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body)
     void *visit(function_block_declaration_c *symbol);
 
+  /*********************************************/
+  /* B.1.6  Sequential function chart elements */
+  /*********************************************/
+  /* INITIAL_STEP step_name ':' action_association_list END_STEP */
+  // SYM_REF2(initial_step_c, step_name, action_association_list)
+    void *visit(initial_step_c *symbol);
+
+  /* STEP step_name ':' action_association_list END_STEP */
+  // SYM_REF2(step_c, step_name, action_association_list)
+    void *visit(step_c *symbol);
+
+
 }; // search_base_type_c
 
 
--- a/absyntax_utils/search_constant_type.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/search_constant_type.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -44,11 +44,9 @@
 #include "../util/symtable.hh"
 #include "search_constant_type.hh"
 #include "absyntax_utils.hh"
+#include "../main.hh" // required for ERROR() and ERROR_MSG() macros.
 
 
-#define ERROR error_exit(__FILE__,__LINE__)
-/* function defined in main.cc */
-extern void error_exit(const char *file_name, int line_no);
 
 symbol_c *search_constant_type_c::get_type(symbol_c *constant) {
   return (symbol_c *)constant->accept(*this);
@@ -105,11 +103,7 @@
 void *search_constant_type_c::visit(neg_time_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
 void *search_constant_type_c::visit(duration_c *symbol) {return (void *)(symbol->type_name);}
 void *search_constant_type_c::visit(fixed_point_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
-void *search_constant_type_c::visit(days_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
-void *search_constant_type_c::visit(hours_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
-void *search_constant_type_c::visit(minutes_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
-void *search_constant_type_c::visit(seconds_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
-void *search_constant_type_c::visit(milliseconds_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
+void *search_constant_type_c::visit(interval_c *symbol) {ERROR; return NULL;}  /* this member function should never be called. */
 
 /************************************/
 /* B 1.2.3.2 - Time of day and Date */
@@ -133,6 +127,12 @@
   return (void *)value_type;
 }
 
+
+
+
+invalid_type_name_c  search_constant_type_c::invalid_type_name;
+
+
 real_type_name_c     search_constant_type_c::real_type_name;
 sint_type_name_c     search_constant_type_c::sint_type_name;
 lint_type_name_c     search_constant_type_c::lint_type_name;
@@ -155,17 +155,26 @@
 time_type_name_c     search_constant_type_c::time_type_name;
 int_type_name_c      search_constant_type_c::int_type_name;
 
-// safebool_type_name_c    search_constant_type_c::safebool_type_name;
-  /* The following is required because the expression (TOD_var - TOD_var) will result in a data type
-   *  (in this case, TIME) that is neither of the expression elements...
-   */
 safetime_type_name_c     search_constant_type_c::safetime_type_name;
 safetod_type_name_c      search_constant_type_c::safetod_type_name;
 safedt_type_name_c       search_constant_type_c::safedt_type_name;
+safedate_type_name_c     search_constant_type_c::safedate_type_name;
+safereal_type_name_c     search_constant_type_c::safereal_type_name;
+safesint_type_name_c     search_constant_type_c::safesint_type_name;
+safelint_type_name_c     search_constant_type_c::safelint_type_name;
+safedint_type_name_c     search_constant_type_c::safedint_type_name;
+safedword_type_name_c    search_constant_type_c::safedword_type_name;
+safeudint_type_name_c    search_constant_type_c::safeudint_type_name;
+safeword_type_name_c     search_constant_type_c::safeword_type_name;
+safewstring_type_name_c  search_constant_type_c::safewstring_type_name;
+safestring_type_name_c   search_constant_type_c::safestring_type_name;
+safelword_type_name_c    search_constant_type_c::safelword_type_name;
+safeuint_type_name_c     search_constant_type_c::safeuint_type_name;
+safelreal_type_name_c    search_constant_type_c::safelreal_type_name;
+safebyte_type_name_c     search_constant_type_c::safebyte_type_name;
+safeusint_type_name_c    search_constant_type_c::safeusint_type_name;
+safeulint_type_name_c    search_constant_type_c::safeulint_type_name;
+safebool_type_name_c     search_constant_type_c::safebool_type_name;
+safeint_type_name_c      search_constant_type_c::safeint_type_name;
 
 
-
-/* temporarily here until we remove the st_code_gen.c and il_code_gen.c files... */
-/* It should then move to search_expression_type_c                               */
-integer_c search_constant_type_c::integer("1");
-real_c search_constant_type_c::real("1.0");
--- a/absyntax_utils/search_constant_type.hh	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/search_constant_type.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -30,6 +30,14 @@
  *
  */
 
+/* NOTE: The use of this visitor class is now deprecated.
+ *       The new version of stage3 data type checking adds an entry to
+ *       every relevant object in the abstract syntax tree defining
+ *       the data type of that object. Please use that instead!
+ */
+
+
+
 /* Determine the data type of a specific constant or variable.
  * A reference to the relevant type definition is returned.
  *
@@ -49,6 +57,10 @@
 class search_constant_type_c: public search_visitor_c {
 
   public:
+  /* object used to identify an entry in the abstract syntax tree with an invalid data type */
+  /* This is only used from stage3 onwards. Stages 1 and 2 will never create any instances of invalid_type_name_c */
+  static invalid_type_name_c     invalid_type_name;
+
   /**********************/
   /* B.1.3 - Data types */
   /**********************/
@@ -77,9 +89,6 @@
   static time_type_name_c     time_type_name;
   static int_type_name_c      int_type_name;
 
-/* temporarily here until we remove the st_code_gen.c and il_code_gen.c files... */
-  static integer_c      integer;
-  static real_c			real;
 
   /******************************************************/
   /* Extensions to the base standard as defined in      */
@@ -96,8 +105,24 @@
   static safetime_type_name_c     safetime_type_name;
   static safetod_type_name_c      safetod_type_name;
   static safedt_type_name_c       safedt_type_name;
-
-
+  static safedate_type_name_c     safedate_type_name;
+  static safereal_type_name_c     safereal_type_name;
+  static safesint_type_name_c     safesint_type_name;
+  static safelint_type_name_c     safelint_type_name;
+  static safedint_type_name_c     safedint_type_name;
+  static safedword_type_name_c    safedword_type_name;
+  static safeudint_type_name_c    safeudint_type_name;
+  static safeword_type_name_c     safeword_type_name;
+  static safewstring_type_name_c  safewstring_type_name;
+  static safestring_type_name_c   safestring_type_name;
+  static safelword_type_name_c    safelword_type_name;
+  static safeuint_type_name_c     safeuint_type_name;
+  static safelreal_type_name_c    safelreal_type_name;
+  static safebyte_type_name_c     safebyte_type_name;
+  static safeusint_type_name_c    safeusint_type_name;
+  static safeulint_type_name_c    safeulint_type_name;
+  static safebool_type_name_c     safebool_type_name;
+  static safeint_type_name_c      safeint_type_name;
 
   public:
     symbol_c *get_type(symbol_c *constant);
@@ -141,12 +166,8 @@
     /************************/
     void *visit(neg_time_c *symbol);
     void *visit(duration_c *symbol);
+    void *visit(interval_c *symbol);
     void *visit(fixed_point_c *symbol);
-    void *visit(days_c *symbol);
-    void *visit(hours_c *symbol);
-    void *visit(minutes_c *symbol);
-    void *visit(seconds_c *symbol);
-    void *visit(milliseconds_c *symbol);
 
     /************************************/
     /* B 1.2.3.2 - Time of day and Date */
@@ -164,5 +185,4 @@
 };  // search_constant_type_c
 
 
-
 #endif /* ifndef _SEARCH_CONSTANT_TYPE_HH */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax_utils/search_il_label.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -0,0 +1,97 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2012  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)
+ *
+ */
+
+
+/*
+ *  Search for a specific label in an IL list. 
+ *
+ *  when instantiated, must be given a pointer to one of the following
+ *     - function_declaration_c
+ *     - function_block_declaration_c
+ *     - program_declaration_c
+ *     - instruction_list_c
+ *
+ * which is where all calls to search for a specific label will look for said label.
+ */
+
+
+
+#include "absyntax_utils.hh"
+
+
+
+/* set to 1 to see debug info during execution */
+static int debug = 0;
+
+search_il_label_c::search_il_label_c(symbol_c *search_scope) {
+  this->search_scope = search_scope;
+  this->search_label = NULL;
+}
+
+search_il_label_c::~search_il_label_c(void) {
+}
+
+
+il_instruction_c *search_il_label_c::find_label(const char *label) {
+  return find_label(new identifier_c(label));
+}
+
+
+il_instruction_c *search_il_label_c::find_label(symbol_c *label) {
+  search_label = label;
+  il_instruction_c *res = (il_instruction_c *)search_scope->accept(*this);
+  search_label = NULL;
+  return res;
+}
+
+
+/****************************************/
+/* B.2 - Language IL (Instruction List) */
+/****************************************/
+/***********************************/
+/* B 2.1 Instructions and Operands */
+/***********************************/
+
+/* | label ':' [il_incomplete_instruction] eol_list */
+// SYM_REF2(il_instruction_c, label, il_instruction)
+// void *visit(instruction_list_c *symbol);
+void *search_il_label_c::visit(il_instruction_c *symbol) {
+// printf("search_il_label_c::visit(il_instruction_c *symbol): searching for %s\n", ((identifier_c *)search_label)->value);
+	if (NULL != symbol->label)
+		if (compare_identifiers(search_label, symbol->label) == 0)
+			return symbol;
+
+	return NULL;
+}
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/absyntax_utils/search_il_label.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -0,0 +1,95 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2012  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)
+ *
+ */
+
+
+/*
+ *  Search for a specific label in an IL list. 
+ *
+ *  when instantiated, must be given a pointer to one of the following
+ *     - function_declaration_c
+ *     - function_block_declaration_c
+ *     - program_declaration_c
+ *     - instruction_list_c
+ *
+ * which is where all calls to search for a specific label will look for said label.
+ */
+
+
+
+#include "../absyntax_utils/absyntax_utils.hh"
+
+
+class search_il_label_c: public search_visitor_c {
+
+  private:
+    search_varfb_instance_type_c *search_varfb_instance_type;
+    symbol_c *search_scope;
+    symbol_c *search_label;
+
+  public:
+    search_il_label_c(symbol_c *search_scope);
+    virtual ~search_il_label_c(void);
+
+    il_instruction_c *find_label(const char *label);
+    il_instruction_c *find_label(symbol_c   *label);
+
+    
+    /****************************************/
+    /* B.2 - Language IL (Instruction List) */
+    /****************************************/
+    /***********************************/
+    /* B 2.1 Instructions and Operands */
+    /***********************************/
+//     void *visit(instruction_list_c *symbol);
+    void *visit(il_instruction_c *symbol);
+//     void *visit(il_simple_operation_c *symbol);
+//     void *visit(il_function_call_c *symbol);
+//     void *visit(il_expression_c *symbol);
+//     void *visit(il_fb_call_c *symbol);
+//     void *visit(il_formal_funct_call_c *symbol);
+//     void *visit(il_operand_list_c *symbol);
+//     void *visit(simple_instr_list_c *symbol);
+//     void *visit(il_simple_instruction_c*symbol);
+//     void *visit(il_param_list_c *symbol);
+//     void *visit(il_param_assignment_c *symbol);
+//     void *visit(il_param_out_assignment_c *symbol);
+
+
+}; // search_il_label_c
+
+
+
+
+
+
+
+
--- a/absyntax_utils/search_var_instance_decl.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/search_var_instance_decl.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -30,27 +30,51 @@
  *
  */
 
-/* Determine the data type of a specific variable instance, including
- * function block instances.
- * A reference to the relevant variable declaration is returned.
- * The variable instance may NOT be a member of a structure of a member
+/* Search in a VAR* END_VAR declaration for the delcration of the specified variable instance. 
+ * Will return:
+ *     - the declaration itself (get_decl() )
+ *     - the type of declaration in which the variable was declared (get_vartype() )
+ *
+ * The variable instance may NOT be a member of a structure of a memeber
  * of a structure of an element of an array of ...
  *
- * example:
+ * For example, considering the following 'variables':
  *    window.points[1].coordinate.x
  *    window.points[1].colour
- *    etc... ARE NOT ALLOWED!
+ *    offset[99]
+ *
+ *   passing a reference to 'points', 'points[1]', 'points[1].colour', 'colour'
+ *    ARE NOT ALLOWED!
  *
  * This class must only be passed the name of the variable that will appear
  * in the variable declaration. In the above examples, this would be
- *   'window' !!
- *
- *
- * If you need to pass a complete name of a variable instance (such as
- * 'window.points[1].coordinate.x') use the search_varfb_instance_type_c instead!
+ *   'window.points[1].coordinate.x'
+ *   'window.points[1].coordinate'
+ *   'window.points[1]'
+ *   'window'
+ *   'window.points[1].colour'
+ *   'offset'
+ *   'offset[99]'
+ *
+ *
  */
-
-/* Note that current_type_decl that this class returns may reference the
+ 
+/* Note: 
+ * Determining the declaration type of a specific variable instance (including
+ * function block instances) really means determining whether the variable was declared in a
+ *  VAR_INPUT
+ *  VAR_OUTPUT
+ *  VAR_IN_OUT
+ *  VAR
+ *  VAR_TEMP
+ *  VAR_EXTERNAL
+ *  VAR_GLOBAL
+ *  VAR <var_name> AT <location>   -> Located variable!
+ * 
+ */
+
+/* Note:
+ *  The current_type_decl that this class returns may reference the
  * name of a type, or the type declaration itself!
  * For an example of the first, consider a variable declared as ...
  * x : AAA;
@@ -61,25 +85,71 @@
  * If it is the first, we will return a reference to the name, if the second
  * we return a reference to the declaration!!
  */
+
+
 #include "absyntax_utils.hh"
 
 
+
+
+
 search_var_instance_decl_c::search_var_instance_decl_c(symbol_c *search_scope) {
   this->current_vartype = none_vt;
   this->search_scope = search_scope;
   this->search_name = NULL;
   this->current_type_decl = NULL;
-}
-
-symbol_c *search_var_instance_decl_c::get_decl(symbol_c *variable_instance_name) {
+  this->current_option = none_opt;
+}
+
+symbol_c *search_var_instance_decl_c::get_decl(symbol_c *variable) {
   this->current_vartype = none_vt;
-  this->search_name = variable_instance_name;
+  this->current_option  = none_opt;
+  this->search_name = get_var_name_c::get_name(variable);
   return (symbol_c *)search_scope->accept(*this);
 }
 
-unsigned int search_var_instance_decl_c::get_vartype(void) {
-  return current_vartype;
-}
+search_var_instance_decl_c::vt_t search_var_instance_decl_c::get_vartype(symbol_c *variable) {
+  this->current_vartype = none_vt;
+  this->current_option  = none_opt;
+  this->search_name = get_var_name_c::get_name(variable);
+  search_scope->accept(*this);
+  return this->current_vartype;
+}
+
+search_var_instance_decl_c::opt_t search_var_instance_decl_c::get_option(symbol_c *variable) {
+  this->current_vartype = none_vt;
+  this->current_option  = none_opt;
+  this->search_name = get_var_name_c::get_name(variable);
+  search_scope->accept(*this);
+  return this->current_option;
+}
+
+
+
+/* This is a temporary fix. Hopefully, once I clean up stage4 code, and I change the way
+ * we generate C code, this function will no longer be needed!
+ */
+#include <typeinfo>  /* required for typeid() */
+bool search_var_instance_decl_c::type_is_complex(symbol_c *symbol) {
+  symbol_c *decl;
+  search_base_type_c search_base_type;
+  
+  decl = this->get_decl(symbol);
+  if (NULL == decl) ERROR;
+  decl = search_base_type.get_basetype_decl(decl);
+  if (NULL == decl) ERROR;
+  
+  return ((typeid( *(decl) ) == typeid( array_specification_c                )) ||
+//        (typeid( *(decl) ) == typeid( array_spec_init_c                    )) ||  /* does not seem to be necessary */
+          (typeid( *(decl) ) == typeid( structure_type_declaration_c         )) ||  
+          (typeid( *(decl) ) == typeid( structure_element_declaration_list_c )) ||
+//        (typeid( *(decl) ) == typeid( structure_type_declaration_c         )) ||  /* does not seem to be necessary */
+          (typeid( *(decl) ) == typeid( initialized_structure_c              ))
+          
+         );
+}
+
+
 
 /***************************/
 /* B 0 - Programming Model */
@@ -100,12 +170,30 @@
 /* edge -> The F_EDGE or R_EDGE directive */
 // SYM_REF2(edge_declaration_c, edge, var1_list)
 // TODO
+void *search_var_instance_decl_c::visit(constant_option_c *symbol) {
+  current_option = constant_opt;
+  return NULL;
+}
+
+void *search_var_instance_decl_c::visit(retain_option_c *symbol) {
+  current_option = retain_opt;
+  return NULL;
+}
+
+void *search_var_instance_decl_c::visit(non_retain_option_c *symbol) {
+  current_option = non_retain_opt;
+  return NULL;
+}
 
 void *search_var_instance_decl_c::visit(input_declarations_c *symbol) {
   current_vartype = input_vt;
+  current_option  = none_opt; /* not really required. Just to make the code more readable */
+  if (NULL != symbol->option)  
+    symbol->option->accept(*this);
   void *res = symbol->input_declaration_list->accept(*this);
   if (res == NULL) {
     current_vartype = none_vt;
+    current_option  = none_opt;
   }
   return res;
 }
@@ -114,9 +202,13 @@
 /* option -> may be NULL ! */
 void *search_var_instance_decl_c::visit(output_declarations_c *symbol) {
   current_vartype = output_vt;
+  current_option  = none_opt; /* not really required. Just to make the code more readable */
+  if (NULL != symbol->option)
+    symbol->option->accept(*this);
   void *res = symbol->var_init_decl_list->accept(*this);
   if (res == NULL) {
     current_vartype = none_vt;
+    current_option  = none_opt;
   }
   return res;
 }
@@ -124,6 +216,7 @@
 /*  VAR_IN_OUT var_declaration_list END_VAR */
 void *search_var_instance_decl_c::visit(input_output_declarations_c *symbol) {
   current_vartype = inoutput_vt;
+  current_option  = none_opt; /* not really required. Just to make the code more readable */
   void *res = symbol->var_declaration_list->accept(*this);
   if (res == NULL) {
     current_vartype = none_vt;
@@ -144,9 +237,13 @@
 /* helper symbol for input_declarations */
 void *search_var_instance_decl_c::visit(var_declarations_c *symbol) {
   current_vartype = private_vt;
+  current_option  = none_opt; /* not really required. Just to make the code more readable */
+  if (NULL != symbol->option)
+    symbol->option->accept(*this);
   void *res = symbol->var_init_decl_list->accept(*this);
   if (res == NULL) {
     current_vartype = none_vt;
+    current_option = none_opt;
   }
   return res;
 }
@@ -154,9 +251,11 @@
 /*  VAR RETAIN var_init_decl_list END_VAR */
 void *search_var_instance_decl_c::visit(retentive_var_declarations_c *symbol) {
   current_vartype = private_vt;
+  current_option  = retain_opt;
   void *res = symbol->var_init_decl_list->accept(*this);
   if (res == NULL) {
     current_vartype = none_vt;
+    current_option = none_opt;
   }
   return res;
 }
@@ -166,9 +265,13 @@
 //SYM_REF2(located_var_declarations_c, option, located_var_decl_list)
 void *search_var_instance_decl_c::visit(located_var_declarations_c *symbol) {
   current_vartype = located_vt;
+  current_option  = none_opt; /* not really required. Just to make the code more readable */
+  if (NULL != symbol->option)
+    symbol->option->accept(*this);
   void *res = symbol->located_var_decl_list->accept(*this);
   if (res == NULL) {
     current_vartype = none_vt;
+    current_option  = none_opt;
   }
   return res;
 }
@@ -178,9 +281,13 @@
 //SYM_REF2(external_var_declarations_c, option, external_declaration_list)
 void *search_var_instance_decl_c::visit(external_var_declarations_c *symbol) {
   current_vartype = external_vt;
+  current_option  = none_opt; /* not really required. Just to make the code more readable */
+  if (NULL != symbol->option)
+    symbol->option->accept(*this);
   void *res = symbol->external_declaration_list->accept(*this);
   if (res == NULL) {
     current_vartype = none_vt;
+    current_option = none_opt;
   }
   return res;
 }
@@ -190,9 +297,13 @@
 //SYM_REF2(global_var_declarations_c, option, global_var_decl_list)
 void *search_var_instance_decl_c::visit(global_var_declarations_c *symbol) {
   current_vartype = global_vt;
+  current_option  = none_opt; /* not really required. Just to make the code more readable */
+  if (NULL != symbol->option)
+    symbol->option->accept(*this);
   void *res = symbol->global_var_decl_list->accept(*this);
   if (res == NULL) {
     current_vartype = none_vt;
+    current_option = none_opt;
   }
   return res;
 }
@@ -232,7 +343,7 @@
   list_c *list = symbol;
   for(int i = 0; i < list->n; i++) {
     if (compare_identifiers(list->elements[i], search_name) == 0)
-  /* by now, current_fb_declaration should be != NULL */
+    /* by now, current_fb_declaration should be != NULL */
       return current_type_decl;
   }
   return NULL;
@@ -262,7 +373,7 @@
 /*  var1_list ':' structure_type_name */
 // SYM_REF2(structured_var_declaration_c, var1_list, structure_type_name)
 void *search_var_instance_decl_c::visit(structured_var_declaration_c *symbol) {
-  current_type_decl = symbol;
+  current_type_decl = symbol->structure_type_name;
   return symbol->var1_list->accept(*this);
 }
 
@@ -400,21 +511,62 @@
 /*****************************/
 /* 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)
 void *search_var_instance_decl_c::visit(function_block_declaration_c *symbol) {
-  /* no need to search through all the body, so we only
-   * visit the variable declarations...!
-   */
-  return symbol->var_declarations->accept(*this);
+  /* visit the variable declarations...! */
+  void *res = symbol->var_declarations->accept(*this);
+  if (NULL != res)
+    return res;
+  
+  /* not yet found, so we look into the body, to see if it is an SFC step! */
+  return symbol->fblock_body->accept(*this);
 }
 
 /**********************/
 /* 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)
 void *search_var_instance_decl_c::visit(program_declaration_c *symbol) {
-  /* no need to search through all the body, so we only
-   * visit the variable declarations...!
-   */
-  return symbol->var_declarations->accept(*this);
+  /* visit the variable declarations...! */
+  void *res = symbol->var_declarations->accept(*this);
+  if (NULL != res)
+    return res;
+  
+  /* not yet found, so we look into the body, to see if it is an SFC step! */
+  return symbol->function_block_body->accept(*this);
+}
+
+
+/*********************************************/
+/* B.1.6  Sequential function chart elements */
+/*********************************************/
+/* | sequential_function_chart sfc_network */
+// SYM_LIST(sequential_function_chart_c)
+/* search_var_instance_decl_c inherits from serach_visitor_c, so no need to implement the following method. */
+// void *search_var_instance_decl_c::visit(sequential_function_chart_c *symbol) {...}
+
+/* initial_step {step | transition | action} */
+// SYM_LIST(sfc_network_c)
+/* search_var_instance_decl_c inherits from serach_visitor_c, so no need to implement the following method. */
+// void *search_var_instance_decl_c::visit(sfc_network_c *symbol) {...}
+
+
+/* INITIAL_STEP step_name ':' action_association_list END_STEP */
+// SYM_REF2(initial_step_c, step_name, action_association_list)
+void *search_var_instance_decl_c::visit(initial_step_c *symbol) {
+  if (compare_identifiers(symbol->step_name, search_name) == 0)
+      return symbol;
+  return NULL;
+}
+
+/* STEP step_name ':' action_association_list END_STEP */
+// SYM_REF2(step_c, step_name, action_association_list)
+void *search_var_instance_decl_c::visit(step_c *symbol) {
+  if (compare_identifiers(symbol->step_name, search_name) == 0)
+      return symbol;
+  return NULL;
 }
 
 
@@ -469,35 +621,30 @@
   return NULL;
 }
 
-#if 0
-/*********************/
-/* B 1.4 - Variables */
-/*********************/
-SYM_REF2(symbolic_variable_c, var_name, unused)
-
-/********************************************/
-/* B.1.4.1   Directly Represented Variables */
-/********************************************/
-SYM_TOKEN(direct_variable_c)
-
-/*************************************/
-/* B.1.4.2   Multi-element Variables */
-/*************************************/
-/*  subscripted_variable '[' subscript_list ']' */
-SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
-
-/* subscript_list ',' subscript */
-SYM_LIST(subscript_list_c)
-
-/*  record_variable '.' field_selector */
-/*  WARNING: input and/or output variables of function blocks
- *           may be accessed as fields of a tructured variable!
- *           Code handling a structured_variable_c must take
- *           this into account!
- */
-SYM_REF2(structured_variable_c, record_variable, field_selector)
-
-
-
-};
-#endif
+
+
+/****************************************/
+/* B.2 - Language IL (Instruction List) */
+/****************************************/
+/***********************************/
+/* B 2.1 Instructions and Operands */
+/***********************************/
+/*| instruction_list il_instruction */
+// SYM_LIST(instruction_list_c)
+void *search_var_instance_decl_c::visit(instruction_list_c *symbol) {
+  /* IL code does not contain any variable declarations! */
+  return NULL;
+}
+
+
+/***************************************/
+/* B.3 - Language ST (Structured Text) */
+/***************************************/
+/********************/
+/* B 3.2 Statements */
+/********************/
+// SYM_LIST(statement_list_c)
+void *search_var_instance_decl_c::visit(statement_list_c *symbol) {
+  /* ST code does not contain any variable declarations! */
+  return NULL;
+}
--- a/absyntax_utils/search_var_instance_decl.hh	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/search_var_instance_decl.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -31,26 +31,51 @@
  */
 
 
-/* Determine the data type of a specific variable instance, including
- * function block instances.
- * A reference to the relevant variable declaration is returned.
+/* Search in a VAR* END_VAR declaration for the delcration of the specified variable instance. 
+ * Will return:
+ *     - the declaration itself (get_decl() )
+ *     - the type of declaration in which the variable was declared (get_vartype() )
+ *
  * The variable instance may NOT be a member of a structure of a memeber
  * of a structure of an element of an array of ...
  *
- * example:
+ * For example, considering the following 'variables':
  *    window.points[1].coordinate.x
  *    window.points[1].colour
- *    etc... ARE NOT ALLOWED!
+ *    offset[99]
+ *
+ *   passing a reference to 'points', 'points[1]', 'points[1].colour', 'colour'
+ *    ARE NOT ALLOWED!
  *
  * This class must only be passed the name of the variable that will appear
  * in the variable declaration. In the above examples, this would be
- *   'window' !!
- *
- *
- * If you need to pass a complete name of a variable instance (such as
- * 'window.points[1].coordinate.x') use the search_varfb_instance_type_c instead!
- */
-/* Note that current_type_decl that this class returns may reference the
+ *   'window.points[1].coordinate.x'
+ *   'window.points[1].coordinate'
+ *   'window.points[1]'
+ *   'window'
+ *   'window.points[1].colour'
+ *   'offset'
+ *   'offset[99]'
+ *
+ *
+ */
+ 
+/* Note: 
+ * Determining the declaration type of a specific variable instance (including
+ * function block instances) really means determining whether the variable was declared in a
+ *  VAR_INPUT
+ *  VAR_OUTPUT
+ *  VAR_IN_OUT
+ *  VAR
+ *  VAR_TEMP
+ *  VAR_EXTERNAL
+ *  VAR_GLOBAL
+ *  VAR <var_name> AT <location>   -> Located variable!
+ * 
+ */
+
+/* Note:
+ *  The current_type_decl that this class returns may reference the
  * name of a type, or the type declaration itself!
  * For an example of the first, consider a variable declared as ...
  * x : AAA;
@@ -65,22 +90,29 @@
 
 class search_var_instance_decl_c: public search_visitor_c {
 
-  private:
-    symbol_c *search_scope;
-    symbol_c *search_name;
-    symbol_c *current_type_decl;
-
-    /* variable used to store the type of variable currently being processed... */
-    /* Will contain a single value of generate_c_vardecl_c::XXXX_vt */
-    unsigned int current_vartype;
-
   public:
     search_var_instance_decl_c(symbol_c *search_scope);
-    symbol_c *get_decl(symbol_c *variable_instance_name);
-    unsigned int get_vartype(void);
 
   public:
-
+    typedef enum {
+        input_vt   ,  // VAR_INPUT
+        output_vt  ,  // VAR_OUTPUT
+        inoutput_vt,  // VAR_IN_OUT
+        private_vt ,  // VAR
+        temp_vt    ,  // VAR_TEMP
+        external_vt,  // VAR_EXTERNAL
+        global_vt  ,  // VAR_GLOBAL
+        located_vt ,   // VAR <var_name> AT <location>
+        none_vt
+      } vt_t;
+      
+    typedef enum {
+        constant_opt  ,
+        retain_opt    ,
+        non_retain_opt,
+        none_opt
+      } opt_t;
+#if 0        
     /* the types of variables that need to be processed... */
     static const unsigned int none_vt     = 0x0000;
     static const unsigned int input_vt    = 0x0001;  // VAR_INPUT
@@ -92,6 +124,34 @@
     static const unsigned int global_vt   = 0x0040;  // VAR_GLOBAL
     static const unsigned int located_vt  = 0x0080;  // VAR <var_name> AT <location>
 
+    static const unsigned int none_opt        = 0x0000;
+    static const unsigned int constant_opt    = 0x0001;
+    static const unsigned int retain_opt      = 0x0002;
+    static const unsigned int non_retain_opt  = 0x0003;
+#endif    
+    
+    symbol_c *   get_decl   (symbol_c *variable_instance_name); 
+    vt_t         get_vartype(symbol_c *variable_instance_name);
+    opt_t        get_option (symbol_c *variable_instance_name);
+
+    /* NOTE: The following function will be completely deleted in the (hopefully near) future. */
+    /* Returns true if the variable is an ARRAY or a STRUCT, otherwise returns false.
+     * Note that for FB, also returns false!
+     */
+    bool type_is_complex(symbol_c *variable_name);
+
+    
+    
+  private:
+    symbol_c *search_scope;
+    symbol_c *search_name;
+    symbol_c *current_type_decl;
+    /* variable used to store the type of variable currently being processed... */
+    /* Will contain a single value of generate_c_vardecl_c::XXXX_vt */
+    vt_t  current_vartype;
+    opt_t current_option;
+
+    
   private:
     /***************************/
     /* B 0 - Programming Model */
@@ -105,6 +165,11 @@
     /* edge -> The F_EDGE or R_EDGE directive */
     // SYM_REF2(edge_declaration_c, edge, var1_list)
     // TODO
+    void *visit(constant_option_c *symbol);
+    void *visit(retain_option_c *symbol);
+    void *visit(non_retain_option_c *symbol);
+
+
     void *visit(input_declarations_c *symbol);
     /* VAR_OUTPUT [RETAIN | NON_RETAIN] var_init_decl_list END_VAR */
     /* option -> may be NULL ! */
@@ -236,6 +301,28 @@
     /**********************/
     void *visit(program_declaration_c *symbol);
 
+    /*********************************************/
+    /* B.1.6  Sequential function chart elements */
+    /*********************************************/
+    /* | sequential_function_chart sfc_network */
+    // SYM_LIST(sequential_function_chart_c)
+    /* search_var_instance_decl_c inherits from serach_visitor_c, so no need to implement the following method. */
+    // void *visit(sequential_function_chart_c *symbol);
+    
+    /* initial_step {step | transition | action} */
+    // SYM_LIST(sfc_network_c)
+    /* search_var_instance_decl_c inherits from serach_visitor_c, so no need to implement the following method. */
+    // void *visit(sfc_network_c *symbol);
+
+
+    /* INITIAL_STEP step_name ':' action_association_list END_STEP */
+    // SYM_REF2(initial_step_c, step_name, action_association_list)
+    void *visit(initial_step_c *symbol);
+
+    /* STEP step_name ':' action_association_list END_STEP */
+    // SYM_REF2(step_c, step_name, action_association_list)
+    void *visit(step_c *symbol);
+
     /********************************/
     /* B 1.7 Configuration elements */
     /********************************/
@@ -265,34 +352,26 @@
     // SYM_REF2(single_resource_declaration_c, task_configuration_list, program_configuration_list)
     void *visit(single_resource_declaration_c *symbol);
 
-#if 0
-/*********************/
-/* B 1.4 - Variables */
-/*********************/
-SYM_REF2(symbolic_variable_c, var_name, unused)
-
-/********************************************/
-/* B.1.4.1   Directly Represented Variables */
-/********************************************/
-SYM_TOKEN(direct_variable_c)
-
-/*************************************/
-/* B.1.4.2   Multi-element Variables */
-/*************************************/
-/*  subscripted_variable '[' subscript_list ']' */
-SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
-
-/* subscript_list ',' subscript */
-SYM_LIST(subscript_list_c)
-
-/*  record_variable '.' field_selector */
-/*  WARNING: input and/or output variables of function blocks
- *           may be accessed as fields of a tructured variable!
- *           Code handling a structured_variable_c must take
- *           this into account!
- */
-SYM_REF2(structured_variable_c, record_variable, field_selector)
-#endif
+    
+    /****************************************/
+    /* B.2 - Language IL (Instruction List) */
+    /****************************************/
+    /***********************************/
+    /* B 2.1 Instructions and Operands */
+    /***********************************/
+    /*| instruction_list il_instruction */
+    // SYM_LIST(instruction_list_c)
+    void *visit(instruction_list_c *symbol);
+
+
+    /***************************************/
+    /* B.3 - Language ST (Structured Text) */
+    /***************************************/
+    /********************/
+    /* B 3.2 Statements */
+    /********************/
+    // SYM_LIST(statement_list_c)
+    void *visit(statement_list_c *symbol);
 
 }; // search_var_instance_decl_c
 
--- a/absyntax_utils/search_varfb_instance_type.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/search_varfb_instance_type.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -1,7 +1,7 @@
 /*
  *  matiec - a compiler for the programming languages defined in IEC 61131-3
  *
- *  Copyright (C) 2003-2011  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2003-2012  Mario de Sousa (msousa@fe.up.pt)
  *  Copyright (C) 2007-2011  Laurent Bessard and Edouard Tisserant
  *
  *  This program is free software: you can redistribute it and/or modify
@@ -75,225 +75,143 @@
  *
  * Member functions:
  * ================
+ *   get_basetype_id()    ---> returns 2A   (implemented, although currently it is not needed! )
  *   get_basetype_decl()  ---> returns 2B 
  *   get_type_id()        ---> returns 1A
  * 
- *   Since we haven't yet needed them, we don't yet implement
- *   get_basetype_id()    ----> would return 2A
- *   get_type_decl()      ----> would return 1B
+ *   Since we haven't yet needed it, we don't yet implement
+ *   get_type_decl()      ---> returns 1B 
  */ 
 
 
-/*
- * TODO: this code has a memory leak...
- *       We call 'new' in several locations, but bever get to 'delete' the object instances...
- */
+
 #include "absyntax_utils.hh"
 
 
+void search_varfb_instance_type_c::init(void) {
+  this->current_type_id        = NULL;
+  this->current_basetype_id    = NULL;
+  this->current_basetype_decl  = NULL;
+  this->current_field_selector = NULL;
+}
+
+
 search_varfb_instance_type_c::search_varfb_instance_type_c(symbol_c *search_scope): search_var_instance_decl(search_scope) {
-  this->decompose_var_instance_name = NULL;
-  this->current_structelement_name = NULL;
-  this->current_typeid = NULL;
-  this->current_basetypeid = NULL;
-}
-
-symbol_c *search_varfb_instance_type_c::get_type_decl(symbol_c *variable_name) {
-  this->current_structelement_name = NULL;
-  this->current_typeid = NULL;
-  this->current_basetypeid = NULL;
-  this->decompose_var_instance_name = new decompose_var_instance_name_c(variable_name);
-  if (NULL == decompose_var_instance_name) ERROR;
-
-  /* find the part of the variable name that will appear in the
-   * variable declaration, for e.g., in window.point.x, this would be
-   * window!
+  this->init();
+}
+
+
+/* We expect to be passed a symbolic_variable_c */
+symbol_c *search_varfb_instance_type_c::get_type_id(symbol_c *variable_name) {
+  this->init();
+  variable_name->accept(*this);
+  return current_type_id;
+}
+
+
+symbol_c *search_varfb_instance_type_c::get_basetype_id(symbol_c *variable_name) {
+  this->init();
+  variable_name->accept(*this);
+  return current_basetype_id;
+}
+
+
+symbol_c *search_varfb_instance_type_c::get_basetype_decl(symbol_c *variable_name) {
+  this->init();
+  variable_name->accept(*this);
+  return current_basetype_decl;
+}  
+
+
+
+
+/*************************/
+/* B.1 - Common elements */
+/*************************/
+/*******************************************/
+/* B 1.1 - Letters, digits and identifiers */
+/*******************************************/
+// SYM_TOKEN(identifier_c)
+void *search_varfb_instance_type_c::visit(identifier_c *variable_name) {
+  /* symbol should be a variable name!! */
+  /* Note: although the method is called get_decl(), it is getting the declaration of the variable, which for us is the type_id of that variable! */
+  current_type_id       = search_var_instance_decl.get_decl (variable_name);
+  current_basetype_decl = search_base_type.get_basetype_decl(current_type_id);
+  current_basetype_id   = search_base_type.get_basetype_id  (current_type_id);
+    
+  /* What if the variable has not been declared?  Then this should not be a compiler error! 
+   * However, currently stage 2 of the compiler already detects when variables have not been delcared,
+   * so if the variable's declaration is not found, then that means that we have an internal compiler error!
+   * 
+   * Actually, the above is not true anymore. See the use of the any_symbolic_variable in iec_bison.yy
+   *  - when defining the delay of a delayed action association in SFC
+   *  - in program connections inside configurations (will this search_varfb_instance_type_c class be called to handle this??)
    */
-  symbol_c *var_name_part = decompose_var_instance_name->next_part();
-  if (NULL == var_name_part) ERROR;
-
-  /* Now we try to find the variable instance declaration, to determine its type... */
-  symbol_c *var_decl = search_var_instance_decl.get_decl(var_name_part);
-  if (NULL == var_decl) ERROR;
-
-  /* if it is a struct or function block, we must search the type
-   * of the struct or function block member.
-   * This is done by this class visiting the var_decl.
-   * This class, while visiting, will recursively call
-   * decompose_var_instance_name->get_next() when and if required...
-   */
-  symbol_c *res = (symbol_c *)var_decl->accept(*this);
-  /* NOTE: A Null result is not really an internal compiler error, but rather an error in 
-   * the IEC 61131-3 source code being compiled. This means we cannot just abort the compiler with ERROR.
-   * //   if (NULL == res) ERROR;
-   */
-  if (NULL == res) return NULL;
-
-  /* make sure that we have decomposed all structure elements of the variable name */
-  symbol_c *var_name = decompose_var_instance_name->next_part();
-  /* NOTE: A non-NULL result is not really an internal compiler error, but rather an error in 
-   * the IEC 61131-3 source code being compiled. 
-   *  (for example, 'int_var.struct_elem' in the source code, when 'int_var' is a simple integer,
-   *   and not a structure, will result in this result being non-NULL!)
-   * This means we cannot just abort the compiler with ERROR.
-   * //   if (NULL != var_name) ERROR;
-   */
-  if (NULL != var_name) return NULL;
-
-  return res;
-}
-
-
-symbol_c *search_varfb_instance_type_c::get_basetype_decl(symbol_c *variable_name) {
-  symbol_c *res = get_type_decl(variable_name);
-  if (NULL == res) return NULL;
-  return (symbol_c *)base_type(res);
-}  
-
-
-unsigned int search_varfb_instance_type_c::get_vartype(symbol_c *variable_name) {
-  this->current_structelement_name = NULL;
-  this->current_typeid = NULL;
-  this->current_basetypeid = NULL;
-  this->is_complex = false;
-  this->decompose_var_instance_name = new decompose_var_instance_name_c(variable_name);
-  if (NULL == decompose_var_instance_name) ERROR;
-
-  /* find the part of the variable name that will appear in the
-   * variable declaration, for e.g., in window.point.x, this would be
-   * window!
-   */
-  symbol_c *var_name_part = decompose_var_instance_name->next_part();
-  if (NULL == var_name_part) ERROR;
-
-  /* Now we try to find the variable instance declaration, to determine its type... */
-  symbol_c *var_decl = search_var_instance_decl.get_decl(var_name_part);
-  if (NULL == var_decl) {
-    /* variable instance declaration not found! */
-    return 0;
-  }
-
-  /* if it is a struct or function block, we must search the type
-   * of the struct or function block member.
-   * This is done by this class visiting the var_decl.
-   * This class, while visiting, will recursively call
-   * decompose_var_instance_name->get_next() when and if required...
-   */
-  var_decl->accept(*this);
-  unsigned int res = search_var_instance_decl.get_vartype();
-  
-  /* make sure that we have decomposed all structure elements of the variable name */
-  symbol_c *var_name = decompose_var_instance_name->next_part();
-  if (NULL != var_name) ERROR;
-
-  return res;
-}
-
-symbol_c *search_varfb_instance_type_c::get_type_id(symbol_c *variable_name) {
-  this->current_typeid = NULL;
-  symbol_c *vartype = this->get_type_decl(variable_name);
-  if (this->current_typeid != NULL)
-    return this->current_typeid;
-  else
-    return vartype;
-}
-
-bool search_varfb_instance_type_c::type_is_complex(void) {
-  return this->is_complex;
-}
-
-/* a helper function... */
-void *search_varfb_instance_type_c::visit_list(list_c *list)	{
-  if (NULL == current_structelement_name) ERROR;
-
-  for(int i = 0; i < list->n; i++) {
-    void *res = list->elements[i]->accept(*this);
-    if (res != NULL)
-      return res;
-  }
-  /* not found! */
-  return NULL;
-}
-
-/* a helper function... */
-void *search_varfb_instance_type_c::base_type(symbol_c *symbol)	{
-    search_base_type_c search_base_type;
-    return symbol->accept(search_base_type);
-}
-
-/* We override the base class' visitor to identifier_c.
- * This is so because the base class does not consider a function block
- * to be a type, unlike this class that allows a variable instance
- * of a function block type...
- */
-void *search_varfb_instance_type_c::visit(identifier_c *type_name) {
-  /* we only store the new type id if none had been found yet.
-   * Since we will recursively carry on looking at the base type 
-   * to determine the base type declaration and id, we must only set this variable
-   * the first time.
-   * e.g. TYPE myint1_t : int    := 1;
-   *           myint2_t : int1_t := 2;
-   *           myint3_t : int2_t := 3;
-   *      END_TYPE;
-   *      VAR
-   *          myint1 : myint1_t;
-   *          myint2 : myint2_t;
-   *          myint3 : myint3_t;
-   *      END_VAR
-   *        
-   *     If we ask for typeid of     myint3, it must return myint3_t
-   *     If we ask for basetypeid of myint3, it must return int
-   *
-   *     When determining the data type of myint3, we will recursively go all the way
-   *     down to int, but we must still only store myint3_t as the base type id.
-   */
-  if (NULL == this->current_typeid)
-    this->current_typeid = type_name;
-  this->current_basetypeid = type_name;
-
-  /* look up the type declaration... */
-  symbol_c *fb_decl = function_block_type_symtable.find_value(type_name);
-  if (fb_decl != function_block_type_symtable.end_value())
-    /* Type declaration found!! */
-    return fb_decl->accept(*this);
-
-  /* No. It is not a function block, so we let
-   * the base class take care of it...
-   */
-  return search_base_type_c::visit(type_name);
-}
+  // if (NULL == current_type_id) ERROR; 
+
+  return NULL;
+}
+
+
+
+
 
 /********************************/
 /* B 1.3.3 - Derived data types */
 /********************************/
-
 /*  identifier ':' array_spec_init */
+/* NOTE: I don't think this will ever get called, since in the visit method for array_variable_c
+ * we use the basetype_decl for recursively calling this class, and the base type should never be a 
+ * array_type_declaration_c, but for now, let's leave it in...
+ */
 void *search_varfb_instance_type_c::visit(array_type_declaration_c *symbol) {
-  return symbol->array_spec_init->accept(*this);
+  ERROR;
+  return NULL;
 }
     
 /* array_specification [ASSIGN array_initialization] */
 /* array_initialization may be NULL ! */
+/* NOTE: I don't think this will ever get called, since in the visit method for array_variable_c
+ * we use the basetype_decl for recursively calling this class, and the base type should never be a 
+ * array_spec_init_c, but for now, let's leave it in...
+ */
 void *search_varfb_instance_type_c::visit(array_spec_init_c *symbol) {
-  return symbol->array_specification->accept(*this);
+  /* Note that the 'array_specification' may be either an identifier of a previsously defined array type, 
+   * or an array_specification_c, so we can not stop here and simply return a array_spec_init_c, 
+   * especially if we are looking for the base class!
+   */
+  ERROR;
+  return NULL;
 }
 
 /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */
+/* NOTE: This method will be reached after being called from the 
+ * search_varfb_instance_type_c::visit(array_variable_c *symbol)
+ * method, so we must return the data type of the data stored in the array, 
+ * and not the data type of the array itself!
+ */
 void *search_varfb_instance_type_c::visit(array_specification_c *symbol) {
-  this->is_complex = true;
-  this->current_typeid = symbol;
-  return symbol->non_generic_type_name->accept(*this);
-}
+  /* found the type of the element we were looking for! */
+  current_type_id       = symbol->non_generic_type_name;
+  current_basetype_decl = search_base_type.get_basetype_decl(current_type_id);
+  current_basetype_id   = search_base_type.get_basetype_id  (current_type_id);
+    
+  return NULL; 
+}
+
 
 /*  structure_type_name ':' structure_specification */
 /* NOTE: this is only used inside a TYPE ... END_TYPE declaration. 
  * It is never used directly when declaring a new variable! 
  */
+/* NOTE: I don't think this will ever get called, since in the visit method for structured_variable_c
+ * we use the basetype_decl for recursively calling this class, and the base type should never be a 
+ * structure_type_declaration_c, but for now, let's leave it in...
+ */
 void *search_varfb_instance_type_c::visit(structure_type_declaration_c *symbol) {
-  this->is_complex = true;
-
-  if (NULL == current_structelement_name) ERROR;
-  return symbol->structure_specification->accept(*this);
+  if (NULL == current_field_selector) ERROR;
+  symbol->structure_specification->accept(*this);
+  return NULL;
   /* NOTE: structure_specification will point to either a
    *       initialized_structure_c
    *       OR A
@@ -301,82 +219,45 @@
    */
 }
 
-/*  var1_list ':' structure_type_name */
-void *search_varfb_instance_type_c::visit(structured_var_declaration_c *symbol) {
-  this->is_complex = true;
-  if (NULL != current_structelement_name) ERROR;
-
-  /* make sure that we have decomposed all structure elements of the variable name */
-  symbol_c *var_name = decompose_var_instance_name->next_part();
-  if (NULL == var_name) {
-	/* this is it... !
-	 * No need to look any further...
-	 * Note also that, unlike for the struct types, a function block may
-	 * not be defined based on another (i.e. no inheritance is allowed),
-	 * so this function block is already the most base type.
-	 * We simply return it.
-	 */
-	return (void *)symbol;
-  }
-
-  /* reset current_type_id because of new structure element part */
-  this->current_typeid = NULL;
-
-  /* look for the var_name in the structure declaration */
-  current_structelement_name = var_name;
-
-  /* recursively find out the data type of current_structelement_name... */
-  return symbol->structure_type_name->accept(*this);
-}
-
 /* structure_type_name ASSIGN structure_initialization */
 /* structure_initialization may be NULL ! */
 // SYM_REF2(initialized_structure_c, structure_type_name, structure_initialization)
-/* NOTE: only the initialized structure is ever used when declaring a new variable instance */
+/* NOTE: only the initialized structure is never used when declaring a new variable instance */
+/* NOTE: I don't think this will ever get called, since in the visit method for structured_variable_c
+ * we use the basetype_decl for recursively calling this class, and the base type should never be a 
+ * initialized_structure_c, but for now, let's leave it in...
+ */
 void *search_varfb_instance_type_c::visit(initialized_structure_c *symbol)	{
-  this->is_complex = true;
-  if (NULL != current_structelement_name) ERROR;
-  
-  /* make sure that we have decomposed all structure elements of the variable name */
-  symbol_c *var_name = decompose_var_instance_name->next_part();
-  if (NULL == var_name) {
-    /* this is it... !
-     * No need to look any further...
-     * Note also that, unlike for the struct types, a function block may
-     * not be defined based on another (i.e. no inheritance is allowed),
-     * so this function block is already the most base type.
-     * We simply return it.
-     */
-    return (void *)symbol;
-  }
-
-  /* reset current_type_id because of new structure element part */
-  this->current_typeid = NULL;
-
-  /* look for the var_name in the structure declaration */
-  current_structelement_name = var_name;
-
-  /* recursively find out the data type of current_structelement_name... */
-  return symbol->structure_type_name->accept(*this);
+  if (NULL != current_field_selector) ERROR;
+  
+  /* recursively find out the data type of current_field_selector... */
+  symbol->structure_type_name->accept(*this);
+  return NULL;
 }
 
 /* helper symbol for structure_declaration */
 /* structure_declaration:  STRUCT structure_element_declaration_list END_STRUCT */
 /* structure_element_declaration_list structure_element_declaration ';' */
 void *search_varfb_instance_type_c::visit(structure_element_declaration_list_c *symbol)	{
-  if (NULL == current_structelement_name) ERROR;
+  if (NULL == current_field_selector) ERROR;
+
   /* now search the structure declaration */
-  return visit_list(symbol);
+  for(int i = 0; i < symbol->n; i++) {
+    symbol->elements[i]->accept(*this);
+  }
+
+  return NULL;
 }
 
 /*  structure_element_name ':' spec_init */
 void *search_varfb_instance_type_c::visit(structure_element_declaration_c *symbol) {
-  if (NULL == current_structelement_name) ERROR;
-
-  if (compare_identifiers(symbol->structure_element_name, current_structelement_name) == 0) {
-    current_structelement_name = NULL;
+  if (NULL == current_field_selector) ERROR;
+
+  if (compare_identifiers(symbol->structure_element_name, current_field_selector) == 0) {
     /* found the type of the element we were looking for! */
-    return symbol->spec_init->accept(*this);
+    current_type_id       = symbol->spec_init;
+    current_basetype_decl = search_base_type.get_basetype_decl(current_type_id);
+    current_basetype_id   = search_base_type.get_basetype_id  (current_type_id);
   }  
 
   /* Did not find the type of the element we were looking for! */
@@ -392,6 +273,79 @@
 void *search_varfb_instance_type_c::visit(structure_element_initialization_c *symbol) {ERROR; return NULL;} /* should never get called... */
 
 
+/*********************/
+/* B 1.4 - Variables */
+/*********************/
+// SYM_REF1(symbolic_variable_c, var_name)
+void *search_varfb_instance_type_c::visit(symbolic_variable_c *symbol) {
+  symbol->var_name->accept(*this);
+  return NULL;
+}
+
+/********************************************/
+/* B.1.4.1   Directly Represented Variables */
+/********************************************/
+// SYM_TOKEN(direct_variable_c)
+/* We do not yet handle this. Will we ever need to handle it, as the data type of the direct variable is
+ * directly obtainable from the syntax of the direct variable itself?
+ */
+
+/*************************************/
+/* B 1.4.2 - Multi-element variables */
+/*************************************/
+/*  subscripted_variable '[' subscript_list ']' */
+// SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
+/* NOTE: when passed a array_variable_c, which represents some IEC61131-3 code similar to X[42]
+ * we must return the data type of the value _stored_ in the array.
+ * If you want to get the data type of the array itself (i.e. just the X variable, without the [42])
+ * then this class must be called with the identifier_c 'X'.
+ */
+void *search_varfb_instance_type_c::visit(array_variable_c *symbol) {
+  /* determine the data type of the subscripted_variable... 
+   * This should be an array_specification_c
+   *    ARRAY [xx..yy] OF Stored_Data_Type
+   */
+  symbol->subscripted_variable->accept(*this);
+  symbol_c *basetype_decl = current_basetype_decl;
+  this->init(); /* set all current_*** pointers to NULL ! */
+  
+  /* Now we determine the 'Stored_Data_Type', i.e. the data type of the variable stored in the array. */
+  if (NULL != basetype_decl) {
+    basetype_decl->accept(*this);
+  }
+  
+  return NULL;
+}
+
+
+/*  record_variable '.' field_selector */
+/*  WARNING: input and/or output variables of function blocks
+ *           may be accessed as fields of a structured variable!
+ *           Code handling a structured_variable_c must take this into account!
+ *           (i.e. that a FB instance may be accessed as a structured variable)!
+ *
+ *  WARNING: Status bit (.X) and activation time (.T) of STEPS in SFC diagrams
+ *           may be accessed as fields of a structured variable!
+ *           Code handling a structured_variable_c must take this into account 
+ *           (i.e. that an SFC STEP may be accessed as a structured variable)!
+ */
+// SYM_REF2(structured_variable_c, record_variable, field_selector)
+void *search_varfb_instance_type_c::visit(structured_variable_c *symbol) {
+  symbol->record_variable->accept(*this);
+  symbol_c *basetype_decl = current_basetype_decl;
+  this->init(); /* set all current_*** pointers to NULL ! */
+  
+  /* Now we search for the data type of the field... But only if we were able to determine the data type of the variable */
+  if (NULL != basetype_decl) {
+    current_field_selector = symbol->field_selector;
+    basetype_decl->accept(*this);
+    current_field_selector = NULL;
+  }
+  
+  return NULL;
+}
+
+
 
 /**************************************/
 /* B.1.5 - Program organization units */
@@ -399,46 +353,53 @@
 /*****************************/
 /* B 1.5.2 - Function Blocks */
 /*****************************/
+
 /*  FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
 // SYM_REF4(function_block_declaration_c, fblock_name, var_declarations, fblock_body, unused)
 void *search_varfb_instance_type_c::visit(function_block_declaration_c *symbol) {
-  /* make sure that we have decomposed all structure elements of the variable name */
-  symbol_c *var_name = decompose_var_instance_name->next_part();
-  if (NULL == var_name) {
-    /* this is it... !
-     * No need to look any further...
-     * Note also that, unlike for the struct types, a function block may
-     * not be defined based on another (i.e. no inheritance is allowed),
-     * so this function block is already the most base type.
-     * We simply return it.
-     */
-    return (void *)symbol;
-   }
-
-   /* reset current_type_id because of new structure element part */
-   this->current_typeid = NULL;
-
-   /* now search the function block declaration for the variable... */
-   search_var_instance_decl_c search_decl(symbol);
-   symbol_c *var_decl = search_decl.get_decl(var_name);
-   if (NULL == var_decl) {
-     /* variable instance declaration not found! */
-     return NULL;
-   }
-#if 0
-   /* We have found the declaration.
-    * Should we look any further?
-    */
-   var_name = decompose_var_instance_name->next_part();
-   if (NULL == var_name) {
-     /* this is it... ! */
-     return base_type(var_decl);
-   }
-
-  current_structelement_name = var_name;
-  /* recursively find out the data type of var_name... */
-  return symbol->var_declarations->accept(*this);
-#endif
-  /* carry on recursively, in case the variable has more elements to be decomposed... */
-  return var_decl->accept(*this);
-}
+  if (NULL == current_field_selector) ERROR;
+
+  /* now search the function block declaration for the variable... */
+  /* If not found, these pointers will all be set to NULL!! */
+  search_var_instance_decl_c search_decl(symbol);
+  current_type_id       = search_decl.get_decl(current_field_selector);
+  current_basetype_decl = search_base_type.get_basetype_decl(current_type_id);
+  current_basetype_id   = search_base_type.get_basetype_id  (current_type_id);
+  
+  return NULL;
+}
+
+
+
+/*********************************************/
+/* B.1.6  Sequential function chart elements */
+/*********************************************/
+/* INITIAL_STEP step_name ':' action_association_list END_STEP */
+// SYM_REF2(initial_step_c, step_name, action_association_list)
+/* NOTE: this method may be called from visit(structured_variable_c *symbol) method| */
+void *search_varfb_instance_type_c::visit(initial_step_c *symbol) {
+  if (NULL == current_field_selector) ERROR;
+
+  identifier_c T("T");
+  identifier_c X("X");
+  
+  if (compare_identifiers(&T, current_field_selector) == 0)   
+    current_type_id = &search_constant_type_c::time_type_name;
+  if (compare_identifiers(&X, current_field_selector) == 0)   
+    current_type_id = &search_constant_type_c::bool_type_name;
+  
+  current_basetype_decl = search_base_type.get_basetype_decl(current_type_id);
+  current_basetype_id   = search_base_type.get_basetype_id  (current_type_id);
+
+  return NULL;
+}
+
+
+/* STEP step_name ':' action_association_list END_STEP */
+// SYM_REF2(step_c, step_name, action_association_list)
+/* NOTE: this method may be called from visit(structured_variable_c *symbol) method| */
+void *search_varfb_instance_type_c::visit(step_c *symbol) {
+  /* The code here should be identicial to the code in the visit(initial_step_c *) visitor! So we simply call the other visitor! */
+  initial_step_c initial_step(NULL, NULL);
+  return initial_step.accept(*this);
+}
--- a/absyntax_utils/search_varfb_instance_type.hh	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/search_varfb_instance_type.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -1,7 +1,7 @@
 /*
  *  matiec - a compiler for the programming languages defined in IEC 61131-3
  *
- *  Copyright (C) 2003-2011  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2003-2012  Mario de Sousa (msousa@fe.up.pt)
  *  Copyright (C) 2007-2011  Laurent Bessard and Edouard Tisserant
  *
  *  This program is free software: you can redistribute it and/or modify
@@ -77,44 +77,38 @@
  *
  * Member functions:
  * ================
+ *   get_basetype_id()    ---> returns 2A   (implemented, although currently it is not needed! )
  *   get_basetype_decl()  ---> returns 2B 
  *   get_type_id()        ---> returns 1A
  * 
- *   Since we haven't yet needed them, we don't yet implement
- *   get_basetype_id()    ----> would return 2A
- *   get_type_decl()      ----> would return 1B
+ *   Since we haven't yet needed it, we don't yet implement
+ *   get_type_decl()      ---> returns 1B 
  */ 
 
-class search_varfb_instance_type_c: public search_base_type_c {
+class search_varfb_instance_type_c : null_visitor_c {
 
   private:
     search_var_instance_decl_c search_var_instance_decl;
-    decompose_var_instance_name_c *decompose_var_instance_name;
-    symbol_c *current_structelement_name;
-    symbol_c *current_typeid;
-    symbol_c *current_basetypeid;
-    bool is_complex;
+    search_base_type_c         search_base_type;
+
+//  symbol_c *current_type_decl;
+    symbol_c *current_type_id;
+    symbol_c *current_basetype_decl;
+    symbol_c *current_basetype_id;
+    
+    symbol_c *current_field_selector;
+
+    /* sets all the above variables to NULL, or false */
+    void init(void);
 
   public:
-    search_varfb_instance_type_c(symbol_c *search_scope);
-    symbol_c *get_basetype_decl(symbol_c *variable_name);
-    symbol_c *get_type_decl(symbol_c *variable_name);
-    symbol_c *get_type_id(symbol_c *variable_name);
-
-    /* NOTE: this function should be remvoed/deleted.
-     *       However, it is currently used in stage 4, and before deleting it
-     *       requires that the stage4 code be analysed and fixed (i.e. replace by 
-     *       a call to one of the above functions get_basetype_decl(), 
-     *       get_type_decl(), get_type_id().
-     *
-     *      At the moment, I have a feeling that this whole class search_varfb_instance_type_c
-     *      will not be needed in the future (i.e. when we finish implementing type checking
-     *      in stage 3 correctly, where we store on each symbol in the abstract syntax
-     *      tree it's data type, so stage4 implementations will not need to deduce the data
-     *      types again), so it does not make much sense to spend more time on it.
-     */
-    unsigned int get_vartype(symbol_c *variable_name);
-    bool type_is_complex(void);
+    search_varfb_instance_type_c(symbol_c *search_scope );
+    symbol_c *get_basetype_decl (symbol_c *variable_name);
+    symbol_c *get_basetype_id   (symbol_c *variable_name);
+//  symbol_c *get_type_decl     (symbol_c *variable_name);
+    symbol_c *get_type_id       (symbol_c *variable_name);
+
+
 
   private:
     /* a helper function... */
@@ -125,17 +119,17 @@
 
 
   private:
-    /* We override the base class' visitor to identifier_c.
-     * This is so because the base class does not consider a function block
-     * to be a type, unlike this class that allows a variable instance
-     * of a function block type...
-     */
-    void *visit(identifier_c *type_name);
-
+    /*************************/
+    /* B.1 - Common elements */
+    /*************************/
+    /*******************************************/
+    /* B 1.1 - Letters, digits and identifiers */
+    /*******************************************/
+    void *visit(identifier_c *variable_name);
+      
     /********************************/
     /* B 1.3.3 - Derived data types */
     /********************************/
-    
     /*  identifier ':' array_spec_init */
     void *visit(array_type_declaration_c *symbol);
     
@@ -149,9 +143,6 @@
     /*  structure_type_name ':' structure_specification */
     void *visit(structure_type_declaration_c *symbol);
 
-    /*  var1_list ':' structure_type_name */
-    void *visit(structured_var_declaration_c *symbol);
-
     /* structure_type_name ASSIGN structure_initialization */
     /* structure_initialization may be NULL ! */
     // SYM_REF2(initialized_structure_c, structure_type_name, structure_initialization)
@@ -173,7 +164,20 @@
     void *visit(structure_element_initialization_c *symbol); /* should never get called... */
 
 
-
+    /*********************/
+    /* B 1.4 - Variables */
+    /*********************/
+    void *visit(symbolic_variable_c *symbol);
+
+    /********************************************/
+    /* B.1.4.1   Directly Represented Variables */
+    /********************************************/
+    /*************************************/
+    /* B 1.4.2 - Multi-element variables */
+    /*************************************/
+    void *visit(array_variable_c *symbol);
+    void *visit(structured_variable_c *symbol);
+    
     /**************************************/
     /* B.1.5 - Program organization units */
     /**************************************/
@@ -184,6 +188,17 @@
     // SYM_REF4(function_block_declaration_c, fblock_name, var_declarations, fblock_body, unused)
     void *visit(function_block_declaration_c *symbol);
 
+    
+    /*********************************************/
+    /* B.1.6  Sequential function chart elements */
+    /*********************************************/
+    /* INITIAL_STEP step_name ':' action_association_list END_STEP */
+    // SYM_REF2(initial_step_c, step_name, action_association_list)
+    void *visit(initial_step_c *symbol);
+    /* STEP step_name ':' action_association_list END_STEP */
+    // SYM_REF2(step_c, step_name, action_association_list)
+    void *visit(step_c *symbol);
+
 }; // search_varfb_instance_type_c
 
 
--- a/absyntax_utils/spec_init_separator.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/spec_init_separator.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -37,6 +37,8 @@
  */
 
 #include "spec_init_separator.hh"
+#include "../main.hh" // required for ERROR() and ERROR_MSG() macros.
+
 
 //#define DEBUG
 #ifdef DEBUG
@@ -45,9 +47,6 @@
 #define TRACE(classname)
 #endif
 
-#define ERROR error_exit(__FILE__,__LINE__)
-/* function defined in main.cc */
-extern void error_exit(const char *file_name, int line_no);
 
 
 spec_init_sperator_c *spec_init_sperator_c::get_class_instance(void) {
--- a/absyntax_utils/type_initial_value.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/type_initial_value.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -84,7 +84,7 @@
     date_literal_0 =  new date_literal_c(integer_1, integer_1, integer_1);
   date_literal_0 =  new date_literal_c(new integer_c("1970"), integer_1, integer_1);
   daytime_literal_0 = new daytime_c(integer_0, integer_0, real_0);
-  time_0 = new duration_c(new time_type_name_c(), NULL, new seconds_c(integer_0, NULL));  // T#0S
+  time_0 = new duration_c(new time_type_name_c(), NULL, new interval_c(NULL, NULL, NULL, integer_0, NULL));  // T#0s
   date_0 = new date_c(new date_type_name_c(), date_literal_0);  //  D#0001-01-01
   tod_0 = new time_of_day_c(new tod_type_name_c(), daytime_literal_0);  //  TOD#00:00:00
   dt_0 = new date_and_time_c(new dt_type_name_c(), date_literal_0, daytime_literal_0);  //  DT#0001-01-01-00:00:00
@@ -366,13 +366,13 @@
  * as would be expected!
  */
 /*  string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */
-#if 0
-SYM_REF4(string_type_declaration_c,	string_type_name,
-					elementary_string_type_name,
-					string_type_declaration_size,
-					string_type_declaration_init) /* may be == NULL! */
-#endif
-void *type_initial_value_c::visit(string_type_declaration_c *symbol)	{return NULL;}
+// SYM_REF4(string_type_declaration_c,	string_type_name,
+// 					elementary_string_type_name,
+// 					string_type_declaration_size,
+// 					string_type_declaration_init) /* may be == NULL! */
+void *type_initial_value_c::visit(string_type_declaration_c *symbol)	{
+  return handle_type_spec(symbol->elementary_string_type_name, symbol->string_type_declaration_init);
+}
 
 
 type_initial_value_c	*type_initial_value_c::_instance = NULL;
--- a/absyntax_utils/type_initial_value.hh	Tue Aug 14 19:40:01 2012 +0200
+++ b/absyntax_utils/type_initial_value.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -279,12 +279,10 @@
      * as would be expected!
      */
     /*  string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */
-#if 0
-SYM_REF4(string_type_declaration_c,	string_type_name,
-					elementary_string_type_name,
-					string_type_declaration_size,
-					string_type_declaration_init) /* may be == NULL! */
-#endif
+     // SYM_REF4(string_type_declaration_c,	string_type_name,
+     //					elementary_string_type_name,
+     //					string_type_declaration_size,
+     // 				string_type_declaration_init) /* may be == NULL! */
     void *visit(string_type_declaration_c *symbol);
 }; // type_initial_value_c
 
--- a/configure	Tue Aug 14 19:40:01 2012 +0200
+++ b/configure	Wed Aug 22 16:46:17 2012 +0200
@@ -4582,6 +4582,65 @@
   RANLIB="$ac_cv_prog_RANLIB"
 fi
 
+for ac_prog in gawk mawk nawk awk
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$AWK"; then
+  ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_prog_AWK="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$AWK" && break
+done
+
+
+# Check bison version, we need a version great or equal than 2.4 to build matiec.
+[[ $(bison --version) =~ ([0-9][.][0-9]*) ]] && version_bison="${BASH_REMATCH[1]}"
+
+if awk -v ver="$version_bison" 'BEGIN { if (ver < 2.4) exit 1; }'; then :
+  have_bison_correct=yes
+else
+  have_bison_correct=no
+fi
+
+
+if test "x${have_bison_correct}" = xno; then
+  echo "------------------------------------------"
+  echo " Wrong bison version: $version_bison < 2.4 "
+  echo "------------------------------------------"
+  (exit 1); exit 1;
+fi
 
 # Checks for header files.
 ac_ext=c
@@ -5677,6 +5736,7 @@
 
 
 
+
 ac_config_files="$ac_config_files Makefile absyntax/Makefile absyntax_utils/Makefile stage1_2/Makefile stage3/Makefile stage4/Makefile stage4/generate_c/Makefile stage4/generate_iec/Makefile"
 
 cat >confcache <<\_ACEOF
--- a/configure.ac	Tue Aug 14 19:40:01 2012 +0200
+++ b/configure.ac	Wed Aug 22 16:46:17 2012 +0200
@@ -25,6 +25,21 @@
 AC_PROG_LN_S
 AC_PROG_MAKE_SET
 AC_PROG_RANLIB
+AC_PROG_AWK
+
+# Check bison version, we need a version great or equal than 2.4 to build matiec.
+[[[ $(bison --version) =~ ([0-9][.][0-9]*) ]]] && version_bison="${BASH_REMATCH[[1]]}"
+
+AS_IF([awk -v ver="$version_bison" 'BEGIN { if (ver < 2.4) exit 1; }'],
+	[have_bison_correct=yes], [have_bison_correct=no])
+
+
+if test "x${have_bison_correct}" = xno; then
+  echo "------------------------------------------"
+  echo " Wrong bison version: $version_bison < 2.4 "
+  echo "------------------------------------------"
+  (exit 1); exit 1;
+fi
 
 # Checks for header files.
 AC_CHECK_HEADERS([float.h limits.h stdint.h stdlib.h string.h strings.h sys/timeb.h unistd.h])
@@ -47,6 +62,7 @@
 AC_FUNC_REALLOC
 AC_CHECK_FUNCS([clock_gettime memset pow strcasecmp strdup strtoul strtoull])
 
+
 AC_CONFIG_MACRO_DIR([config])
 
 AC_CONFIG_FILES([Makefile \
--- a/lib/iec_std_lib.h	Tue Aug 14 19:40:01 2012 +0200
+++ b/lib/iec_std_lib.h	Wed Aug 22 16:46:17 2012 +0200
@@ -81,28 +81,28 @@
 #endif
 
 
-#define __lit(type,value,sfx) (type)value##sfx
-// Keep this macro expention step to let sfx change into L or LL
-#define __literal(type,value,sfx) __lit(type,value,sfx)
-
-#define __BOOL_LITERAL(value) __literal(BOOL,value,)
-#define __SINT_LITERAL(value) __literal(SINT,value,)
-#define __INT_LITERAL(value) __literal(INT,value,)
+#define __lit(type,value,...) (type)value##__VA_ARGS__
+// Keep this macro expention step to let sfx(__VA_ARGS__) change into L or LL
+#define __literal(type,value,...) __lit(type,value,##__VA_ARGS__)
+
+#define __BOOL_LITERAL(value) __literal(BOOL,value)
+#define __SINT_LITERAL(value) __literal(SINT,value)
+#define __INT_LITERAL(value) __literal(INT,value)
 #define __DINT_LITERAL(value) __literal(DINT,value,__32b_sufix)
 #define __LINT_LITERAL(value) __literal(LINT,value,__64b_sufix)
-#define __USINT_LITERAL(value) __literal(USINT,value,)
-#define __UINT_LITERAL(value) __literal(UINT,value,)
+#define __USINT_LITERAL(value) __literal(USINT,value)
+#define __UINT_LITERAL(value) __literal(UINT,value)
 #define __UDINT_LITERAL(value) __literal(UDINT,value,__32b_sufix)
 #define __ULINT_LITERAL(value) __literal(ULINT,value,__64b_sufix)
 #define __REAL_LITERAL(value) __literal(REAL,value,__32b_sufix)
 #define __LREAL_LITERAL(value) __literal(LREAL,value,__64b_sufix)
-#define __TIME_LITERAL(value) __literal(TIME,value,)
-#define __DATE_LITERAL(value) __literal(DATE,value,)
-#define __TOD_LITERAL(value) __literal(TOD,value,)
-#define __DT_LITERAL(value) __literal(DT,value,)
+#define __TIME_LITERAL(value) __literal(TIME,value)
+#define __DATE_LITERAL(value) __literal(DATE,value)
+#define __TOD_LITERAL(value) __literal(TOD,value)
+#define __DT_LITERAL(value) __literal(DT,value)
 #define __STRING_LITERAL(count,value) (STRING){count,value}
-#define __BYTE_LITERAL(value) __literal(BYTE,value,)
-#define __WORD_LITERAL(value) __literal(WORD,value,)
+#define __BYTE_LITERAL(value) __literal(BYTE,value)
+#define __WORD_LITERAL(value) __literal(WORD,value)
 #define __DWORD_LITERAL(value) __literal(DWORD,value,__32b_sufix)
 #define __LWORD_LITERAL(value) __literal(LWORD,value,__64b_sufix)
 
@@ -261,6 +261,7 @@
   broken_down_time.tm_mday = day;  /* day of month, from 1 to 31 */
   broken_down_time.tm_mon = month - 1;   /* month since January, in the range 0 to 11 */
   broken_down_time.tm_year = year - 1900;  /* number of years since 1900 */
+  broken_down_time.tm_isdst = 0; /* disable daylight savings time */
 
   epoch_seconds = mktime(&broken_down_time); /* determine number of seconds since the epoch, i.e. Jan 1st 1970 */
   if ((time_t)(-1) == epoch_seconds)
@@ -568,16 +569,16 @@
     }
     if(IN.tv_nsec == 0){
         res.len = snprintf((char*)&res.body, STR_MAX_LEN, "DT#%d-%2.2d-%2.2d-%2.2d:%2.2d:%d",
-                 broken_down_time->tm_year,
-                 broken_down_time->tm_mon,
+                 broken_down_time->tm_year + 1900,
+                 broken_down_time->tm_mon  + 1,
                  broken_down_time->tm_mday,
                  broken_down_time->tm_hour,
                  broken_down_time->tm_min,
                  broken_down_time->tm_sec);
     }else{
         res.len = snprintf((char*)&res.body, STR_MAX_LEN, "DT#%d-%2.2d-%2.2d-%2.2d:%2.2d:%g",
-                 broken_down_time->tm_year,
-                 broken_down_time->tm_mon,
+                 broken_down_time->tm_year + 1900,
+                 broken_down_time->tm_mon  + 1,
                  broken_down_time->tm_mday,
                  broken_down_time->tm_hour,
                  broken_down_time->tm_min,
@@ -1752,7 +1753,6 @@
     /**************/
     /*     NE     */
     /**************/
-
 #define __ne_num(fname, TYPENAME) \
 static inline BOOL fname(EN_ENO_PARAMS, TYPENAME op1, TYPENAME op2){\
   TEST_EN(BOOL)\
--- a/main.cc	Tue Aug 14 19:40:01 2012 +0200
+++ b/main.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -80,11 +80,23 @@
 #define HGVERSION ""
 #endif
 
-#define ERROR          error_exit(__FILE__,__LINE__)
-void error_exit(const char *file_name, int line_no) {
-  std::cerr << "\nInternal compiler error in file " << file_name
-            << " at line " << line_no << "\n";
-//   if (msg != NULL) std::cerr << message << "\n\n";
+#include "main.hh"  // symbol_c type
+#include <stdarg.h> // required for va_start(), va_list
+
+void error_exit(const char *file_name, int line_no, const char *errmsg, ...) {
+  va_list argptr;
+  va_start(argptr, errmsg); /* second argument is last fixed pamater of error_exit() */
+
+  fprintf(stderr, "\nInternal compiler error in file %s at line %d", file_name, line_no);
+  if (errmsg != NULL) {
+    fprintf(stderr, ": ");
+    vfprintf(stderr, errmsg, argptr);
+  } else {
+    fprintf(stderr, ".");
+  }
+  fprintf(stderr, "\n");
+  va_end(argptr);
+    
   exit(EXIT_FAILURE);
 }
 
@@ -124,6 +136,7 @@
   char * builddir = NULL;
   stage1_2_options_t stage1_2_options = {false, false, NULL};
   int optres, errflg = 0;
+  int path_len;
 /*
   extern char *optarg;
   extern int optind, optopt;
@@ -148,9 +161,19 @@
       stage1_2_options.safe_extensions = true;
       break;
     case 'I':
+      /* NOTE: To improve the usability under windows:
+       *       We delete last char's path if it ends with "\".
+       *       In this way compiler front-end accepts paths with or without
+       *       slash terminator.
+       */
+      path_len = strlen(optarg) - 1;
+      if (optarg[path_len] == '\\') optarg[path_len]= '\0';
       stage1_2_options.includedir = optarg;
       break;
     case 'T':
+      /* NOTE: see note above */
+      path_len = strlen(optarg) - 1;
+      if (optarg[path_len] == '\\') optarg[path_len]= '\0';
       builddir = optarg;
       break;
     case ':':       /* -I or -T without operand */
@@ -198,7 +221,7 @@
     /* moved to bison, although it could perfectly well still be here instead of in bison code. */
   //add_en_eno_param_decl_c::add_to(tree_root);
 
-  /* Only very simple (not yet complete) data type checking currently implemented... */
+  /* Do semantic verification of code (data type and lvalue checking currently implemented) */
   if (stage3(tree_root) < 0)
     return EXIT_FAILURE;
   
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -0,0 +1,127 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *  Copyright (C) 2003-2011  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2007-2011  Laurent Bessard and Edouard Tisserant
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <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)
+ *
+ */
+
+
+
+#ifndef _MAIN_HH
+#define _MAIN_HH
+
+
+
+ /* Function used throughout the code --> used to report failed assertions (i.e. internal compiler errors)! */
+#include <stddef.h>  /* required for NULL */
+ 
+#define ERROR               error_exit(__FILE__,__LINE__)
+#define ERROR_MSG(msg, ...) error_exit(__FILE__,__LINE__, msg)
+// #define ERROR_MSG(msg, ...) error_exit(__FILE__,__LINE__, msg, __VA_ARGS__)
+
+extern void error_exit(const char *file_name, int line_no, const char *errmsg = NULL, ...);
+
+
+
+
+
+
+ /* Get the definition of INT16_MAX, INT16_MIN, UINT64_MAX, INT64_MAX, INT64_MIN, ... */
+
+#define __STDC_LIMIT_MACROS /* required to have UINTxx_MAX defined when including stdint.h from C++ source code. */
+#include <stdint.h>         
+#include <limits>
+
+#ifndef   UINT64_MAX 
+  #define UINT64_MAX (std::numeric_limits< uint64_t >::max())
+#endif
+#ifndef    INT64_MAX 
+  #define  INT64_MAX (std::numeric_limits<  int64_t >::max())
+#endif
+#ifndef    INT64_MIN
+  #define  INT64_MIN (std::numeric_limits<  int64_t >::min()) 
+#endif
+
+
+
+/* Determine, for the current platform, which datas types (float, double or long double) use 64 and 32 bits. */
+/* NOTE: We cant use sizeof() in pre-processor directives, so we have to do it another way... */
+/* CURIOSITY: We can use sizeof() and offsetof() inside static_assert() but:
+ *          - this only allows us to make assertions, and not #define new macros
+ *          - is only available in the C standard [ISO/IEC 9899:2011] and the C++ 0X draft standard [Becker 2008]. It is not available in C99.
+ *          https://www.securecoding.cert.org/confluence/display/seccode/DCL03-C.+Use+a+static+assertion+to+test+the+value+of+a+constant+expression
+ *         struct {int a, b, c, d} header_t;
+ *  e.g.:  static_assert(offsetof(struct header_t, c) == 8, "Compile time error message.");
+ */
+
+#include <float.h>
+#if    (LDBL_MANT_DIG == 53) /* NOTE: 64 bit IEC559 real has 53 bits for mantissa! */
+  #define long_double long double
+  #define real64_t long_double /* so we can later use #if (real64_t == long_double) directives in the code! */
+  #define REAL64_MAX  LDBL_MAX
+#elif  ( DBL_MANT_DIG == 53) /* NOTE: 64 bit IEC559 real has 53 bits for mantissa! */
+  #define real64_t double
+  #define REAL64_MAX  DBL_MAX
+#elif  ( FLT_MANT_DIG == 53) /* NOTE: 64 bit IEC559 real has 53 bits for mantissa! */
+  #define real64_t float
+  #define REAL64_MAX  FLT_MAX
+#else 
+  #error Could not find a 64 bit floating point data type on this platform. Aborting...
+#endif
+
+
+#if    (LDBL_MANT_DIG == 24) /* NOTE: 32 bit IEC559 real has 24 bits for mantissa! */
+  #ifndef long_double 
+    #define long_double long double
+  #endif  
+  #define real32_t long_double /* so we can later use #if (real32_t == long_double) directives in the code! */
+  #define REAL32_MAX  LDBL_MAX
+#elif  ( DBL_MANT_DIG == 24) /* NOTE: 32 bit IEC559 real has 24 bits for mantissa! */
+  #define real32_t double
+  #define REAL32_MAX  DBL_MAX
+#elif  ( FLT_MANT_DIG == 24) /* NOTE: 32 bit IEC559 real has 24 bits for mantissa! */
+  #define real32_t float
+  #define REAL32_MAX  FLT_MAX
+#else 
+  #error Could not find a 32 bit floating point data type on this platform. Aborting...
+#endif
+
+
+
+#include <math.h>
+#ifndef INFINITY
+  #error Could not find the macro that defines the value for INFINITY in the current platform.
+#endif
+#ifndef NAN
+  #error Could not find the macro that defines the value for NAN in the current platform.
+#endif
+
+
+
+
+
+#endif // #ifndef _MAIN_HH
\ No newline at end of file
--- a/readme	Tue Aug 14 19:40:01 2012 +0200
+++ b/readme	Wed Aug 22 16:46:17 2012 +0200
@@ -8,7 +8,64 @@
   FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
 
 
-  Copyright (C) 2003-2011  Mario de Sousa (msousa@fe.up.pt)
+  Copyright (C) 2003-2012  Mario de Sousa (msousa@fe.up.pt)
+
+
+****************************************************************
+****************************************************************
+****************************************************************
+*********                                              *********
+*********                                              *********
+*********         O V E R A L L    G O A L S           *********
+*********                                              *********
+*********                                              *********
+****************************************************************
+****************************************************************
+****************************************************************
+
+
+
+ This project has the goal of producing an open source compiler for the programming languages defined
+in the IEC 61131-3 standard. These programming languages are mostly used in the industrial automation 
+domain, to program PLCs (Programmable Logic Controllers).
+
+ This standard defines 5 programming languages:
+     - IL : Instructtion List
+            A textual programming language, somewhat similar to assembly.
+     - ST : Structured Text
+            A textual programming language, somewhat similar to Pascal.
+     - FBD: Function Block Diagram
+            A graphical programming language, somewhat similar to an electrical circuit diagram based on small 
+             scale integration ICs (Integrated Circuits) (counters, AND/OR/XOR/... logic gates, timers, ...).
+     - LD : Ladder Diagram
+            A graphical programming language, somewhat similar to an electrical circuit diagram based on 
+             relays (used for basic cabled logic controllers).
+     - SFC: Sequential Function Chart
+            A graphical programming language, that defines a state machine, based largely on Grafcet.
+            (may also be expressed in textual format).
+
+ Of the above 5 languages, the standard defines textual representations for IL, ST and SFC. 
+It is these 3 languages that we target, and we currently support all three, as long as they are
+expressed in the textual format as defined in the standard.
+
+ Currently the matiec project generates two compilers (more correctly, code translaters, but we like
+to call them compilers :-O ): iec2c, and iec2iec
+
+ Both compilers accept the same input: a text file with ST, IL and/or SFC code.
+
+ The iec2c compiler generates ANSI C code which is equivalent to the IEC 61131-3 code expressed in the input file.
+
+ The iec2iec compiler generates IEC61131-3 code which is equivalent to the IEC 61131-3 code expressed in the input file.
+This last compiler should generate and output file which should be almost identical to the input file (some formating 
+may change, as well as the case of letters, etc.). This 'compiler' is mostly used by the matiec project contributors
+to help debug the lexical and syntax portions of the compilers.
+
+
+
+ To compile/build these compilers, just
+$./configure; make
+
+
 
 
 
@@ -25,26 +82,111 @@
 ****************************************************************
 
  The compiler works in 4(+1) stages:
- Stage 1   - Lexical analyser      - implemented with flex (iec.flex)
- Stage 2   - Syntax parser         - implemented with bison (iec.y)
- Stage 3   - Semantics analyser    - currently in its early stages
- Stage 4   - Code generator        - implemented in C++
- Stage 4+1 - Binary code generator - gcc, javac, etc...
+ ==================================
+ Stage 1    - Lexical analyser       - implemented with flex (stage1_2/iec_flex.ll)
+ Stage 2    - Syntax parser          - implemented with bison (stage1_2/iec_bison.yy)
+ Stage pre3 - Populate symbol tables - Symbol tables that will ease searching for symbols in the abstract symbol tree.
+ Stage 3    - Semantics analyser     - currently does type checking only
+ Stage 4    - Code generator         - generates ANSI C code
+
+ Stage 5    - Binary code generator - gcc, javac, etc... (Not integrated into matiec compiler. Must be called explicitly by the user.)
+
 
 
  Data structures passed between stages, in global variables:
- 1->2   : tokens (int), and token values (char *)
- 2->1   : symbol tables (defined in symtable.hh)
- 2->3   : abstract syntax tree (tree of C++ classes, in absyntax.hh file)
- 3->4   : Same as 2->3
- 4->4+1 : file with program in c, java, etc...
+ ==========================================================
+   1->2   : tokens (int), and token values (char *) (defined in stage1_2/stage1_2_priv.hh)
+   2->1   : symbol tables (implemented in util/symtable.[hh|cc], and defined in stage1_2/stage1_2_priv.hh)
+   2->3   : abstract syntax tree (tree of C++ objects, whose classes are defined in absyntax/absyntax.hh)
+pre3->3,4 : global symbol tables (defined in util/[d]symtable.[hh|cc] and declared in absyntax_utils/absyntax_utils.hh)
+   3->4   : abstract syntax tree (same as 2->3), but now annotated (i.e. some extra data inserted into the absyntax tree)
+
+   4->5   : file with program in c, java, etc...
+
+
 
 
  The compiler works in several passes:
- Pass 1: executes stages 1 and 2 simultaneously
- Pass 2: executes stage 3
- Pass 3: executes stage 4
- Pass 4: executes stage 4+1
+ ====================================
+
+Stage 1 and Stage 2
+-------------------
+  Executed in one single pass. This pass will:
+  - Do lexical analysis
+  - Do syntax analysis
+  - Execute the absyntax_utils/add_en_eno_param_decl_c visitor class
+    This class will add the EN and ENO parameter declarations to all
+    functions that do not have them already explicitly declared by the user.
+    This will let us handle these parameters in the remaining compiler just as if
+    they were standard input/output parameters.
+
+
+Stage Pre3
+----------
+  Executed in one single pass. This pass will populate the following symbol tables:
+   - function_symtable;            /* A symbol table with all globally declared functions POUs. */
+   - function_block_type_symtable; /* A symbol table with all globally declared functions block POUs. */
+   - program_type_symtable;        /* A symbol table with all globally declared program POUs. */
+   - type_symtable;                /* A symbol table with all user declared (non elementary) datat type definitions. */
+   - enumerated_value_symtable;    /* A symbol table with all identifiers (values) declared for enumerated types. */
+
+
+Stage 3
+-------
+  Executes two algorithms (flow control analysis, and data type analysis) in several passes.
+
+  Flow control:
+     Pass 1: Does flow control analysis (for now only of IL code) 
+             Implemented in -> stage3/flow_control_analysis_c
+             This will anotate the abstract syntax tree 
+             (Every object of the class il_instruction_c that is in the abstract syntax tree will have the variable 'prev_il_instruction' correctly filled in.)
+
+  Data Type Analysis
+     Pass 1: Analyses the possible data types each expression/literal/IL instruction/etc. may take 
+             Implemented in -> stage3/fill_candidate_datatypes_c
+             This will anotate the abstract syntax tree 
+             (Every object of in the abstract syntax tree that may have a data type, will have the variable 'candidate_datatypes' correctly filled in.
+             Additionally, objects in the abstract syntax tree that represen function invocations will have the variable 
+              'candidate_functions' correctly filled in.)
+Pass 2: Narrows all the possible data types each expression/literal/IL instruction/etc. may take down to a single data type 
+             Implemented in -> stage3/narrow_candidate_datatypes_c
+             This will anotate the abstract syntax tree 
+             (Every object of in the abstract syntax tree that may have a data type, will have the variable 'datatype' correctly filled in.
+              Additionally, objects in the abstract syntax tree that represen function invocations will have the variables 
+              'called_function_declaration' and 'extensible_param_count' correctly filled in.
+              Additionally, objects in the abstract syntax tree that represen function block (FB) invocations will have the variable
+              'called_fb_declaration' correctly filled in.)
+     Pass 2: Prints error messages in the event of the IEC 61131-3 source code being analysed contains semantic data type incompatibility errors.
+             Implemented in -> stage3/print_datatype_errors_c
+
+  
+Stage 4
+-------
+  Has 2 possible implementations.
+  
+  iec2c  :  Generates C source code in a single pass (stage4/generate_c).
+  iec2iec:  Generates IEC61131 source code in a single pass (stage4/generate_iec).
+
+
+
+
+
+
+****************************************************************
+****************************************************************
+****************************************************************
+*********                                              *********
+*********                                              *********
+*********               N O T E S                      *********
+*********                                              *********
+*********                                              *********
+****************************************************************
+****************************************************************
+****************************************************************
+
+
+
+
 
 
  NOTE 1
@@ -388,4 +530,4 @@
 
 **************************************************************************
 
-  Copyright (C) 2003-2011  Mario de Sousa (msousa@fe.up.pt)
+  Copyright (C) 2003-2012  Mario de Sousa (msousa@fe.up.pt)
--- a/stage1_2/iec_bison.yy	Tue Aug 14 19:40:01 2012 +0200
+++ b/stage1_2/iec_bison.yy	Wed Aug 22 16:46:17 2012 +0200
@@ -58,6 +58,17 @@
 /**********************************************************************/
 /**********************************************************************/
 
+/* NOTE: the following file contains many rules used merely for detecting errors in
+ * the IEC source code being parsed.
+ * To remove all these rules, simply execute the command (first replace all '%' with '/'):
+ * $sed '\:%\* ERROR_CHECK_BEGIN \*%:,\:%\* ERROR_CHECK_END \*%: d' iec_bison.yy
+ *
+ * The above command had to be edited ('/' replaced by '%') so as not to include the C syntax that closes
+ * comments inside this comment!
+ * If you place the command in a shell script, be sure to remove the backslashes '\' before each asterisk '*' !!
+ */
+
+
 
 
 
@@ -150,10 +161,7 @@
          while (0)
 
 
-/* A macro for printing out internal parser errors... */
-#define ERROR error_exit(__FILE__,__LINE__)
-/* function defined in main.cc */
-extern void error_exit(const char *file_name, int line_no);
+#include "../main.hh" // required for ERROR() and ERROR_MSG() macros.
 
 
 
@@ -250,17 +258,9 @@
  * declared twice.
  * We therefore use the #if !defined YYLTYPE ...
  * to make sure only the first declaration is parsed by the C++ compiler.
- *
- * At first glance it seems that what we really should do is delcare the
- * YYLTYPE directly as an anonymous struct, thus:
- * #define YYLTYPE struct{ ...}
- * however, this also results in compilation errors.
- *
- * I (Mario) think this is kind of a hack. If you know how to
- * do this re-declaration of YYLTYPE properly, please let me know!
  */
 #if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED
-  typedef struct {
+typedef struct YYLTYPE {
     int         first_line;
     int         first_column;
     const char *first_file;
@@ -269,9 +269,11 @@
     int         last_column;
     const char *last_file;
     long int    last_order;
-  } yyltype__local;
-  #define YYLTYPE yyltype__local
+} YYLTYPE;
+#define YYLTYPE_IS_DECLARED 1
+#define YYLTYPE_IS_TRIVIAL 1
 #endif
+
 }
 
 
@@ -496,17 +498,6 @@
 %type  <leaf>	seconds
 %type  <leaf>	milliseconds
 
-%type  <leaf>	integer_d
-%type  <leaf>	integer_h
-%type  <leaf>	integer_m
-%type  <leaf>	integer_s
-%type  <leaf>	integer_ms
-%type  <leaf>	fixed_point_d
-%type  <leaf>	fixed_point_h
-%type  <leaf>	fixed_point_m
-%type  <leaf>	fixed_point_s
-%type  <leaf>	fixed_point_ms
-
 %token <ID>	fixed_point_token
 %token <ID>	fixed_point_d_token
 %token <ID>	integer_d_token
@@ -518,7 +509,8 @@
 %token <ID>	integer_s_token
 %token <ID>	fixed_point_ms_token
 %token <ID>	integer_ms_token
-
+%token <ID>	end_interval_token
+%token <ID>	erroneous_interval_token
 // %token TIME
 %token T_SHARP
 
@@ -1915,13 +1907,13 @@
 
 integer_literal:
   integer_type_name '#' signed_integer
-	{$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));}
+	{$$ = new integer_literal_c($1, $3, locloc(@$));}
 | integer_type_name '#' binary_integer
-	{$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));}
+	{$$ = new integer_literal_c($1, $3, locloc(@$));}
 | integer_type_name '#' octal_integer
-	{$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));}
+	{$$ = new integer_literal_c($1, $3, locloc(@$));}
 | integer_type_name '#' hex_integer
-	{$$ = new integer_literal_c($1, $3, locf(@1), locl(@3));}
+	{$$ = new integer_literal_c($1, $3, locloc(@$));}
 /* NOTE: see note in the definition of constant for reason
  * why signed_integer, binary_integer, octal_integer
  * and hex_integer are missing here!
@@ -1957,7 +1949,7 @@
  */
 /*  signed_real */
   real_type_name '#' signed_real
-	{$$ = new real_literal_c($1, $3, locf(@1), locl(@3));}
+	{$$ = new real_literal_c($1, $3, locloc(@$));}
 /* ERROR_CHECK_BEGIN */
 | real_type_name signed_real
 	{$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between real type name and value in real literal."); yynerrs++;}
@@ -1981,13 +1973,13 @@
 
 bit_string_literal:
   bit_string_type_name '#' integer  /* i.e. unsigned_integer */
-	{$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));}
+	{$$ = new bit_string_literal_c($1, $3, locloc(@$));}
 | bit_string_type_name '#' binary_integer
-	{$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));}
+	{$$ = new bit_string_literal_c($1, $3, locloc(@$));}
 | bit_string_type_name '#' octal_integer
-	{$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));}
+	{$$ = new bit_string_literal_c($1, $3, locloc(@$));}
 | bit_string_type_name '#' hex_integer
-	{$$ = new bit_string_literal_c($1, $3, locf(@1), locl(@3));}
+	{$$ = new bit_string_literal_c($1, $3, locloc(@$));}
 /* NOTE: see note in the definition of constant for reason
  * why unsigned_integer, binary_integer, octal_integer
  * and hex_integer are missing here!
@@ -2144,156 +2136,56 @@
 	{$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME' and interval in duration."); yynerrs++;}
 | TIME '-' interval
 	{$$ = NULL; print_err_msg(locl(@1), locf(@2), "'#' missing between 'TIME' and interval in duration."); yynerrs++;}
-| TIME '#' error
-	{$$ = NULL;
-	 if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for duration.");}
-	 else {print_err_msg(locf(@3), locl(@3), "invalid value for duration."); yyclearin;}
-	 yyerrok;
-	}
-| T_SHARP error
-	{$$ = NULL;
-	 if (is_current_syntax_token()) {print_err_msg(locl(@1), locf(@2), "no value defined for duration.");}
-	 else {print_err_msg(locf(@2), locl(@2), "invalid value for duration."); yyclearin;}
-	 yyerrok;
-	}
-/* ERROR_CHECK_END */
-;
+| TIME '#' erroneous_interval_token
+	{$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value for duration."); yynerrs++;}
+| T_SHARP erroneous_interval_token
+	{$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid value for duration."); yynerrs++;}
+| TIME '#' '-' erroneous_interval_token
+	{$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid value for duration."); yynerrs++;}
+| T_SHARP '-' erroneous_interval_token
+	{$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid value for duration."); yynerrs++;}
+/* ERROR_CHECK_END */
+;
+
+fixed_point:
+  integer
+| fixed_point_token	{$$ = new fixed_point_c($1, locloc(@$));};
 
 
 interval:
-  days
-| hours
-| minutes
-| seconds
-| milliseconds
-;
-
-integer_d:  integer_d_token  {$$ = new integer_c($1, locloc(@$));};
-integer_h:  integer_h_token  {$$ = new integer_c($1, locloc(@$));};
-integer_m:  integer_m_token  {$$ = new integer_c($1, locloc(@$));};
-integer_s:  integer_s_token  {$$ = new integer_c($1, locloc(@$));};
-integer_ms: integer_ms_token {$$ = new integer_c($1, locloc(@$));};
-
-fixed_point_d:
-  fixed_point_d_token
-	{$$ = new fixed_point_c($1, locloc(@$));}
-| integer_d
-;
-
-fixed_point_h:
-  fixed_point_h_token
-	{$$ = new fixed_point_c($1, locloc(@$));}
-| integer_h
-;
-
-fixed_point_m:
-  fixed_point_m_token
-	{$$ = new fixed_point_c($1, locloc(@$));}
-| integer_m
-;
-
-fixed_point_s:
-  fixed_point_s_token
-	{$$ = new fixed_point_c($1, locloc(@$));}
-| integer_s
-;
-
-fixed_point_ms:
-  fixed_point_ms_token
-	{$$ = new fixed_point_c($1, locloc(@$));}
-| integer_ms
-;
-
-
-fixed_point:
-  fixed_point_token
-	{$$ = new fixed_point_c($1, locloc(@$));}
-| integer
-;
-
-
-days:
-/*  fixed_point ('d') */
-  fixed_point_d
-	{$$ = new days_c($1, NULL, locloc(@$));}
-/*| integer ('d') ['_'] hours */
-| integer_d hours
-	{$$ = new days_c($1, $2, locloc(@$));}
-| integer_d '_' hours
-	{$$ = new days_c($1, $3, locloc(@$));}
-/* ERROR_CHECK_BEGIN */
-| integer_d '_' error
-	{$$ = NULL;
-	 if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for hours in duration.");}
-	 else {print_err_msg(locf(@3), locl(@3), "invalid value for hours in duration."); yyclearin;}
-	 yyerrok;
-	}
-/* ERROR_CHECK_END */
-;
-
-
-hours:
-/*  fixed_point ('h') */
-  fixed_point_h
-	{$$ = new hours_c($1, NULL, locloc(@$));}
-/*| integer ('h') ['_'] minutes */
-| integer_h minutes
-	{$$ = new hours_c($1, $2, locloc(@$));}
-| integer_h '_' minutes
-	{$$ = new hours_c($1, $3, locloc(@$));}
-/* ERROR_CHECK_BEGIN */
-| integer_h '_' error
-	{$$ = NULL;
-	 if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for minutes in duration.");}
-	 else {print_err_msg(locf(@3), locl(@3), "invalid value for minutes in duration."); yyclearin;}
-	 yyerrok;
-	}
-/* ERROR_CHECK_END */
-
-;
-
-minutes:
-/*  fixed_point ('m') */
-  fixed_point_m
-	{$$ = new minutes_c($1, NULL, locloc(@$));}
-/*| integer ('m') ['_'] seconds */
-| integer_m seconds
-	{$$ = new minutes_c($1, $2, locloc(@$));}
-| integer_m '_' seconds
-	{$$ = new minutes_c($1, $3, locloc(@$));}
-/* ERROR_CHECK_BEGIN */
-| integer_m '_' error
-	{$$ = NULL;
-	 if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for seconds in duration.");}
-	 else {print_err_msg(locf(@3), locl(@3), "invalid value for seconds in duration."); yyclearin;}
-	 yyerrok;
-	}
-/* ERROR_CHECK_END */
-;
-
-seconds:
-/*  fixed_point ('s') */
-  fixed_point_s
-	{$$ = new seconds_c($1, NULL, locloc(@$));}
-/*| integer ('s') ['_'] milliseconds */
-| integer_s milliseconds
-	{$$ = new seconds_c($1, $2, locloc(@$));}
-| integer_s '_' milliseconds
-	{$$ = new seconds_c($1, $3, locloc(@$));}
-/* ERROR_CHECK_BEGIN */
-| integer_s '_' error
-	{$$ = NULL;
-	 if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for milliseconds in duration.");}
-	 else {print_err_msg(locf(@3), locl(@3), "invalid value for milliseconds in duration."); yyclearin;}
-	 yyerrok;
-	}
-/* ERROR_CHECK_END */
-;
-
-milliseconds:
-/*  fixed_point ('ms') */
-  fixed_point_ms
-	{$$ = new milliseconds_c($1, locloc(@$));}
+  days hours minutes seconds milliseconds end_interval_token
+	{$$ = new interval_c($1, $2, $3, $4, $5, locloc(@$));};
+;
+
+
+days:   /*  fixed_point ('d') */
+  /* empty */		{$$ = NULL;}
+| fixed_point_d_token	{$$ = new fixed_point_c($1, locloc(@$));};
+| integer_d_token	{$$ = new integer_c($1, locloc(@$));};
+;
+
+hours:  /*  fixed_point ('h') */
+  /* empty */		{$$ = NULL;}
+| fixed_point_h_token	{$$ = new fixed_point_c($1, locloc(@$));};
+| integer_h_token	{$$ = new integer_c($1, locloc(@$));};
+;
+
+minutes: /*  fixed_point ('m') */
+  /* empty */		{$$ = NULL;}
+| fixed_point_m_token	{$$ = new fixed_point_c($1, locloc(@$));};
+| integer_m_token	{$$ = new integer_c($1, locloc(@$));};
+;
+
+seconds: /*  fixed_point ('s') */
+  /* empty */		{$$ = NULL;}
+| fixed_point_s_token	{$$ = new fixed_point_c($1, locloc(@$));};
+| integer_s_token	{$$ = new integer_c($1, locloc(@$));};
+;
+
+milliseconds: /*  fixed_point ('ms') */
+  /* empty */		{$$ = NULL;}
+| fixed_point_ms_token	{$$ = new fixed_point_c($1, locloc(@$));};
+| integer_ms_token	{$$ = new integer_c($1, locloc(@$));};
 ;
 
 
@@ -2991,13 +2883,18 @@
 	{$$ = new array_initial_elements_list_c(locloc(@$)); $$->add_element($1);}
 | array_initial_elements_list ',' array_initial_elements
 	{$$ = $1; $$->add_element($3);}
-/* ERROR_CHECK_BEGIN 
+/* ERROR_CHECK_BEGIN */
+/* The following error checking rules have been commented out. Why? Was it a typo? 
+ * Lets keep them commented out for now...
+ */
+/*
 | array_initial_elements_list ',' error
 	{$$ = $1;
 	 if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no array initial value in array initial values list.");}
 	 else {print_err_msg(locf(@3), locl(@3), "invalid array initial value in array initial values list."); yyclearin;}
 	 yyerrok;
 	}
+*/
 /* ERROR_CHECK_END */
 ;
 
@@ -3151,7 +3048,11 @@
 	{$$ = new structure_element_initialization_list_c(locloc(@$)); $$->add_element($1);}
 | structure_element_initialization_list ',' structure_element_initialization
 	{$$ = $1; $$->add_element($3);}
-/* ERROR_CHECK_BEGIN 
+/* ERROR_CHECK_BEGIN */
+/* The following error checking rules have been commented out. Why? Was it a typo? 
+ * Lets keep them commented out for now...
+ */
+/*
 | structure_element_initialization_list structure_element_initialization
 	{$$ = $1; print_err_msg(locl(@1), locf(@2), "',' missing in structure element initialization list in structure initialization."); yynerrs++;}
 | structure_element_initialization_list ',' error
@@ -3160,6 +3061,7 @@
 	 else {print_err_msg(locf(@3), locl(@3), "invalid structure element initialization in structure initialization."); yyclearin;}
 	 yyerrok;
 	}
+*/
 /* ERROR_CHECK_END */
 ;
 
@@ -3407,7 +3309,7 @@
   record_variable '.' field_selector
 	{$$ = new structured_variable_c($1, $3, locloc(@$));}
 | record_variable '.' il_simple_operator_clash3
-    {$$ = new structured_variable_c($1, $3, locloc(@$));}
+    {$$ = new structured_variable_c($1, il_operator_c_2_identifier_c($3), locloc(@$));}
 ;
 
 
@@ -5237,7 +5139,9 @@
 initial_step:
   INITIAL_STEP step_name ':' action_association_list END_STEP
 //  INITIAL_STEP identifier ':' action_association_list END_STEP
-	{$$ = new initial_step_c($2, $4, locloc(@$));}
+	{$$ = new initial_step_c($2, $4, locloc(@$));
+	 variable_name_symtable.insert($2, prev_declared_variable_name_token); // A step name may later be used as a structured variable!!
+	}
 /* ERROR_CHECK_BEGIN */
 | INITIAL_STEP ':' action_association_list END_STEP
   {$$ = NULL; print_err_msg(locf(@1), locl(@2), "no step name defined in initial step declaration."); yynerrs++;}
@@ -5257,7 +5161,9 @@
 step:
   STEP step_name ':' action_association_list END_STEP
 //  STEP identifier ':' action_association_list END_STEP
-	{$$ = new step_c($2, $4, locloc(@$));}
+	{$$ = new step_c($2, $4, locloc(@$));
+	 variable_name_symtable.insert($2, prev_declared_variable_name_token); // A step name may later be used as a structured variable!!
+	}
 /* ERROR_CHECK_BEGIN */
 | STEP ':' action_association_list END_STEP
   {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no step name defined in step declaration."); yynerrs++;}
@@ -5359,9 +5265,58 @@
 | SL		{$$ = new timed_qualifier_c(strdup("SL"), locloc(@$));}
 ;
 
+/* NOTE: A step_name may be used as a structured vaqriable, in order to access the status bit (e.g. Step1.X) 
+ *       or the time it has been active (e.g. Step1.T). 
+ *       In order to allow the step name to be used as a variable inside ST expressions (only ST expressions ??)
+ *       when defining transitions, we need to add the step_name to the list of previously declared variables.
+ *       This allows the step name to be used as a variable inside all transition expressions, as the user
+ *       can clearly define the transition _after_ the step itself has been defined/declared, so the 
+ *       'variable' is previously 'declared'.
+ *
+ *       However, when defining/declaring a step, a variable name can also be used to define a timed
+ *       action association. In this case, we may have a circular reference:
+ *        e.g.
+ *            ...
+ *             STEP step1:
+ *                action1 (D,t#100ms);
+ *             end_step
+ *
+ *             STEP step2:
+ *                action1 (D,step3.T);  <---- forward reference to step3.T !!!!!!
+ *             end_step
+ *
+ *             STEP step3:
+ *                action1 (D,step2.T);  <---- back reference to step2.T
+ *             end_step
+ *
+ *
+ *         There is no way the user can always use the step3.T variable only after it has
+ *         been 'declared'. So adding the steps to the list of previously declared variables 
+ *         when the steps are declared is not a solution to the above situation.
+ *
+ *         Fortunately, the standard does not allow ST expressions in the above syntax
+ *         (i.e. when defining the delay of a timed actions), but only either a 
+ *         Time literal, or a variable.
+ *         This is why we change the definition of action_time from
+ *         action_time:
+ *           duration
+ *         | variable
+ *         ;
+ *
+ *         to:
+ *         action_time:
+ *           duration
+ *         | any_symbolic_variable
+ *         ;
+ *
+ *       NOTE that this same problem does not occur with the 'indicator_name': it does not
+ *       make sense to set/indicate a step1.X variable, as these variables are read-only!
+ */     
+    
 action_time:
   duration
-| variable
+//| variable
+  | any_symbolic_variable
 ;
 
 indicator_name: variable;
@@ -5460,12 +5415,15 @@
   {$$ = NULL;}
 | '(' {cmd_goto_sfc_priority_state();} PRIORITY {cmd_pop_state();} ASSIGN integer ')'
 	{$$ = $6;}
-/* ERROR_CHECK_BEGIN 
+/* ERROR_CHECK_BEGIN */
+/* The following error checking rules have been intentionally commented out. */
+/*
 | '(' ASSIGN integer ')'
 	{$$ = NULL; print_err_msg(locl(@1), locf(@2), "'PRIORITY' missing between '(' and ':=' in transition declaration with priority."); yynerrs++;}
 | '(' error ASSIGN integer ')'
 	{$$ = NULL; print_err_msg(locf(@2), locl(@2), "expecting 'PRIORITY' between '(' and ':=' in transition declaration with priority."); yyerrok;}
- ERROR_CHECK_END */
+*/
+/* ERROR_CHECK_END */
 ;
 
 
@@ -6293,7 +6251,7 @@
   il_instruction
 	{$$ = new instruction_list_c(locloc(@$)); $$->add_element($1);}
 | any_pragma eol_list
-	{$$ = new instruction_list_c(locloc(@$)); $$->add_element($1);}
+	{$$ = new instruction_list_c(locloc(@1)); $$->add_element($1);} /* locloc(@1) is not a bug! We ignore trailing EOLs when determining symbol location! */
 | instruction_list il_instruction
 	{$$ = $1; $$->add_element($2);}
 | instruction_list any_pragma
@@ -6304,11 +6262,11 @@
 
 il_instruction:
   il_incomplete_instruction eol_list
-	{$$ = new il_instruction_c(NULL, $1, locloc(@$));}
+	{$$ = new il_instruction_c(NULL, $1, locloc(@1));} /* locloc(@1) is not a bug! We ignore trailing EOLs when determining symbol location! */
 | label ':' il_incomplete_instruction eol_list
-	{$$ = new il_instruction_c($1, $3, locloc(@$));}
+	{$$ = new il_instruction_c($1, $3, locf(@1), locl(@3));} /* locf(@1), locl(@3) is not a bug! We ignore trailing EOLs when determining symbol location! */
 | label ':' eol_list
-	{$$ = new il_instruction_c($1, NULL, locloc(@$));}
+	{$$ = new il_instruction_c($1, NULL, locf(@1), locl(@2));} /* locf(@1), locl(@2) is not a bug! We ignore trailing EOLs when determining symbol location! */
 /* ERROR_CHECK_BEGIN */
 | error eol_list
 	{$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid IL instruction."); yyerrok;}
@@ -6643,8 +6601,11 @@
 
 il_simple_instruction:
   il_simple_operation eol_list
+	{$$ = new il_simple_instruction_c($1, locloc(@1));} /* locloc(@1) is not a bug! We ignore trailing EOLs when determining symbol location! */
 | il_expression eol_list
+	{$$ = new il_simple_instruction_c($1, locloc(@1));} /* locloc(@1) is not a bug! We ignore trailing EOLs when determining symbol location! */
 | il_formal_funct_call eol_list
+	{$$ = new il_simple_instruction_c($1, locloc(@1));} /* locloc(@1) is not a bug! We ignore trailing EOLs when determining symbol location! */
 /* ERROR_CHECK_BEGIN */
 | il_expression error
   {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing after expression IL instruction."); yyerrok;}
@@ -8062,11 +8023,11 @@
 
   if (full_token_loc) {
     if (first_filename == last_filename)
-      fprintf(stderr, "%s:%d-%d..%d-%d: error : %s\n", first_filename, first_line, first_column, last_line, last_column, additional_error_msg);
+      fprintf(stderr, "%s:%d-%d..%d-%d: error: %s\n", first_filename, first_line, first_column, last_line, last_column, additional_error_msg);
     else
-      fprintf(stderr, "%s:%d-%d..%s:%d-%d: error : %s\n", first_filename, first_line, first_column, last_filename, last_line, last_column, additional_error_msg);
+      fprintf(stderr, "%s:%d-%d..%s:%d-%d: error: %s\n", first_filename, first_line, first_column, last_filename, last_line, last_column, additional_error_msg);
   } else {
-      fprintf(stderr, "%s:%d: error : %s\n", first_filename, first_line, additional_error_msg);
+      fprintf(stderr, "%s:%d: error: %s\n", first_filename, first_line, additional_error_msg);
   }
   //fprintf(stderr, "error %d: %s\n", yynerrs /* a global variable */, additional_error_msg);
   print_include_stack();
@@ -8253,6 +8214,7 @@
   }
 
   /* first parse the standard library file... */
+  /* Do not debug the standard library, even if debug flag is set! */
   /*
   #if YYDEBUG
     yydebug = 1;
@@ -8268,7 +8230,7 @@
       ERROR;
 
   if (yynerrs > 0) {
-    fprintf (stderr, "\nFound %d error(s) in %s. Bailing out!\n", yynerrs /* global variable */, libfilename);
+    fprintf (stderr, "\n%d error(s) found in %s. Bailing out!\n", yynerrs /* global variable */, libfilename);
     ERROR;
   }
   free(libfilename);
@@ -8301,7 +8263,7 @@
   }
 
   if (yynerrs > 0) {
-    fprintf (stderr, "\nFound %d error(s). Bailing out!\n", yynerrs /* global variable */);
+    fprintf (stderr, "\n%d error(s) found. Bailing out!\n", yynerrs /* global variable */);
     exit(EXIT_FAILURE);
   }
   
--- a/stage1_2/iec_flex.ll	Tue Aug 14 19:40:01 2012 +0200
+++ b/stage1_2/iec_flex.ll	Wed Aug 22 16:46:17 2012 +0200
@@ -91,8 +91,10 @@
  */
 %option noyy_top_state
 
-/* We will not be using unput() in our flex code... */
+/* We will be using unput() in our flex code, so we cannot set the following option!... */
+/*
 %option nounput
+*/
 
 /**************************************************/
 /* External Variable and Function declarations... */
@@ -171,8 +173,9 @@
  * track of the locations, in order to give
  * more meaningful error messages!
  */
-extern YYLTYPE yylloc;
-
+/*
+ *extern YYLTYPE yylloc;
+b*/
 #define YY_INPUT(buf,result,max_size)  {\
     result = GetNextChar(buf, max_size);\
     if (  result <= 0  )\
@@ -208,7 +211,6 @@
 	current_order++;							\
 	}
 
-
 /* Since this lexical parser we defined only works in ASCII based
  * systems, we might as well make sure it is being compiled on
  * one...
@@ -241,6 +243,10 @@
 %{
 /* return all the text in the current token back to the input stream. */
 void unput_text(unsigned int n);
+/* return all the text in the current token back to the input stream, 
+ * but first return to the stream an additional character to mark the end of the token. 
+ */
+void unput_and_mark(const char c);
 %}
 
 
@@ -340,6 +346,16 @@
  * expecting any action qualifiers, flex does not return these tokens, and is free
  * to interpret them as previously defined variables/functions/... as the case may be.
  *
+ * The time_literal_state is required because TIME# literals are decomposed into 
+ * portions, and wewant to send these portions one by one to bison. Each poertion will 
+ * represent the value in days/hours/minutes/seconds/ms.
+ * Unfortunately, some of these portions may also be lexically analysed as an identifier. So,
+ * we need to disable lexical identification of identifiers while parsing TIME# literals!
+ * e.g.:  TIME#55d_4h_56m
+ *       We would like to return to bison the tokens 'TIME' '#' '55d' '_' '4h' '_' '56m'
+ *       Unfortunately, flex will join '_' and '4h' to create a legal {identifier} '_4h',
+ *       and return that identifier instead! So, we added this state!
+ *
  * The state machine has 7 possible states (INITIAL, config, decl, body, st, il, sfc)
  * Possible state changes are:
  *   INITIAL -> goto(decl_state)
@@ -418,7 +434,8 @@
 /* we are parsing sfc code, and expecting the priority token.       */
 %s sfc_priority_state
 
-
+/* we are parsing a TIME# literal. We must not return any {identifier} tokens. */
+%x time_literal_state
 
 
 /*******************/
@@ -598,6 +615,15 @@
 /* B.1.2.1   Numeric literals */
 /******************************/
 integer         {digit}((_?{digit})*)
+
+/* Some helper symbols for parsing TIME literals... */
+integer_0_59    (0(_?))*([0-5](_?))?{digit}
+integer_0_19    (0(_?))*([0-1](_?))?{digit}
+integer_20_23   (0(_?))*2(_?)[0-3]
+integer_0_23    {integer_0_19}|{integer_20_23}
+integer_0_999   {digit}((_?{digit})?)((_?{digit})?)
+
+
 binary_integer  2#{bit}((_?{bit})*)
 bit		[0-1]
 octal_integer   8#{octal_digit}((_?{octal_digit})*)
@@ -673,21 +699,54 @@
 /************************/
 fixed_point		{integer}\.{integer}
 
-fixed_point_d		{fixed_point}d
-integer_d		{integer}d
-
-fixed_point_h		{fixed_point}h
-integer_h		{integer}h
-
-fixed_point_m		{fixed_point}m
-integer_m		{integer}m
-
-fixed_point_s		{fixed_point}s
-integer_s		{integer}s
-
-fixed_point_ms		{fixed_point}ms
-integer_ms		{integer}ms
-
+
+/* NOTE: The IEC 61131-3 v2 standard has an incorrect formal syntax definition of duration,
+ *       as its definition does not match the standard's text.
+ *       IEC 61131-3 v3 (committee draft) seems to have this fixed, so we use that
+ *       definition instead!
+ *
+ *       duration::= ('T' | 'TIME') '#' ['+'|'-'] interval
+ *       interval::= days | hours | minutes | seconds | milliseconds
+ *       fixed_point  ::= integer [ '.' integer]
+ *       days         ::= fixed_point 'd' | integer 'd' ['_'] [ hours ]
+ *       hours        ::= fixed_point 'h' | integer 'h' ['_'] [ minutes ]
+ *       minutes      ::= fixed_point 'm' | integer 'm' ['_'] [ seconds ]
+ *       seconds      ::= fixed_point 's' | integer 's' ['_'] [ milliseconds ]
+ *       milliseconds ::= fixed_point 'ms'
+ * 
+ * 
+ *  The original IEC 61131-3 v2 definition is:
+ *       duration ::= ('T' | 'TIME') '#' ['-'] interval
+ *       interval ::= days | hours | minutes | seconds | milliseconds
+ *       fixed_point  ::= integer [ '.' integer]
+ *       days         ::= fixed_point 'd' | integer 'd' ['_'] hours
+ *       hours        ::= fixed_point 'h' | integer 'h' ['_'] minutes
+ *       minutes      ::= fixed_point 'm' | integer 'm' ['_'] seconds
+ *       seconds      ::= fixed_point 's' | integer 's' ['_'] milliseconds
+ *       milliseconds ::= fixed_point 'ms'
+
+ */
+
+interval_ms_X		({integer_0_999}(\.{integer})?)ms
+interval_s_X		{integer_0_59}s(_?{interval_ms_X})?
+interval_m_X		{integer_0_59}m(_?{interval_s_X})?
+interval_h_X		{integer_0_23}h(_?{interval_m_X})?
+
+interval_ms		{integer}ms|({fixed_point}ms)
+interval_s		{integer}s(_?{interval_ms_X})?|({fixed_point}s)
+interval_m		{integer}m(_?{interval_s_X})?|({fixed_point}m)
+interval_h		{integer}h(_?{interval_m_X})?|({fixed_point}h)
+interval_d		{integer}d(_?{interval_h_X})?|({fixed_point}d)
+
+interval		{interval_ms}|{interval_s}|{interval_m}|{interval_h}|{interval_d}
+
+/* to help provide nice error messages, we also parse an incorrect but plausible interval... */
+/* NOTE that this erroneous interval will be parsed outside the time_literal_state, so must not 
+ *      be able to parse any other legal lexcial construct (besides a legal interval, but that
+ *      is OK as this rule will appear _after_ the rule to parse legal intervals!).
+ */
+fixed_point_or_integer  {fixed_point}|{integer}
+erroneous_interval	({fixed_point_or_integer}d_?)?({fixed_point_or_integer}h_?)?({fixed_point_or_integer}m_?)?({fixed_point_or_integer}s_?)?({fixed_point_or_integer}ms)?
 
 /********************************************/
 /* B.1.4.1   Directly Represented Variables */
@@ -719,9 +778,9 @@
  *    in which case we are currently using "%I3" as the variable
  *    name.
  */
-direct_variable_matplc		%{identifier}
-
-direct_variable			{direct_variable_standard}|{direct_variable_matplc}
+/* direct_variable_matplc		%{identifier} */
+/* direct_variable			{direct_variable_standard}|{direct_variable_matplc} */
+direct_variable			{direct_variable_standard}
 
 /******************************************/
 /* B 1.4.3 - Declaration & Initialisation */
@@ -1541,23 +1600,26 @@
 	/* B 1.2.3.1 - Duration */
 	/************************/
 {fixed_point}		{yylval.ID=strdup(yytext); return fixed_point_token;}
-
-{fixed_point_d}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_d_token;}
-{integer_d}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_d_token;}
-
-{fixed_point_h}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_h_token;}
-{integer_h}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_h_token;}
-
-{fixed_point_m}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_m_token;}
-{integer_m}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_m_token;}
-
-{fixed_point_s}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_s_token;}
-{integer_s}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_s_token;}
-
-{fixed_point_ms}	{yylval.ID=strdup(yytext); yylval.ID[yyleng-2] = '\0'; return fixed_point_ms_token;}
-{integer_ms}		{yylval.ID=strdup(yytext); yylval.ID[yyleng-2] = '\0'; return integer_ms_token;}
-
-
+{interval}		{/*fprintf(stderr, "entering time_literal_state ##%s##\n", yytext);*/ unput_and_mark('#'); yy_push_state(time_literal_state);}
+{erroneous_interval}	{return erroneous_interval_token;}
+
+<time_literal_state>{
+{integer}d		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_d_token;}
+{integer}h		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_h_token;}
+{integer}m		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_m_token;}
+{integer}s		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return integer_s_token;}
+{integer}ms		{yylval.ID=strdup(yytext); yylval.ID[yyleng-2] = '\0'; return integer_ms_token;}
+{fixed_point}d		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_d_token;}
+{fixed_point}h		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_h_token;}
+{fixed_point}m		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_m_token;}
+{fixed_point}s		{yylval.ID=strdup(yytext); yylval.ID[yyleng-1] = '\0'; return fixed_point_s_token;}
+{fixed_point}ms		{yylval.ID=strdup(yytext); yylval.ID[yyleng-2] = '\0'; return fixed_point_ms_token;}
+
+_			/* do nothing - eat it up!*/
+\#			{/*fprintf(stderr, "popping from time_literal_state (###)\n");*/ yy_pop_state(); return end_interval_token;}
+.			{/*fprintf(stderr, "time_literal_state: found invalid character '%s'. Aborting!\n", yytext);*/ ERROR;}
+\n			{ERROR;}
+}
 	/*******************************/
 	/* B.1.2.2   Character Strings */
 	/*******************************/
@@ -1645,6 +1707,20 @@
 }
 
 
+/* return all the text in the current token back to the input stream, 
+ * but first return to the stream an additional character to mark the end of the token. 
+ */
+void unput_and_mark(const char c) {
+  char *yycopy = strdup( yytext ); /* unput() destroys yytext, so we copy it first */
+  unput(c);
+  for (int i = yyleng-1; i >= 0; i--)
+    unput(yycopy[i]);
+
+  free(yycopy);
+}
+
+
+
 /* Called by flex when it reaches the end-of-file */
 int yywrap(void)
 {
--- a/stage3/Makefile.am	Tue Aug 14 19:40:01 2012 +0200
+++ b/stage3/Makefile.am	Wed Aug 22 16:46:17 2012 +0200
@@ -4,5 +4,12 @@
 
 libstage3_a_SOURCES = \
 	stage3.cc \
-	visit_expression_type.cc 
+	flow_control_analysis.cc \
+	fill_candidate_datatypes.cc \
+	narrow_candidate_datatypes.cc \
+	print_datatypes_error.cc \
+	datatype_functions.cc \
+	lvalue_check.cc \
+	array_range_check.cc \
+        constant_folding.cc
 
--- a/stage3/Makefile.in	Tue Aug 14 19:40:01 2012 +0200
+++ b/stage3/Makefile.in	Wed Aug 22 16:46:17 2012 +0200
@@ -33,7 +33,7 @@
 PRE_UNINSTALL = :
 POST_UNINSTALL = :
 DIST_COMMON = $(srcdir)/../common.mk $(srcdir)/Makefile.am \
-	$(srcdir)/Makefile.in
+	$(srcdir)/Makefile.in TODO
 subdir = stage3
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/configure.ac
@@ -71,7 +71,12 @@
 libstage3_a_AR = $(AR) $(ARFLAGS)
 libstage3_a_LIBADD =
 am_libstage3_a_OBJECTS = stage3.$(OBJEXT) \
-	visit_expression_type.$(OBJEXT)
+	flow_control_analysis.$(OBJEXT) \
+	fill_candidate_datatypes.$(OBJEXT) \
+	narrow_candidate_datatypes.$(OBJEXT) \
+	print_datatypes_error.$(OBJEXT) datatype_functions.$(OBJEXT) \
+	lvalue_check.$(OBJEXT) array_range_check.$(OBJEXT) \
+	constant_folding.$(OBJEXT)
 libstage3_a_OBJECTS = $(am_libstage3_a_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/config
 depcomp = $(SHELL) $(top_srcdir)/config/depcomp
@@ -188,7 +193,14 @@
 lib_LIBRARIES = libstage3.a
 libstage3_a_SOURCES = \
 	stage3.cc \
-	visit_expression_type.cc 
+	flow_control_analysis.cc \
+	fill_candidate_datatypes.cc \
+	narrow_candidate_datatypes.cc \
+	print_datatypes_error.cc \
+	datatype_functions.cc \
+	lvalue_check.cc \
+	array_range_check.cc \
+        constant_folding.cc
 
 all: all-am
 
@@ -267,8 +279,15 @@
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/array_range_check.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/constant_folding.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/datatype_functions.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fill_candidate_datatypes.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow_control_analysis.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lvalue_check.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/narrow_candidate_datatypes.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/print_datatypes_error.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stage3.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/visit_expression_type.Po@am__quote@
 
 .cc.o:
 @am__fastdepCXX_TRUE@	$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/TODO	Wed Aug 22 16:46:17 2012 +0200
@@ -0,0 +1,13 @@
+
+
+ Things that we must still check for in stage 3:
+
+
+1) Handling of CONSTANTs:
+
+ 1.a) "Any program organization unit attempts to modify the value of a variable that has been declared with the CONSTANT qualifier;"
+ 1.b) From table 16.a "The CONSTANT qualifier shall not be used in the declaration of function block instances as described in 2.5.2.1."
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/array_range_check.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -0,0 +1,322 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2009-2012  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2012       Manuele Conti  (conti.ma@alice.it)
+ *
+ *
+ *  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)
+ *
+ */
+
+
+/*
+ * Array Range Checking:
+ *   - Check whether array subscript values fall within the allowed range.
+ *     Note that for the checking of subscript values to work correctly, we need to have constant folding working too:
+ *     array_var[8 + 99] can not be checked without constant folding.
+ */
+
+
+#include "array_range_check.hh"
+#include <limits>  // required for std::numeric_limits<XXX>
+
+
+#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;                                                                                                   \
+}
+
+#define GET_CVALUE(dtype, symbol)             ((symbol)->const_value._##dtype.value)
+#define VALID_CVALUE(dtype, symbol)           (symbol_c::cs_const_value == (symbol)->const_value._##dtype.status)
+
+/*  The cmp_unsigned_signed function compares two numbers u and s.
+ *  It returns an integer indicating the relationship between the numbers:
+ *  - A zero value indicates that both numbers are equal.
+ *  - A value greater than zero indicates that numbers does not match and
+ *    first has a greater value.
+ *  - A value less than zero indicates that numbers does not match and
+ *    first has a lesser value.
+ */
+static inline int cmp_unsigned_signed(const uint64_t u, const int64_t s) {
+  const uint64_t INT64_MAX_uvar = INT64_MAX;
+  if (u <= INT64_MAX_uvar)
+    return ((int64_t)u - s);
+  return -1;
+}
+
+array_range_check_c::array_range_check_c(symbol_c *ignore) {
+	error_count = 0;
+	current_display_error_level = 0;
+}
+
+
+
+array_range_check_c::~array_range_check_c(void) {
+}
+
+
+
+int array_range_check_c::get_error_count() {
+	return error_count;
+}
+
+
+
+void array_range_check_c::check_dimension_count(array_variable_c *symbol) {
+	int dimension_count;
+	symbol_c *var_decl;
+
+	var_decl = search_varfb_instance_type->get_basetype_decl(symbol->subscripted_variable);
+	array_dimension_iterator_c array_dimension_iterator(var_decl);
+	for (dimension_count = 0; NULL != array_dimension_iterator.next(); dimension_count++);
+	if (dimension_count != ((list_c *)symbol->subscript_list)->n)
+		STAGE3_ERROR(0, symbol, symbol, "Number of subscripts/indexes does not match the number of subscripts/indexes in the array's declaration (array has %d indexes)", dimension_count);
+}
+
+
+
+void array_range_check_c::check_bounds(array_variable_c *symbol) {
+  list_c *l; /* the subscript_list */
+  symbol_c *var_decl;
+
+  l = (list_c *)symbol->subscript_list;
+  var_decl = search_varfb_instance_type->get_basetype_decl(symbol->subscripted_variable);
+  array_dimension_iterator_c array_dimension_iterator(var_decl);
+  for (int i =  0; i < l->n; i++) {
+    subrange_c *dimension = array_dimension_iterator.next();
+    /* mismatch between number of indexes/subscripts. This error will be caught in check_dimension_count() so we ignore it. */
+    if (NULL == dimension) 
+      return;
+
+    /* Check lower limit */
+    if ( VALID_CVALUE( int64, l->elements[i]) && VALID_CVALUE( int64, dimension->lower_limit))
+      if ( GET_CVALUE( int64, l->elements[i]) < GET_CVALUE( int64, dimension->lower_limit) )
+      {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds."); continue;}
+
+    if ( VALID_CVALUE( int64, l->elements[i]) && VALID_CVALUE(uint64, dimension->lower_limit))
+      if ( cmp_unsigned_signed( GET_CVALUE(uint64, dimension->lower_limit), GET_CVALUE( int64, l->elements[i])) > 0 )
+      {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds."); continue;}
+
+    if ( VALID_CVALUE(uint64, l->elements[i]) && VALID_CVALUE(uint64, dimension->lower_limit))
+      if ( GET_CVALUE(uint64, l->elements[i])   <  GET_CVALUE(uint64, dimension->lower_limit))
+      {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds."); continue;}
+
+    if ( VALID_CVALUE(uint64, l->elements[i]) && VALID_CVALUE( int64, dimension->lower_limit))
+      if ( cmp_unsigned_signed(GET_CVALUE(uint64, l->elements[i]), GET_CVALUE( int64, dimension->lower_limit)) < 0 )
+      {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds."); continue;}
+
+    /* Repeat the same check, now for upper limit */
+    if ( VALID_CVALUE( int64, l->elements[i]) && VALID_CVALUE( int64, dimension->upper_limit))
+      if ( GET_CVALUE( int64, l->elements[i])   >  GET_CVALUE( int64, dimension->upper_limit))
+      {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds."); continue;}
+
+    if ( VALID_CVALUE( int64, l->elements[i]) && VALID_CVALUE(uint64, dimension->upper_limit))
+      if ( cmp_unsigned_signed( GET_CVALUE(uint64, dimension->upper_limit), GET_CVALUE( int64, l->elements[i])) < 0 )
+      {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds."); continue;}
+
+    if ( VALID_CVALUE(uint64, l->elements[i]) && VALID_CVALUE(uint64, dimension->upper_limit))
+      if ( GET_CVALUE(uint64, l->elements[i])   >  GET_CVALUE(uint64, dimension->upper_limit))
+      {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds."); continue;}
+      
+    if ( VALID_CVALUE(uint64, l->elements[i]) && VALID_CVALUE( int64, dimension->upper_limit))
+      if ( cmp_unsigned_signed(GET_CVALUE(uint64, l->elements[i]), GET_CVALUE( int64, dimension->upper_limit)) > 0 )
+      {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds."); continue;}
+      
+  }
+}
+
+
+
+
+
+
+
+
+
+/*************************/
+/* B.1 - Common elements */
+/*************************/
+/**********************/
+/* B.1.3 - Data types */
+/**********************/
+/********************************/
+/* B 1.3.3 - Derived data types */
+/********************************/
+
+/*  signed_integer DOTDOT signed_integer */
+/* dimension will be filled in during stage 3 (array_range_check_c) with the number of elements in this subrange */
+// SYM_REF2(subrange_c, lower_limit, upper_limit, unsigned long long int dimension)
+void *array_range_check_c::visit(subrange_c *symbol) {
+	unsigned long long int dimension = 0; // we use unsigned long long instead of uint64_t since it might just happen to be larger than uint64_t in the platform used for compiling this code!!
+
+	/* Determine the size of the array... */
+	if        (VALID_CVALUE( int64, symbol->upper_limit) && VALID_CVALUE( int64, symbol->lower_limit)) {  
+		// do the sums in such a way that no overflow is possible... even during intermediate steps used by compiler!
+		// remember that the result (dimension) is unsigned, while the operands are signed!!
+		// dimension = GET_CVALUE( int64, symbol->upper_limit) - VALID_CVALUE( int64, symbol->lower_limit);
+		if (GET_CVALUE( int64, symbol->lower_limit) >= 0) {
+			dimension = GET_CVALUE( int64, symbol->upper_limit) - GET_CVALUE( int64, symbol->lower_limit);
+		} else {
+			dimension  = -GET_CVALUE( int64, symbol->lower_limit);
+			dimension +=  GET_CVALUE( int64, symbol->upper_limit);     
+		}
+	} else if (VALID_CVALUE(uint64, symbol->upper_limit) && VALID_CVALUE(uint64, symbol->lower_limit)) {
+		dimension = GET_CVALUE(uint64, symbol->upper_limit) - GET_CVALUE(uint64, symbol->lower_limit); 
+	} else if (VALID_CVALUE(uint64, symbol->upper_limit) && VALID_CVALUE( int64, symbol->lower_limit)) {
+		if (GET_CVALUE( int64, symbol->lower_limit) >= 0) {
+			dimension = GET_CVALUE(uint64, symbol->upper_limit) - GET_CVALUE( int64, symbol->lower_limit);
+		} else {
+			unsigned long long int lower_ull;
+			lower_ull  = -GET_CVALUE( int64, symbol->lower_limit);
+			dimension  =  GET_CVALUE(uint64, symbol->upper_limit) + lower_ull;     
+			if (dimension < lower_ull)
+				STAGE3_ERROR(0, symbol, symbol, "Number of elements in array subrange exceeds maximum number of elements (%llu).", std::numeric_limits< unsigned long long int >::max());
+		}
+	} else ERROR;
+
+	/* correct value for dimension is actually ---> dimension = upper_limit - lower_limit + 1
+	 * Up to now, we have only determined dimension = upper_limit - lower_limit
+	 * We must first check whether this last increment will cause an overflow!
+	 */
+	if (dimension == std::numeric_limits< unsigned long long int >::max())
+		STAGE3_ERROR(0, symbol, symbol, "Number of elements in array subrange exceeds maximum number of elements (%llu).", std::numeric_limits< unsigned long long int >::max());
+	
+	/* correct value for dimension is actually ---> dimension = upper_limit - lower_limit + 1 */
+	dimension++; 
+	
+	symbol->dimension = dimension;
+	return NULL;
+}
+
+
+
+
+
+/* integer '(' [array_initial_element] ')' */
+/* array_initial_element may be NULL ! */
+// SYM_REF2(array_initial_elements_c, integer, array_initial_element)
+void *array_range_check_c::visit(array_initial_elements_c *symbol) {
+	if (VALID_CVALUE( int64, symbol->integer) && (GET_CVALUE( int64, symbol->integer) < 0)) 
+		ERROR; /* the IEC 61131-3 syntax guarantees that this value will never be negative! */
+
+	/* TODO: check that the total number of 'initial values' does not exceed the size of the array! */
+
+	return NULL;
+}
+
+
+
+
+
+
+
+
+
+/*********************/
+/* B 1.4 - Variables */
+/*********************/
+/*************************************/
+/* B 1.4.2 - Multi-element variables */
+/*************************************/
+void *array_range_check_c::visit(array_variable_c *symbol) {
+	check_dimension_count(symbol);
+	check_bounds(symbol);
+	return NULL;
+}
+
+
+/**************************************/
+/* B 1.5 - Program organisation units */
+/**************************************/
+/***********************/
+/* B 1.5.1 - Functions */
+/***********************/
+// SYM_REF4(function_declaration_c, derived_function_name, type_name, var_declarations_list, function_body)
+void *array_range_check_c::visit(function_declaration_c *symbol) {
+	symbol->var_declarations_list->accept(*this); // required for visiting subrange_c
+	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
+	// search_var_instance_decl = new search_var_instance_decl_c(symbol);
+	symbol->function_body->accept(*this);
+	delete search_varfb_instance_type;
+	// delete search_var_instance_decl;
+	search_varfb_instance_type = NULL;
+	// search_var_instance_decl = NULL;
+	return NULL;
+}
+
+/*****************************/
+/* B 1.5.2 - Function blocks */
+/*****************************/
+// SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body)
+void *array_range_check_c::visit(function_block_declaration_c *symbol) {
+	symbol->var_declarations->accept(*this); // required for visiting subrange_c
+	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
+	// search_var_instance_decl = new search_var_instance_decl_c(symbol);
+	symbol->fblock_body->accept(*this);
+	delete search_varfb_instance_type;
+	// delete search_var_instance_decl;
+	search_varfb_instance_type = NULL;
+	// search_var_instance_decl = NULL;
+	return NULL;
+}
+
+/**********************/
+/* B 1.5.3 - Programs */
+/**********************/
+// SYM_REF3(program_declaration_c, program_type_name, var_declarations, function_block_body)
+void *array_range_check_c::visit(program_declaration_c *symbol) {
+	symbol->var_declarations->accept(*this); // required for visiting subrange_c
+	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
+	// search_var_instance_decl = new search_var_instance_decl_c(symbol);
+	symbol->function_block_body->accept(*this);
+	delete search_varfb_instance_type;
+	// delete search_var_instance_decl;
+	search_varfb_instance_type = NULL;
+	// search_var_instance_decl = NULL;
+	return NULL;
+}
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/array_range_check.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -0,0 +1,103 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2009-2012  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2012       Manuele Conti  (conti.ma@alice.it)
+ *
+ *
+ *  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)
+ *
+ */
+
+// #include <vector>
+#include "../absyntax_utils/absyntax_utils.hh"
+// #include "datatype_functions.hh"
+
+
+
+class array_range_check_c: public iterator_visitor_c {
+
+  private:
+    search_varfb_instance_type_c *search_varfb_instance_type;
+    // search_var_instance_decl_c *search_var_instance_decl;
+    search_base_type_c search_base_type;
+    int error_count;
+    int current_display_error_level;
+
+    void check_dimension_count(array_variable_c *symbol);
+    void check_bounds(array_variable_c *symbol);
+
+  public:
+    array_range_check_c(symbol_c *ignore);
+    virtual ~array_range_check_c(void);
+    int get_error_count();
+
+    /*************************/
+    /* B.1 - Common elements */
+    /*************************/
+    /**********************/
+    /* B.1.3 - Data types */
+    /**********************/
+    /********************************/
+    /* B 1.3.3 - Derived data types */
+    /********************************/
+    /* NOTE: we may later want to move the following 2 methods to a visitor that will focus on analysing the data type declarations! */
+    void *visit(subrange_c *symbol);
+    void *visit(array_initial_elements_c *symbol);
+  
+    /*********************/
+    /* B 1.4 - Variables */
+    /*********************/
+    /*************************************/
+    /* B 1.4.2 - Multi-element variables */
+    /*************************************/
+    void *visit(array_variable_c *symbol);
+
+    /**************************************/
+    /* B 1.5 - Program organisation units */
+    /**************************************/
+    /***********************/
+    /* B 1.5.1 - Functions */
+    /***********************/
+    void *visit(function_declaration_c *symbol);
+
+    /*****************************/
+    /* B 1.5.2 - Function blocks */
+    /*****************************/
+    void *visit(function_block_declaration_c *symbol);
+
+    /**********************/
+    /* B 1.5.3 - Programs */
+    /**********************/
+    void *visit(program_declaration_c *symbol);
+
+}; /* array_range_check_c */
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/constant_folding.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -0,0 +1,1097 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2003-2011  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2012       Manuele Conti (conti.ma@alice.it)
+ *
+ *  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)
+ *
+ */
+
+
+
+
+
+/* Do constant folding...
+ *
+ * I.e., Determine the value of all expressions in which only constant values (i.e. literals) are used.
+ * The (constant) result of each operation is stored (annotated) in the respective operation symbol 
+ * (e.g.: add_expression_c) in the abstract syntax tree,
+ *
+ * For example:
+ *       2 + 3         -> the constant value '5'    is stored in the add_expression_c symbol.
+ *       22.2 - 5.0    -> the constant value '17.2' is stored in the add_expression_c symbol.
+ *       etc...
+ *
+ *
+ * NOTE 1 
+ *      Some operations and constants can have multiple data types. For example,
+ *        1 AND 0
+ *      may be either a BOOL, BYTE, WORD or LWORD.
+ *
+ *      The same happens with 
+ *        1 + 2
+ *      which may be signed (e.g. INT) or unsigned (UINT)
+ *
+ *      For the above reason, instead of storing a single constant value, we actually store 4:
+ *        - bool
+ *        - uint64
+ *        -  int64
+ *        - real64
+ *
+ *      Additionally, since the result of an operation may result in an overflow, we actually
+ *      store the result inside a struct (defined in absyntax.hh)
+ *
+ *             ** During stage 3 (semantic analysis/checking) we will be doing constant folding.
+ *              * That algorithm will anotate the abstract syntax tree with the result of operations
+ *              * on literals (i.e. 44 + 55 will store the result 99).
+ *              * Since the same source code (e.g. 1 + 0) may actually be a BOOL or an ANY_INT,
+ *              * or an ANY_BIT, we need to handle all possibilities, and determine the result of the
+ *              * operation assuming each type.
+ *              * For this reason, we have one entry for each possible type, with some expressions
+ *              * having more than one entry filled in!
+ *              **
+ *             typedef enum { cs_undefined,   // not defined --> const_value is not valid!
+ *                            cs_const_value, // const value is valid
+ *                            cs_overflow     // result produced overflow or underflow --> const_value is not valid!
+ *                          } const_status_t;
+ *    
+ *             typedef struct {
+ *                 const_status_t status;
+ *                 real64_t       value; 
+ *             } const_value_real64_t;
+ *             const_value_real64_t *const_value_real64; // when NULL --> UNDEFINED
+ *             
+ *             typedef struct {
+ *                 const_status_t status;
+ *                 int64_t        value; 
+ *             } const_value_int64_t;
+ *             const_value_int64_t *const_value_int64; // when NULL --> UNDEFINED
+ *             
+ *             typedef struct {
+ *                 const_status_t status;
+ *                 uint64_t       value; 
+ *             } const_value_uint64_t;
+ *             const_value_uint64_t *const_value_uint64; // when NULL --> UNDEFINED
+ *             
+ *             typedef struct {
+ *                 const_status_t status;
+ *                 bool           value; 
+ *             } const_value_bool_t;
+ *             const_value_bool_t *const_value_bool; // when NULL --> UNDEFINED
+ *
+ *
+ *
+ * NOTE 2 
+ *    This file does not print out any error messages!
+ *    We cannot really print out error messages when we find an overflow. Since each operation
+ *    (symbol in the absract syntax tree for that operation) will have up to 4 constant results,
+ *    it may happen that some of them overflow, while other do not.
+ *    We must wait for data type checking to determine the exact data type of each expression
+ *    before we can decide whether or not we should print out an overflow error message.
+ *
+ *    For this reason, this visitor merely annotates the abstract syntax tree, and leaves the
+ *    actuall printing of errors for the print_datatype_errors_c class!
+ */
+
+#include "constant_folding.hh"
+#include <stdlib.h> /* required for malloc() */
+
+#include <string.h>  /* required for strlen() */
+// #include <stdlib.h>  /* required for atoi() */
+#include <errno.h>   /* required for errno */
+
+#include "../main.hh" // required for uint8_t, real_64_t, ..., and the macros NAN, INFINITY, INT8_MAX, REAL32_MAX, ... */
+
+
+
+
+
+
+#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;                                                                                                   \
+}
+
+
+
+
+
+
+
+
+
+
+
+
+#define SET_CVALUE(dtype, symbol, new_value)  ((symbol)->const_value._##dtype.value) = new_value; ((symbol)->const_value._##dtype.status) = symbol_c::cs_const_value;
+#define GET_CVALUE(dtype, symbol)             ((symbol)->const_value._##dtype.value)
+#define SET_OVFLOW(dtype, symbol)             ((symbol)->const_value._##dtype.status) = symbol_c::cs_overflow
+#define SET_NONCONST(dtype, symbol)           ((symbol)->const_value._##dtype.status) = symbol_c::cs_non_const
+
+#define VALID_CVALUE(dtype, symbol)           (symbol_c::cs_const_value == (symbol)->const_value._##dtype.status)
+#define ISZERO_CVALUE(dtype, symbol)          ((VALID_CVALUE(dtype, symbol)) && (GET_CVALUE(dtype, symbol) == 0))
+
+#define ISEQUAL_CVALUE(dtype, symbol1, symbol2) \
+	(VALID_CVALUE(dtype, symbol1) && VALID_CVALUE(dtype, symbol2) && (GET_CVALUE(dtype, symbol1) == GET_CVALUE(dtype, symbol2))) 
+
+#define DO_BINARY_OPER(dtype, oper, otype)\
+	if (VALID_CVALUE(dtype, symbol->r_exp) && VALID_CVALUE(dtype, symbol->l_exp)) {                                \
+		SET_CVALUE(otype, symbol, GET_CVALUE(dtype, symbol->l_exp) oper GET_CVALUE(dtype, symbol->r_exp));     \
+	}
+
+#define DO_BINARY_OPER_(oper_type, operation, res_type, operand1, operand2)\
+	if (VALID_CVALUE(oper_type, operand1) && VALID_CVALUE(oper_type, operand2)) {                                     \
+		SET_CVALUE(res_type, symbol, GET_CVALUE(oper_type, operand1) operation GET_CVALUE(oper_type, operand2));  \
+	}
+
+#define DO_UNARY_OPER(dtype, operation, operand)\
+	if (VALID_CVALUE(dtype, operand)) {                                                                               \
+		SET_CVALUE(dtype, symbol, operation GET_CVALUE(dtype, operand));                                          \
+	}
+
+
+
+
+
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+/***            convert string to numerical value                    ***/
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+
+
+
+  /* To allow the compiler to be portable, we cannot assume that int64_t is mapped onto long long int,
+   * so we cannot call strtoll() and strtoull() in extract_int64() and extract_uint64().
+   *
+   * So, we create our own strtouint64() and strtoint64() functions.
+   * (We actually call them matiec_strtoint64() so they will not clash with any function
+   *  that may be added to the standard library in the future).
+   * We actually create several of each, and let the compiler choose which is the correct one,
+   * by having it resolve the call to the overloaded function. For the C++ compiler to be able
+   * to resolve this ambiguity, we need to add a dummy parameter to each function!
+   *
+   * TODO: support platforms in which int64_t is mapped onto int !! Is this really needed?
+   */
+static  int64_t matiec_strtoint64 (         long      int *dummy, const char *nptr, char **endptr, int base) {return strtol  (nptr, endptr, base);}
+static  int64_t matiec_strtoint64 (         long long int *dummy, const char *nptr, char **endptr, int base) {return strtoll (nptr, endptr, base);}
+  
+static uint64_t matiec_strtouint64(unsigned long      int *dummy, const char *nptr, char **endptr, int base) {return strtoul (nptr, endptr, base);}
+static uint64_t matiec_strtouint64(unsigned long long int *dummy, const char *nptr, char **endptr, int base) {return strtoull(nptr, endptr, base);}
+
+
+/* extract the value of an integer from an integer_c object !! */
+/* NOTE: it must ignore underscores! */
+/* NOTE: To follow the basic structure used throughout the compiler's code, we should really be
+ * writing this as a visitor_c (and do away with the dynamic casts!), but since we only have 3 distinct 
+ * symbol class types to handle, it is probably easier to read if we write it as a standard function... 
+ */
+int64_t extract_int64_value(symbol_c *sym, bool *overflow) {
+  int64_t      ret;
+  std::string  str = "";
+  char        *endptr;
+  const char  *value;
+  int          base;
+  integer_c         *integer;
+  hex_integer_c     *hex_integer;
+  octal_integer_c   *octal_integer;
+  binary_integer_c  *binary_integer;
+
+   if       ((integer        = dynamic_cast<integer_c *>(sym))        != NULL) {value = integer       ->value + 0; base = 10;}
+   else  if ((hex_integer    = dynamic_cast<hex_integer_c *>(sym))    != NULL) {value = hex_integer   ->value + 3; base = 16;}
+   else  if ((octal_integer  = dynamic_cast<octal_integer_c *>(sym))  != NULL) {value = octal_integer ->value + 2; base =  8;}
+   else  if ((binary_integer = dynamic_cast<binary_integer_c *>(sym)) != NULL) {value = binary_integer->value + 2; base =  2;}
+   else  ERROR;
+
+  for(unsigned int i = 0; i < strlen(value); i++)
+    if (value[i] != '_')  str += value[i];
+
+  errno = 0; // since strtoXX() may legally return 0, we must set errno to 0 to detect errors correctly!
+  ret = matiec_strtoint64((int64_t *)NULL, str.c_str(), &endptr, base);
+  if (overflow != NULL)
+    *overflow = (errno == ERANGE);
+  if (((errno != 0) && (errno != ERANGE)) || (*endptr != '\0'))
+    ERROR;
+
+  return ret;
+}
+
+
+
+uint64_t extract_uint64_value(symbol_c *sym, bool *overflow) {
+  uint64_t     ret;
+  std::string  str = "";
+  char        *endptr;
+  const char  *value;
+  int          base;
+  integer_c         *integer;
+  hex_integer_c     *hex_integer;
+  octal_integer_c   *octal_integer;
+  binary_integer_c  *binary_integer;
+
+   if       ((integer        = dynamic_cast<integer_c *>(sym))        != NULL) {value = integer       ->value + 0; base = 10;}
+   else  if ((hex_integer    = dynamic_cast<hex_integer_c *>(sym))    != NULL) {value = hex_integer   ->value + 3; base = 16;}
+   else  if ((octal_integer  = dynamic_cast<octal_integer_c *>(sym))  != NULL) {value = octal_integer ->value + 2; base =  8;}
+   else  if ((binary_integer = dynamic_cast<binary_integer_c *>(sym)) != NULL) {value = binary_integer->value + 2; base =  2;}
+   else  ERROR;
+
+  for(unsigned int i = 0; i < strlen(value); i++)
+    if (value[i] != '_')  str += value[i];
+
+  errno = 0; // since strtoXX() may legally return 0, we must set errno to 0 to detect errors correctly!
+  ret = matiec_strtouint64((uint64_t *)NULL, str.c_str(), &endptr, base);
+  if (overflow != NULL)
+    *overflow = (errno == ERANGE);
+  if (((errno != 0) && (errno != ERANGE)) || (*endptr != '\0'))
+    ERROR;
+
+  return ret;
+}
+
+
+
+/* extract the value of a real from an real_c object !! */
+/* NOTE: it must ignore underscores! */
+/* From iec_bison.yy
+ *  real:
+ *   real_token		{$$ = new real_c($1, locloc(@$));}
+ * | fixed_point_token	{$$ = new real_c($1, locloc(@$));}
+ *
+ * From iec_flex.ll
+ * {real}			{yylval.ID=strdup(yytext); return real_token;}
+ * {fixed_point}		{yylval.ID=strdup(yytext); return fixed_point_token;}
+ *
+ * real		{integer}\.{integer}{exponent}
+ * fixed_point		{integer}\.{integer}
+ * exponent        [Ee]([+-]?){integer}
+ * integer         {digit}((_?{digit})*)
+ */
+real64_t extract_real_value(symbol_c *sym, bool *overflow) {
+  std::string str = "";
+  real_c *real_sym;
+  char   *endptr;
+  real64_t ret;
+
+  if ((real_sym = dynamic_cast<real_c *>(sym)) == NULL) ERROR;
+  for(unsigned int i = 0; i < strlen(real_sym->value); i++)
+    if (real_sym->value[i] != '_') str += real_sym->value[i];
+    
+  errno = 0; // since strtoXX() may legally return 0, we must set errno to 0 to detect errors correctly!
+  #if    (real64_t  == float)
+    ret = strtof(str.c_str(),  &endptr);
+  #elif  (real64_t  == double)
+    ret = strtod(str.c_str(),  &endptr);
+  #elif  (real64_t  == long_double)
+    ret = strtold(str.c_str(), &endptr);
+  #else 
+    #error Could not determine which data type is being used for real64_t (defined in absyntax.hh). Aborting!
+  #endif
+  if (overflow != NULL)
+    *overflow = (errno == ERANGE);
+  if (((errno != 0) && (errno != ERANGE)) || (*endptr != '\0'))
+    ERROR;
+
+  return ret;
+}
+
+
+
+
+
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+/***        Functions to check for overflow situation                ***/
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+
+
+/* NOTE:
+ *   Most of the conditions to detect overflows on signed and unsigned integer operations were adapted from
+ *   https://www.securecoding.cert.org/confluence/display/seccode/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow?showComments=false
+ *   https://www.securecoding.cert.org/confluence/display/seccode/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap
+ */
+
+/* NOTE: If at all possible, all overflow tests are done by pre-condition tests, i.e. tests that 
+ *       can be run _before_ the operation is executed, and therefore without accessing the result!
+ *
+ *       The exception is for real/floating point values, that simply test if the result is NaN (not a number).
+ */
+
+/* res = a + b */
+static void CHECK_OVERFLOW_uint64_SUM(symbol_c *res, symbol_c *a, symbol_c *b) {
+	if (!VALID_CVALUE(uint64, res))
+		return;
+	/* Test by post-condition: If sum is smaller than either operand => overflow! */
+	// if (GET_CVALUE(uint64, res) < GET_CVALUE(uint64, a))
+	/* Test by pre-condition: If (UINT64_MAX - a) < b => overflow! */
+	if ((UINT64_MAX - GET_CVALUE(uint64, a)) < GET_CVALUE(uint64, b))
+		SET_OVFLOW(uint64, res);
+}
+
+
+/* res = a - b */
+static void CHECK_OVERFLOW_uint64_SUB(symbol_c *res, symbol_c *a, symbol_c *b) {
+	if (!VALID_CVALUE(uint64, res))
+		return;
+	/* Test by post-condition: If diference is larger than a => overflow! */
+	// if (GET_CVALUE(uint64, res) > GET_CVALUE(uint64, a))
+	/* Test by pre-condition: if b > a => overflow! */
+	if (GET_CVALUE(uint64, b) > GET_CVALUE(uint64, a))
+		SET_OVFLOW(uint64, res);
+}
+
+
+/* res = a * b */
+static void CHECK_OVERFLOW_uint64_MUL(symbol_c *res, symbol_c *a, symbol_c *b) {
+	if (!VALID_CVALUE(uint64, res))
+		return;
+	/* Test by pre-condition: If (UINT64_MAX / a) < b => overflow! */
+	if ((UINT64_MAX / GET_CVALUE(uint64, a)) < GET_CVALUE(uint64, b))
+		SET_OVFLOW(uint64, res);
+}
+
+
+/* res = a / b */
+static void CHECK_OVERFLOW_uint64_DIV(symbol_c *res, symbol_c *a, symbol_c *b) {
+	if (!VALID_CVALUE(uint64, res))
+		return;
+	if (GET_CVALUE(uint64, b) == 0) /* division by zero! */
+		SET_OVFLOW(uint64, res);
+}
+
+
+/* res = a MOD b */
+static void CHECK_OVERFLOW_uint64_MOD(symbol_c *res, symbol_c *a, symbol_c *b) {
+	if (!VALID_CVALUE(uint64, res))
+		return;
+	/* no overflow condition exists, including division by zero, which IEC 61131-3 considers legal for MOD operation! */
+	if (false) 
+		SET_OVFLOW(uint64, res);
+}
+
+
+/* res = a + b */
+static void CHECK_OVERFLOW_int64_SUM(symbol_c *res, symbol_c *a_ptr, symbol_c *b_ptr) {
+	if (!VALID_CVALUE(int64, res))
+		return;
+	int64_t a = GET_CVALUE(int64, a_ptr);
+	int64_t b = GET_CVALUE(int64, b_ptr);
+	/* The following test is valid no matter what representation is being used (e.g. two's complement, etc...) */
+	if (((b > 0) && (a > (INT64_MAX - b)))
+	 || ((b < 0) && (a < (INT64_MIN - b))))
+		SET_OVFLOW(int64, res);
+}
+
+
+/* res = a - b */
+static void CHECK_OVERFLOW_int64_SUB(symbol_c *res, symbol_c *a_ptr, symbol_c *b_ptr) {
+	if (!VALID_CVALUE(int64, res))
+		return;
+	int64_t a = GET_CVALUE(int64, a_ptr);
+	int64_t b = GET_CVALUE(int64, b_ptr);
+	/* The following test is valid no matter what representation is being used (e.g. two's complement, etc...) */
+	if (((b > 0) && (a < (INT64_MIN + b)))
+	 || ((b < 0) && (a > (INT64_MAX + b))))
+		SET_OVFLOW(int64, res);
+}
+
+
+/* res = a * b */
+static void CHECK_OVERFLOW_int64_MUL(symbol_c *res, symbol_c *a_ptr, symbol_c *b_ptr) {
+	if (!VALID_CVALUE(int64, res))
+		return;
+	int64_t a = GET_CVALUE(int64, a_ptr);
+	int64_t b = GET_CVALUE(int64, b_ptr);
+	if (   ( (a > 0) &&  (b > 0) &&             (a > (INT64_MAX / b))) 
+	    || ( (a > 0) && !(b > 0) &&             (b < (INT64_MIN / a))) 
+	    || (!(a > 0) &&  (b > 0) &&             (a < (INT64_MIN / b))) 
+	    || (!(a > 0) && !(b > 0) && (a != 0) && (b < (INT64_MAX / a))))
+		SET_OVFLOW(int64, res);
+}
+
+
+/* res = a / b */
+static void CHECK_OVERFLOW_int64_DIV(symbol_c *res, symbol_c *a_ptr, symbol_c *b_ptr) {
+	if (!VALID_CVALUE(int64, res))
+		return;
+	int64_t a = GET_CVALUE(int64, a_ptr);
+	int64_t b = GET_CVALUE(int64, b_ptr);
+	if ((b == 0) || ((a == INT64_MIN) && (b == -1)))
+		SET_OVFLOW(int64, res);
+}
+
+
+/* res = a MOD b */
+static void CHECK_OVERFLOW_int64_MOD(symbol_c *res, symbol_c *a_ptr, symbol_c *b_ptr) {
+	if (!VALID_CVALUE(int64, res))
+		return;
+	int64_t a = GET_CVALUE(int64, a_ptr);
+	int64_t b = GET_CVALUE(int64, b_ptr);
+	/* IEC 61131-3 standard says IN1 MOD IN2 must be equivalent to
+	 *  IF (IN2 = 0) THEN OUT:=0 ; ELSE OUT:=IN1 - (IN1/IN2)*IN2 ; END_IF
+	 *
+	 * Note that, when IN1 = INT64_MIN, and IN2 = -1, an overflow occurs in the division,
+	 * so although the MOD operation should be OK, acording to the above definition, we actually have an overflow!!
+	 *
+	 * On the other hand, division by 0 is OK!!
+	 */
+	if ((a == INT64_MIN) && (b == -1))
+		SET_OVFLOW(int64, res);
+}
+
+
+/* res = - a */
+static void CHECK_OVERFLOW_int64_NEG(symbol_c *res, symbol_c *a_ptr) {
+	if (!VALID_CVALUE(int64, res))
+		return;
+	int64_t a = GET_CVALUE(int64, a_ptr);
+	if (a == INT64_MIN)
+		SET_OVFLOW(int64, res);
+}
+
+
+
+static void CHECK_OVERFLOW_real64(symbol_c *res_ptr) {
+	if (!VALID_CVALUE(real64, res_ptr))
+		return;
+	real64_t res = GET_CVALUE(real64, res_ptr);
+	/* NaN => underflow, overflow, number is a higher precision format, is a complex number (IEEE standard) */
+	/* The IEC 61131-3 clearly states in section '2.5.1.5.2 Numerical functions':
+	 * "It is an error if the result of evaluation of one of these [numerical] functions exceeds the range of values
+	 *  specified for the data type of the function output, or if division by zero is attempted."
+	 * For this reason, any operation that has as a result a positive or negative inifinity, is also an error!
+	 */
+	if ((isnan(res)) || (res == INFINITY) || (res == -INFINITY))
+		SET_OVFLOW(real64, res_ptr);
+}
+
+
+
+
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+/***        Functions to execute operations on the const values      ***/
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+
+/* static void *handle_cmp(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2, OPERATION) */
+#define handle_cmp(symbol, oper1, oper2, operation) {               \
+	if ((NULL == oper1) || (NULL == oper2)) return NULL;        \
+	DO_BINARY_OPER_(  bool, operation, bool, oper1, oper2);     \
+	DO_BINARY_OPER_(uint64, operation, bool, oper1, oper2);     \
+	DO_BINARY_OPER_( int64, operation, bool, oper1, oper2);     \
+	DO_BINARY_OPER_(real64, operation, bool, oper1, oper2);     \
+	return NULL;                                                \
+}
+
+
+/* NOTE: the MOVE standard function is equivalent to the ':=' in ST syntax */
+static void *handle_move(symbol_c *to, symbol_c *from) {
+	if (NULL == from) return NULL;
+	to->const_value = from->const_value;
+	return NULL;
+}
+
+
+/* unary negation (multiply by -1) */
+static void *handle_neg(symbol_c *symbol, symbol_c *oper) {
+	DO_UNARY_OPER( int64, -, oper);	CHECK_OVERFLOW_int64_NEG(symbol, oper);
+	DO_UNARY_OPER(real64, -, oper);	CHECK_OVERFLOW_real64(symbol);
+	return NULL;
+}
+
+
+/* unary boolean negation (NOT) */
+static void *handle_not(symbol_c *symbol, symbol_c *oper) {
+	if (NULL == oper) return NULL;
+	DO_UNARY_OPER(  bool, !, oper);
+	DO_UNARY_OPER(uint64, ~, oper);
+	return NULL;
+}
+
+
+static void *handle_or (symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
+	if ((NULL == oper1) || (NULL == oper2)) return NULL;
+	DO_BINARY_OPER_(  bool, ||, bool  , oper1, oper2);
+	DO_BINARY_OPER_(uint64, | , uint64, oper1, oper2);
+	return NULL;
+}
+
+
+static void *handle_xor(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
+	if ((NULL == oper1) || (NULL == oper2)) return NULL;
+	DO_BINARY_OPER_(  bool, ^, bool  , oper1, oper2);
+	DO_BINARY_OPER_(uint64, ^, uint64, oper1, oper2);
+	return NULL;
+}
+
+
+static void *handle_and(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
+	if ((NULL == oper1) || (NULL == oper2)) return NULL;
+	DO_BINARY_OPER_(  bool, &&, bool, oper1, oper2);
+	DO_BINARY_OPER_(uint64, & , uint64, oper1, oper2);
+	return NULL;
+}
+
+
+static void *handle_add(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
+	if ((NULL == oper1) || (NULL == oper2)) return NULL;
+	DO_BINARY_OPER_(uint64, +, uint64, oper1, oper2);   CHECK_OVERFLOW_uint64_SUM(symbol, oper1, oper2);
+	DO_BINARY_OPER_( int64, +,  int64, oper1, oper2);   CHECK_OVERFLOW_int64_SUM (symbol, oper1, oper2);
+	DO_BINARY_OPER_(real64, +, real64, oper1, oper2);   CHECK_OVERFLOW_real64    (symbol);
+	return NULL;
+}
+
+
+static void *handle_sub(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
+	if ((NULL == oper1) || (NULL == oper2)) return NULL;
+	DO_BINARY_OPER_(uint64, -, uint64, oper1, oper2);   CHECK_OVERFLOW_uint64_SUB(symbol, oper1, oper2);
+	DO_BINARY_OPER_( int64, -,  int64, oper1, oper2);   CHECK_OVERFLOW_int64_SUB (symbol, oper1, oper2);
+	DO_BINARY_OPER_(real64, -, real64, oper1, oper2);   CHECK_OVERFLOW_real64    (symbol);
+	return NULL;
+}
+
+
+static void *handle_mul(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
+	if ((NULL == oper1) || (NULL == oper2)) return NULL;
+	DO_BINARY_OPER_(uint64, *, uint64, oper1, oper2);   CHECK_OVERFLOW_uint64_MUL(symbol, oper1, oper2);
+	DO_BINARY_OPER_( int64, *,  int64, oper1, oper2);   CHECK_OVERFLOW_int64_MUL (symbol, oper1, oper2);
+	DO_BINARY_OPER_(real64, *, real64, oper1, oper2);   CHECK_OVERFLOW_real64    (symbol);
+	return NULL;
+}
+
+
+static void *handle_div(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
+	if ((NULL == oper1) || (NULL == oper2)) return NULL;
+	if (ISZERO_CVALUE(uint64, oper2))  {SET_OVFLOW(uint64, symbol);} else {DO_BINARY_OPER_(uint64, /, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_DIV(symbol, oper1, oper2);};
+	if (ISZERO_CVALUE( int64, oper2))  {SET_OVFLOW( int64, symbol);} else {DO_BINARY_OPER_( int64, /,  int64, oper1, oper2); CHECK_OVERFLOW_int64_DIV (symbol, oper1, oper2);};
+	if (ISZERO_CVALUE(real64, oper2))  {SET_OVFLOW(real64, symbol);} else {DO_BINARY_OPER_(real64, /, real64, oper1, oper2); CHECK_OVERFLOW_real64(symbol);};
+	return NULL;
+}
+
+
+static void *handle_mod(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
+	if ((NULL == oper1) || (NULL == oper2)) return NULL;
+	/* IEC 61131-3 standard says IN1 MOD IN2 must be equivalent to
+	 *  IF (IN2 = 0) THEN OUT:=0 ; ELSE OUT:=IN1 - (IN1/IN2)*IN2 ; END_IF
+	 *
+	 * Note that, when IN1 = INT64_MIN, and IN2 = -1, an overflow occurs in the division,
+	 * so although the MOD operation should be OK, acording to the above definition, we actually have an overflow!!
+	 */
+	if (ISZERO_CVALUE(uint64, oper2))  {SET_CVALUE(uint64, symbol, 0);} else {DO_BINARY_OPER_(uint64, %, uint64, oper1, oper2); CHECK_OVERFLOW_uint64_MOD(symbol, oper1, oper2);};
+	if (ISZERO_CVALUE( int64, oper2))  {SET_CVALUE( int64, symbol, 0);} else {DO_BINARY_OPER_( int64, %,  int64, oper1, oper2); CHECK_OVERFLOW_int64_MOD (symbol, oper1, oper2);};
+	return NULL;
+}
+
+
+static void *handle_pow(symbol_c *symbol, symbol_c *oper1, symbol_c *oper2) {
+	/* NOTE: If the const_value in symbol->r_exp is within the limits of both int64 and uint64, then we do both operations.
+	 *       That is OK, as the result should be identicial (we do create an unnecessary CVALUE variable, but who cares?).
+	 *       If only one is valid, then that is the oper we will do!
+	 */
+	if (VALID_CVALUE(real64, oper1) && VALID_CVALUE( int64, oper2))
+		SET_CVALUE(real64, symbol, pow(GET_CVALUE(real64, oper1), GET_CVALUE( int64, oper2)));
+	if (VALID_CVALUE(real64, oper1) && VALID_CVALUE(uint64, oper2))
+		SET_CVALUE(real64, symbol, pow(GET_CVALUE(real64, oper1), GET_CVALUE(uint64, oper2)));
+	CHECK_OVERFLOW_real64(symbol);
+	return NULL;
+}
+
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+/***        Helper functions for handling IL instruction lists.      ***/
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+
+
+/* If the cvalues of all the prev_il_intructions have the same VALID value, then set the local cvalue to that value, otherwise, set it to NONCONST! */
+#define intersect_prev_CVALUE_(dtype, symbol) {                                                                   \
+	symbol->const_value._##dtype = symbol->prev_il_instruction[0]->const_value._##dtype;                      \
+	for (unsigned int i = 1; i < symbol->prev_il_instruction.size(); i++) {                                   \
+		if (!ISEQUAL_CVALUE(dtype, symbol, symbol->prev_il_instruction[i]))                               \
+			{SET_NONCONST(dtype, symbol); break;}                                                     \
+	}                                                                                                         \
+}
+
+static void intersect_prev_cvalues(il_instruction_c *symbol) {
+	if (symbol->prev_il_instruction.empty())
+		return;
+	intersect_prev_CVALUE_(real64, symbol);
+	intersect_prev_CVALUE_(uint64, symbol);
+	intersect_prev_CVALUE_( int64, symbol);
+	intersect_prev_CVALUE_(  bool, symbol);
+}
+
+
+
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+/***        The constant_folding_c                                   ***/
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+
+
+
+
+
+
+constant_folding_c::constant_folding_c(symbol_c *symbol) {
+    error_count = 0;
+    warning_found = false;
+    current_display_error_level = 0;
+    
+    /* check whether the platform on which the compiler is being run implements IEC 559 floating point data types. */
+    symbol_c null_symbol;
+    if (! (std::numeric_limits<real64_t>::is_iec559) )
+        STAGE3_WARNING(&null_symbol, &null_symbol, "The platform running the compiler does not implement IEC 60559 floating point numbers. "
+                                                   "Any error and/or warning messages related to overflow/underflow of the result of operations on REAL/LREAL literals "
+                                                   "(i.e. constant folding) may themselves be erroneous, although are most probably correct."
+                                                   "However, more likely is the possible existance of overflow/underflow errors that are not detected.");
+}
+
+
+constant_folding_c::~constant_folding_c(void) {
+}
+
+
+int constant_folding_c::get_error_count() {
+	return error_count;
+}
+
+
+/*********************/
+/* B 1.2 - Constants */
+/*********************/
+/******************************/
+/* B 1.2.1 - Numeric Literals */
+/******************************/
+void *constant_folding_c::visit(real_c *symbol) {
+	bool overflow;
+	SET_CVALUE(real64, symbol, extract_real_value(symbol, &overflow));
+	if (overflow) SET_OVFLOW(real64, symbol);
+	return NULL;
+}
+
+
+void *constant_folding_c::visit(integer_c *symbol) {
+	bool overflow;
+	SET_CVALUE( int64, symbol, extract_int64_value (symbol, &overflow));
+	if (overflow) SET_OVFLOW(int64, symbol);
+	SET_CVALUE(uint64, symbol, extract_uint64_value(symbol, &overflow));
+	if (overflow) SET_OVFLOW(uint64, symbol);
+	return NULL;
+}
+
+
+void *constant_folding_c::visit(neg_real_c *symbol) {
+	symbol->exp->accept(*this);
+	DO_UNARY_OPER(real64, -, symbol->exp);
+	CHECK_OVERFLOW_real64(symbol);
+	return NULL;
+}
+
+/* | '-' integer	{$$ = new neg_integer_c($2, locloc(@$));} */
+void *constant_folding_c::visit(neg_integer_c *symbol) {
+	symbol->exp->accept(*this);
+	DO_UNARY_OPER(int64, -, symbol->exp);
+	CHECK_OVERFLOW_int64_NEG(symbol, symbol->exp);
+	/* NOTE 1: INT64_MIN = -(INT64_MAX + 1)   ---> assuming two's complement representation!!!
+	 * NOTE 2: if the user happens to want INT_MIN, that value will first be parsed as a positive integer, before being negated here.
+	 * However, the positive value cannot be stored inside an int64! So, in this case, we will get the value from the uint64 cvalue.
+	 */
+	// if (INT64_MIN == -INT64_MAX - 1) // We do not really need to check that the platform uses two's complement
+	if (VALID_CVALUE(uint64, symbol->exp) && (GET_CVALUE(uint64, symbol->exp) == (uint64_t)INT64_MAX+1)) {
+		SET_CVALUE(int64, symbol, INT64_MIN);
+	}
+	return NULL;
+}
+
+
+void *constant_folding_c::visit(binary_integer_c *symbol) {
+	bool overflow;
+	SET_CVALUE( int64, symbol, extract_int64_value (symbol, &overflow));
+	if (overflow) SET_OVFLOW(int64, symbol);
+	SET_CVALUE(uint64, symbol, extract_uint64_value(symbol, &overflow));
+	if (overflow) SET_OVFLOW(uint64, symbol);
+	return NULL;
+}
+
+
+void *constant_folding_c::visit(octal_integer_c *symbol) {
+	bool overflow;
+	SET_CVALUE( int64, symbol, extract_int64_value (symbol, &overflow));
+	if (overflow) SET_OVFLOW(int64, symbol);
+	SET_CVALUE(uint64, symbol, extract_uint64_value(symbol, &overflow));
+	if (overflow) SET_OVFLOW(uint64, symbol);
+	return NULL;
+}
+
+
+void *constant_folding_c::visit(hex_integer_c *symbol) {
+	bool overflow;
+	SET_CVALUE( int64, symbol, extract_int64_value (symbol, &overflow));
+	if (overflow) SET_OVFLOW(int64, symbol);
+	SET_CVALUE(uint64, symbol, extract_uint64_value(symbol, &overflow));
+	if (overflow) SET_OVFLOW(uint64, symbol);
+	return NULL;
+}
+
+
+/*
+integer_literal:
+  integer_type_name '#' signed_integer	{$$ = new integer_literal_c($1, $3, locloc(@$));}
+| integer_type_name '#' binary_integer	{$$ = new integer_literal_c($1, $3, locloc(@$));}
+| integer_type_name '#' octal_integer	{$$ = new integer_literal_c($1, $3, locloc(@$));}
+| integer_type_name '#' hex_integer	{$$ = new integer_literal_c($1, $3, locloc(@$));}
+*/
+// SYM_REF2(integer_literal_c, type, value)
+void *constant_folding_c::visit(integer_literal_c *symbol) {
+	symbol->value->accept(*this);
+	DO_UNARY_OPER( int64, /* none */, symbol->value);
+	DO_UNARY_OPER(uint64, /* none */, symbol->value);
+	return NULL;
+}
+
+
+void *constant_folding_c::visit(real_literal_c *symbol) {
+	symbol->value->accept(*this);
+	DO_UNARY_OPER(real64, /* none */, symbol->value);
+	return NULL;
+}
+
+
+void *constant_folding_c::visit(bit_string_literal_c *symbol) {
+	return NULL;
+}
+
+
+void *constant_folding_c::visit(boolean_literal_c *symbol) {
+	symbol->value->accept(*this);
+	DO_UNARY_OPER(bool, /* none */, symbol->value);
+	return NULL;
+}
+
+
+void *constant_folding_c::visit(boolean_true_c *symbol) {
+	SET_CVALUE(bool, symbol, true);
+	return NULL;
+}
+
+
+void *constant_folding_c::visit(boolean_false_c *symbol) {
+	SET_CVALUE(bool, symbol, false);
+	return NULL;
+}
+
+
+
+
+
+/****************************************/
+/* B.2 - Language IL (Instruction List) */
+/****************************************/
+/***********************************/
+/* B 2.1 Instructions and Operands */
+/***********************************/
+/* Not needed, since we inherit from iterator_visitor_c */
+/*| instruction_list il_instruction */
+// SYM_LIST(instruction_list_c)
+// void *constant_folding_c::visit(instruction_list_c *symbol) {}
+
+/* | label ':' [il_incomplete_instruction] eol_list */
+// SYM_REF2(il_instruction_c, label, il_instruction)
+// void *visit(instruction_list_c *symbol);
+void *constant_folding_c::visit(il_instruction_c *symbol) {
+	if (NULL == symbol->il_instruction) {
+		/* This empty/null il_instruction does not change the value of the current/default IL variable.
+		 * So it inherits the candidate_datatypes from it's previous IL instructions!
+		 */
+		intersect_prev_cvalues(symbol);
+	} else {
+		il_instruction_c fake_prev_il_instruction = *symbol;
+		intersect_prev_cvalues(&fake_prev_il_instruction);
+
+		if (symbol->prev_il_instruction.size() == 0)  prev_il_instruction = NULL;
+		else                                          prev_il_instruction = &fake_prev_il_instruction;
+		symbol->il_instruction->accept(*this);
+		prev_il_instruction = NULL;
+
+		/* This object has (inherits) the same cvalues as the il_instruction */
+		symbol->const_value = symbol->il_instruction->const_value;
+	}
+
+	return NULL;
+}
+
+
+void *constant_folding_c::visit(il_simple_operation_c *symbol) {
+	/* determine the cvalue of the operand */
+	if (NULL != symbol->il_operand) {
+		symbol->il_operand->accept(*this);
+	}
+	/* determine the cvalue resulting from executing the il_operator... */
+	il_operand = symbol->il_operand;
+	symbol->il_simple_operator->accept(*this);
+	il_operand = NULL;
+	/* This object has (inherits) the same cvalues as the il_instruction */
+	symbol->const_value = symbol->il_simple_operator->const_value;
+	return NULL;
+}
+
+
+/* TODO: handle function invocations... */
+/* | function_name [il_operand_list] */
+/* NOTE: The parameters 'called_function_declaration' and 'extensible_param_count' are used to pass data between the stage 3 and stage 4. */
+// SYM_REF2(il_function_call_c, function_name, il_operand_list, symbol_c *called_function_declaration; int extensible_param_count;)
+// void *constant_folding_c::visit(il_function_call_c *symbol) {}
+
+
+/* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */
+// SYM_REF3(il_expression_c, il_expr_operator, il_operand, simple_instr_list);
+void *constant_folding_c::visit(il_expression_c *symbol) {
+  symbol_c *prev_il_instruction_backup = prev_il_instruction;
+  
+  if (NULL != symbol->il_operand)
+    symbol->il_operand->accept(*this);
+
+  if(symbol->simple_instr_list != NULL)
+    symbol->simple_instr_list->accept(*this);
+
+  /* Now do the operation,  */
+  il_operand = symbol->simple_instr_list;
+  prev_il_instruction = prev_il_instruction_backup;
+  symbol->il_expr_operator->accept(*this);
+  il_operand = NULL;
+  
+  /* This object has (inherits) the same cvalues as the il_instruction */
+  symbol->const_value = symbol->il_expr_operator->const_value;
+  return NULL;
+}
+
+
+
+void *constant_folding_c::visit(il_jump_operation_c *symbol) {
+  /* recursive call to fill const values... */
+  il_operand = NULL;
+  symbol->il_jump_operator->accept(*this);
+  il_operand = NULL;
+  /* This object has (inherits) the same cvalues as the il_jump_operator */
+  symbol->const_value = symbol->il_jump_operator->const_value;
+  return NULL;
+}
+
+
+
+/* FB calls leave the value in the accumulator unchanged */
+/*   il_call_operator prev_declared_fb_name
+ * | il_call_operator prev_declared_fb_name '(' ')'
+ * | il_call_operator prev_declared_fb_name '(' eol_list ')'
+ * | il_call_operator prev_declared_fb_name '(' il_operand_list ')'
+ * | il_call_operator prev_declared_fb_name '(' eol_list il_param_list ')'
+ */
+/* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 (although currently it is not used in stage 4 */
+// SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration)
+void *constant_folding_c::visit(il_fb_call_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+
+
+/* TODO: handle function invocations... */
+/* | function_name '(' eol_list [il_param_list] ')' */
+/* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. */
+// SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;)
+// void *constant_folding_c::visit(il_formal_funct_call_c *symbol) {return NULL;}
+
+
+
+/* Not needed, since we inherit from iterator_visitor_c */
+//  void *constant_folding_c::visit(il_operand_list_c *symbol);
+
+
+
+/* | simple_instr_list il_simple_instruction */
+/* This object is referenced by il_expression_c objects */
+void *constant_folding_c::visit(simple_instr_list_c *symbol) {
+  if (symbol->n <= 0)
+    return NULL;  /* List is empty! Nothing to do. */
+    
+  for(int i = 0; i < symbol->n; i++)
+    symbol->elements[i]->accept(*this);
+
+  /* This object has (inherits) the same cvalues as the il_jump_operator */
+  symbol->const_value = symbol->elements[symbol->n-1]->const_value;
+  return NULL;
+}
+
+
+
+// SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;)
+void *constant_folding_c::visit(il_simple_instruction_c *symbol) {
+  if (symbol->prev_il_instruction.size() > 1) ERROR; /* There should be no labeled insructions inside an IL expression! */
+  if (symbol->prev_il_instruction.size() == 0)  prev_il_instruction = NULL;
+  else                                          prev_il_instruction = symbol->prev_il_instruction[0];
+  symbol->il_simple_instruction->accept(*this);
+  prev_il_instruction = NULL;
+
+  /* This object has (inherits) the same cvalues as the il_jump_operator */
+  symbol->const_value = symbol->il_simple_instruction->const_value;
+  return NULL;
+}
+
+
+/*
+    void *visit(il_param_list_c *symbol);
+    void *visit(il_param_assignment_c *symbol);
+    void *visit(il_param_out_assignment_c *symbol);
+*/
+
+
+/*******************/
+/* B 2.2 Operators */
+/*******************/
+void *constant_folding_c::visit(   LD_operator_c *symbol) {return handle_move(symbol, il_operand);}
+void *constant_folding_c::visit(  LDN_operator_c *symbol) {return handle_not (symbol, il_operand);}
+
+/* NOTE: we are implementing a constant folding algorithm, not a constant propagation algorithm.
+ *       For the constant propagation algorithm, the correct implementation of ST(N)_operator_c would be...
+ */
+//void *constant_folding_c::visit(   ST_operator_c *symbol) {return handle_move(il_operand, symbol);}
+//void *constant_folding_c::visit(  STN_operator_c *symbol) {return handle_not (il_operand, symbol);}
+void *constant_folding_c::visit(   ST_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit(  STN_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+
+/* NOTE: the standard allows syntax in which the NOT operator is followed by an optional <il_operand>
+ *              NOT [<il_operand>]
+ *       However, it does not define the semantic of the NOT operation when the <il_operand> is specified.
+ *       We therefore consider it an error if an il_operand is specified! This error will be caught elsewhere!
+ */
+void *constant_folding_c::visit(  NOT_operator_c *symbol) {return handle_not(symbol, prev_il_instruction);}
+
+/* NOTE: Since we are only implementing a constant folding algorithm, and not a constant propagation algorithm,
+ *       the following IL instructions do not change/set the value of the il_operand!
+ */
+void *constant_folding_c::visit(    S_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit(    R_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+
+/* FB calls leave the value in the accumulator unchanged */
+void *constant_folding_c::visit(   S1_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit(   R1_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit(  CLK_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit(   CU_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit(   CD_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit(   PV_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit(   IN_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit(   PT_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+
+void *constant_folding_c::visit(  AND_operator_c *symbol) {return handle_and (symbol, prev_il_instruction, il_operand);}
+void *constant_folding_c::visit(   OR_operator_c *symbol) {return handle_or  (symbol, prev_il_instruction, il_operand);}
+void *constant_folding_c::visit(  XOR_operator_c *symbol) {return handle_xor (symbol, prev_il_instruction, il_operand);}
+void *constant_folding_c::visit( ANDN_operator_c *symbol) {       handle_and (symbol, prev_il_instruction, il_operand); return handle_not(symbol, symbol);}
+void *constant_folding_c::visit(  ORN_operator_c *symbol) {       handle_or  (symbol, prev_il_instruction, il_operand); return handle_not(symbol, symbol);}
+void *constant_folding_c::visit( XORN_operator_c *symbol) {       handle_xor (symbol, prev_il_instruction, il_operand); return handle_not(symbol, symbol);}
+
+void *constant_folding_c::visit(  ADD_operator_c *symbol) {return handle_add (symbol, prev_il_instruction, il_operand);}
+void *constant_folding_c::visit(  SUB_operator_c *symbol) {return handle_sub (symbol, prev_il_instruction, il_operand);}
+void *constant_folding_c::visit(  MUL_operator_c *symbol) {return handle_mul (symbol, prev_il_instruction, il_operand);}
+void *constant_folding_c::visit(  DIV_operator_c *symbol) {return handle_div (symbol, prev_il_instruction, il_operand);}
+void *constant_folding_c::visit(  MOD_operator_c *symbol) {return handle_mod (symbol, prev_il_instruction, il_operand);}
+
+void *constant_folding_c::visit(   GT_operator_c *symbol) {       handle_cmp (symbol, prev_il_instruction, il_operand, > );}
+void *constant_folding_c::visit(   GE_operator_c *symbol) {       handle_cmp (symbol, prev_il_instruction, il_operand, >=);}
+void *constant_folding_c::visit(   EQ_operator_c *symbol) {       handle_cmp (symbol, prev_il_instruction, il_operand, ==);}
+void *constant_folding_c::visit(   LT_operator_c *symbol) {       handle_cmp (symbol, prev_il_instruction, il_operand, < );}
+void *constant_folding_c::visit(   LE_operator_c *symbol) {       handle_cmp (symbol, prev_il_instruction, il_operand, <=);}
+void *constant_folding_c::visit(   NE_operator_c *symbol) {       handle_cmp (symbol, prev_il_instruction, il_operand, !=);}
+
+void *constant_folding_c::visit(  CAL_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit(  RET_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit(  JMP_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit( CALC_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit(CALCN_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit( RETC_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit(RETCN_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit( JMPC_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+void *constant_folding_c::visit(JMPCN_operator_c *symbol) {return handle_move(symbol, prev_il_instruction);}
+
+
+
+
+/***************************************/
+/* B.3 - Language ST (Structured Text) */
+/***************************************/
+/***********************/
+/* B 3.1 - Expressions */
+/***********************/
+void *constant_folding_c::visit(    or_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_or (symbol, symbol->l_exp, symbol->r_exp);}
+void *constant_folding_c::visit(   xor_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_xor(symbol, symbol->l_exp, symbol->r_exp);}
+void *constant_folding_c::visit(   and_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_and(symbol, symbol->l_exp, symbol->r_exp);}
+
+void *constant_folding_c::visit(   equ_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this);        handle_cmp (symbol, symbol->l_exp, symbol->r_exp, ==);}
+void *constant_folding_c::visit(notequ_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this);        handle_cmp (symbol, symbol->l_exp, symbol->r_exp, !=);}
+void *constant_folding_c::visit(    lt_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this);        handle_cmp (symbol, symbol->l_exp, symbol->r_exp, < );}
+void *constant_folding_c::visit(    gt_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this);        handle_cmp (symbol, symbol->l_exp, symbol->r_exp, > );}
+void *constant_folding_c::visit(    le_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this);        handle_cmp (symbol, symbol->l_exp, symbol->r_exp, <=);}
+void *constant_folding_c::visit(    ge_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this);        handle_cmp (symbol, symbol->l_exp, symbol->r_exp, >=);}
+
+void *constant_folding_c::visit(   add_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_add(symbol, symbol->l_exp, symbol->r_exp);}
+void *constant_folding_c::visit(   sub_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_sub(symbol, symbol->l_exp, symbol->r_exp);}
+void *constant_folding_c::visit(   mul_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_mul(symbol, symbol->l_exp, symbol->r_exp);}
+void *constant_folding_c::visit(   div_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_div(symbol, symbol->l_exp, symbol->r_exp);}
+void *constant_folding_c::visit(   mod_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_mod(symbol, symbol->l_exp, symbol->r_exp);}
+void *constant_folding_c::visit( power_expression_c *symbol) {symbol->l_exp->accept(*this); symbol->r_exp->accept(*this); return handle_pow(symbol, symbol->l_exp, symbol->r_exp);}
+
+void *constant_folding_c::visit(   neg_expression_c *symbol) {symbol->  exp->accept(*this); return handle_neg(symbol, symbol->exp);}
+void *constant_folding_c::visit(   not_expression_c *symbol) {symbol->  exp->accept(*this); return handle_not(symbol, symbol->exp);}
+
+/* TODO: handle function invocations... */
+// void *fill_candidate_datatypes_c::visit(function_invocation_c *symbol) {}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/constant_folding.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -0,0 +1,179 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2009-2012  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2012       Manuele Conti (conti.ma@alice.it)
+ *
+ *  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)
+ *
+ */
+
+/* Determine the data type of an constant expression.
+ * A reference to the relevant type definition is returned.
+ *
+ * For example:
+ *       2 + 3       -> returns reference 
+ *       22.2 - 5    -> returns reference
+ *       etc...
+ */
+
+#include <vector>
+#include "../absyntax_utils/absyntax_utils.hh"
+
+
+
+class constant_folding_c : public iterator_visitor_c {
+  private:
+    search_varfb_instance_type_c *search_varfb_instance_type;
+    search_base_type_c search_base_type;
+    int error_count;
+    bool warning_found;
+    int current_display_error_level;
+    /* Pointer to the previous IL instruction, which contains the current cvalue of the data stored in the IL stack, i.e. the default variable, a.k.a. accumulator */
+    symbol_c *prev_il_instruction;
+    /* the current IL operand being analyzed */
+    symbol_c *il_operand;
+
+  public:
+	constant_folding_c(symbol_c *symbol = NULL);
+	virtual ~constant_folding_c(void);
+	int get_error_count();
+
+  private:
+    /*********************/
+    /* B 1.2 - Constants */
+    /*********************/
+    /******************************/
+    /* B 1.2.1 - Numeric Literals */
+    /******************************/
+    void *visit(real_c *symbol);
+    void *visit(integer_c *symbol);
+    void *visit(neg_real_c *symbol);
+    void *visit(neg_integer_c *symbol);
+    void *visit(binary_integer_c *symbol);
+    void *visit(octal_integer_c *symbol);
+    void *visit(hex_integer_c *symbol);
+    void *visit(integer_literal_c *symbol);
+    void *visit(real_literal_c *symbol);
+    void *visit(bit_string_literal_c *symbol);
+    void *visit(boolean_literal_c *symbol);
+    void *visit(boolean_true_c *symbol);
+    void *visit(boolean_false_c *symbol);
+
+    /****************************************/
+    /* B.2 - Language IL (Instruction List) */
+    /****************************************/
+    /***********************************/
+    /* B 2.1 Instructions and Operands */
+    /***********************************/
+    // void *visit(instruction_list_c *symbol); /* Not needed, since we inherit from iterator_visitor_c */
+    void *visit(il_instruction_c *symbol);
+    void *visit(il_simple_operation_c *symbol);
+    //void *visit(il_function_call_c *symbol);  /* TODO */
+    void *visit(il_expression_c *symbol);
+    void *visit(il_jump_operation_c *symbol);
+    void *visit(il_fb_call_c *symbol);
+    //void *visit(il_formal_funct_call_c *symbol);   /* TODO */
+    //void *visit(il_operand_list_c *symbol);  /* Not needed, since we inherit from iterator_visitor_c */
+    void *visit(simple_instr_list_c *symbol);
+    void *visit(il_simple_instruction_c *symbol);
+
+
+    /*******************/
+    /* B 2.2 Operators */
+    /*******************/
+    void *visit(   LD_operator_c *symbol);
+    void *visit(  LDN_operator_c *symbol);
+    void *visit(   ST_operator_c *symbol);
+    void *visit(  STN_operator_c *symbol);
+    void *visit(  NOT_operator_c *symbol);
+    void *visit(    S_operator_c *symbol);
+    void *visit(    R_operator_c *symbol);
+    void *visit(   S1_operator_c *symbol);
+    void *visit(   R1_operator_c *symbol);
+    void *visit(  CLK_operator_c *symbol);
+    void *visit(   CU_operator_c *symbol);
+    void *visit(   CD_operator_c *symbol);
+    void *visit(   PV_operator_c *symbol);
+    void *visit(   IN_operator_c *symbol);
+    void *visit(   PT_operator_c *symbol);
+    void *visit(  AND_operator_c *symbol);
+    void *visit(   OR_operator_c *symbol);
+    void *visit(  XOR_operator_c *symbol);
+    void *visit( ANDN_operator_c *symbol);
+    void *visit(  ORN_operator_c *symbol);
+    void *visit( XORN_operator_c *symbol);
+    void *visit(  ADD_operator_c *symbol);
+    void *visit(  SUB_operator_c *symbol);
+    void *visit(  MUL_operator_c *symbol);
+    void *visit(  DIV_operator_c *symbol);
+    void *visit(  MOD_operator_c *symbol);
+    void *visit(   GT_operator_c *symbol);
+    void *visit(   GE_operator_c *symbol);
+    void *visit(   EQ_operator_c *symbol);
+    void *visit(   LT_operator_c *symbol);
+    void *visit(   LE_operator_c *symbol);
+    void *visit(   NE_operator_c *symbol);
+    void *visit(  CAL_operator_c *symbol);
+    void *visit( CALC_operator_c *symbol);
+    void *visit(CALCN_operator_c *symbol);
+    void *visit(  RET_operator_c *symbol);
+    void *visit( RETC_operator_c *symbol);
+    void *visit(RETCN_operator_c *symbol);
+    void *visit(  JMP_operator_c *symbol);
+    void *visit( JMPC_operator_c *symbol);
+    void *visit(JMPCN_operator_c *symbol);
+    /* Symbol class handled together with function call checks */
+    // void *visit(il_assign_operator_c *symbol, variable_name);
+    /* Symbol class handled together with function call checks */
+    // void *visit(il_assign_operator_c *symbol, option, variable_name);
+
+    /***************************************/
+    /* B.3 - Language ST (Structured Text) */
+    /***************************************/
+    /***********************/
+    /* B 3.1 - Expressions */
+    /***********************/
+    void *visit(    or_expression_c *symbol);
+    void *visit(   xor_expression_c *symbol);
+    void *visit(   and_expression_c *symbol);
+    void *visit(   equ_expression_c *symbol);
+    void *visit(notequ_expression_c *symbol);
+    void *visit(    lt_expression_c *symbol);
+    void *visit(    gt_expression_c *symbol);
+    void *visit(    le_expression_c *symbol);
+    void *visit(    ge_expression_c *symbol);
+    void *visit(   add_expression_c *symbol);
+    void *visit(   sub_expression_c *symbol);
+    void *visit(   mul_expression_c *symbol);
+    void *visit(   div_expression_c *symbol);
+    void *visit(   mod_expression_c *symbol);
+    void *visit( power_expression_c *symbol);
+    void *visit(   neg_expression_c *symbol);
+    void *visit(   not_expression_c *symbol);
+    //void *visit(function_invocation_c *symbol); /* TODO */
+    
+};
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/datatype_functions.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -0,0 +1,806 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2009-2012  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2012       Manuele Conti  (conti.ma@alice.it)
+ *
+ *  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.
+ */
+
+#include "datatype_functions.hh"
+#include "../absyntax_utils/absyntax_utils.hh"
+#include <vector>
+
+
+
+
+
+
+elementary_type_c *elementary_type_c::singleton = NULL;
+
+const char *elementary_type_c::to_string(symbol_c *symbol) {
+  if (NULL == singleton)    singleton = new elementary_type_c;
+  if (NULL == singleton)    ERROR;
+  const char *res           = (const char *)symbol->accept(*singleton);
+  if (NULL == res)          ERROR;
+  return res;
+}
+
+
+
+
+
+/* Macro that expand to subtypes */
+/* copied from matiec/lib/create_standard_functions_txt.sh */
+#define __ANY(DO)                 __ANY_DERIVED(DO) __ANY_ELEMENTARY(DO)
+#define __ANY_DERIVED(DO)
+#define __ANY_ELEMENTARY(DO)      __ANY_MAGNITUDE(DO) __ANY_BIT(DO) __ANY_STRING(DO) __ANY_DATE(DO)
+#define __ANY_MAGNITUDE(DO)       __ANY_NUM(DO) DO(time)
+#define __ANY_BIT(DO)             __ANY_NBIT(DO) DO(bool)
+#define __ANY_NBIT(DO)            DO(byte) DO(word) DO(dword) DO(lword)
+//#define __ANY_STRING(DO)          DO(string) DO(wstring)
+#define __ANY_STRING(DO)          DO(string)
+#define __ANY_DATE(DO)            DO(date) DO(tod) DO(dt)
+#define __ANY_NUM(DO)             __ANY_REAL(DO) __ANY_INT(DO)
+#define __ANY_REAL(DO)            DO(real) DO(lreal)
+#define __ANY_INT(DO)             __ANY_SINT(DO) __ANY_UINT(DO)
+#define __ANY_SINT(DO)            DO(sint) DO(int) DO(dint) DO(lint)
+#define __ANY_UINT(DO)            DO(usint) DO(uint) DO(udint) DO(ulint)
+
+#define __ANY_1(DO,P1)            __ANY_DERIVED_1(DO,P1) __ANY_ELEMENTARY_1(DO,P1)
+#define __ANY_DERIVED_1(DO,P1)
+#define __ANY_ELEMENTARY_1(DO,P1) __ANY_MAGNITUDE_1(DO,P1) __ANY_BIT_1(DO,P1) __ANY_STRING_1(DO,P1) __ANY_DATE_1(DO,P1)
+#define __ANY_MAGNITUDE_1(DO,P1)  __ANY_NUM_1(DO,P1) DO(time,P1)
+#define __ANY_BIT_1(DO,P1)        __ANY_NBIT_1(DO,P1) DO(bool,P1)
+#define __ANY_NBIT_1(DO,P1)       DO(byte,P1) DO(word,P1) DO(dword,P1) DO(lword,P1)
+// #define __ANY_STRING_1(DO,P1)     DO(string,P1) DO(wstring,P1)
+#define __ANY_STRING_1(DO,P1)     DO(string,P1)
+#define __ANY_DATE_1(DO,P1)       DO(date,P1) DO(tod,P1) DO(dt,P1)
+#define __ANY_NUM_1(DO,P1)        __ANY_REAL_1(DO,P1) __ANY_INT_1(DO,P1)
+#define __ANY_REAL_1(DO,P1)       DO(real,P1) DO(lreal,P1)
+#define __ANY_INT_1(DO,P1)        __ANY_SINT_1(DO,P1) __ANY_UINT_1(DO,P1)
+#define __ANY_SINT_1(DO,P1)       DO(sint,P1) DO(int,P1) DO(dint,P1) DO(lint,P1)
+#define __ANY_UINT_1(DO,P1)       DO(usint,P1) DO(uint,P1) DO(udint,P1) DO(ulint,P1)
+
+
+/**************************************************************/
+/**************************************************************/
+/**************************************************************/
+/*******  TABLE 24: Standard arithmetic functions       *******/
+/*******    merged with                                 *******/
+/*******  TABLE 30: Functions of time data types        *******/
+/**************************************************************/
+/**************************************************************/
+/**************************************************************/
+
+/* NOTE: IEC 61131-3 v2 declares that using implicit operations ('+', '-', '*', '/') on ANYTIME data types is
+ *       valid, but deprecated, suposedly meaning that they will be removed in the following version of the standard.
+ *       However, the current draft version of IEC 61131-3 v3 still allows this use, and no longer declares these
+ *       implicit operations as deprecated.
+ *       Because of this, and although we are implementing v2 of the standard, we will no longer mark these 
+ *       operations as deprecated.
+ */
+  #define ANYTIME_OPER_DEPRECATION_STATUS widen_entry::ok
+//#define ANYTIME_OPER_DEPRECATION_STATUS widen_entry::deprecated
+
+
+const struct widen_entry widen_ADD_table[] = {
+#define __add(TYPE)       \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok                 },
+    __ANY_NUM(__add)
+#undef __add
+
+    /*******************************************/
+    /*******************************************/
+    /*** Operations with TIME, DT and TOD... ***/
+    /*******************************************/
+    /*******************************************/ 
+    { &search_constant_type_c::time_type_name,          &search_constant_type_c::time_type_name,            &search_constant_type_c::time_type_name,         widen_entry::ok                 },
+    { &search_constant_type_c::tod_type_name,           &search_constant_type_c::time_type_name,            &search_constant_type_c::tod_type_name,          ANYTIME_OPER_DEPRECATION_STATUS },
+    /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */
+    /* not currently supported by stage4, so it is best no tto add it for now... */
+//  { &search_constant_type_c::time_type_name,          &search_constant_type_c::tod_type_name,             &search_constant_type_c::tod_type_name,          ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::dt_type_name,            &search_constant_type_c::time_type_name,            &search_constant_type_c::dt_type_name,           ANYTIME_OPER_DEPRECATION_STATUS },         
+    /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */
+    /* not currently supported by stage4, so it is best no tto add it for now... */
+//  { &search_constant_type_c::time_type_name,          &search_constant_type_c::dt_type_name,              &search_constant_type_c::dt_type_name,           ANYTIME_OPER_DEPRECATION_STATUS },         
+
+    /*******************************/
+    /* SAFE version on the left... */
+    /*******************************/
+    { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::time_type_name,            &search_constant_type_c::time_type_name,         widen_entry::ok                 },
+    { &search_constant_type_c::safetod_type_name,       &search_constant_type_c::time_type_name,            &search_constant_type_c::tod_type_name,          ANYTIME_OPER_DEPRECATION_STATUS },
+    /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */
+    /* not currently supported by stage4, so it is best no tto add it for now... */
+//  { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::tod_type_name,             &search_constant_type_c::tod_type_name,          ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::safedt_type_name,        &search_constant_type_c::time_type_name,            &search_constant_type_c::dt_type_name,           ANYTIME_OPER_DEPRECATION_STATUS },         
+    /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */
+    /* not currently supported by stage4, so it is best no tto add it for now... */
+//  { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::dt_type_name,              &search_constant_type_c::dt_type_name,           ANYTIME_OPER_DEPRECATION_STATUS },         
+
+    /********************************/
+    /* SAFE version on the right... */
+    /********************************/
+    { &search_constant_type_c::time_type_name,          &search_constant_type_c::safetime_type_name,        &search_constant_type_c::time_type_name,         widen_entry::ok         },
+    { &search_constant_type_c::tod_type_name,           &search_constant_type_c::safetime_type_name,        &search_constant_type_c::tod_type_name,          ANYTIME_OPER_DEPRECATION_STATUS },
+    /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */
+    /* not currently supported by stage4, so it is best no tto add it for now... */
+//  { &search_constant_type_c::time_type_name,          &search_constant_type_c::safetod_type_name,         &search_constant_type_c::tod_type_name,          ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::dt_type_name,            &search_constant_type_c::safetime_type_name,        &search_constant_type_c::dt_type_name,           ANYTIME_OPER_DEPRECATION_STATUS },         
+    /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */
+    /* not currently supported by stage4, so it is best no tto add it for now... */
+//  { &search_constant_type_c::time_type_name,          &search_constant_type_c::safedt_type_name,          &search_constant_type_c::dt_type_name,           ANYTIME_OPER_DEPRECATION_STATUS },         
+
+    /*************************************/
+    /* SAFE version on left and right... */
+    /*************************************/
+    { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::safetime_type_name,        &search_constant_type_c::safetime_type_name,     widen_entry::ok                 },
+    { &search_constant_type_c::safetod_type_name,       &search_constant_type_c::safetime_type_name,        &search_constant_type_c::safetod_type_name,      ANYTIME_OPER_DEPRECATION_STATUS },
+    /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */
+    /* not currently supported by stage4, so it is best no tto add it for now... */
+//  { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::safetod_type_name,         &search_constant_type_c::safetod_type_name,      ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::safedt_type_name,        &search_constant_type_c::safetime_type_name,        &search_constant_type_c::safedt_type_name,       ANYTIME_OPER_DEPRECATION_STATUS },         
+    /* NOTE: the standard des not explicitly support the following semantics. However, since 'addition' is supposed to be commutative, we add it anyway... */
+    /* not currently supported by stage4, so it is best no tto add it for now... */
+//  { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::safedt_type_name,          &search_constant_type_c::safedt_type_name,       ANYTIME_OPER_DEPRECATION_STATUS },
+   
+    { NULL, NULL, NULL, widen_entry::ok },
+};
+
+
+
+
+
+
+
+const struct widen_entry widen_SUB_table[] = {
+#define __sub(TYPE)       \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok                 },
+    __ANY_NUM(__sub)
+#undef __sub
+
+    /*******************************************/
+    /*******************************************/
+    /*** Operations with TIME, DT and TOD... ***/
+    /*******************************************/
+    /*******************************************/ 
+    { &search_constant_type_c::time_type_name,          &search_constant_type_c::time_type_name,            &search_constant_type_c::time_type_name,         widen_entry::ok                 },
+    { &search_constant_type_c::date_type_name,          &search_constant_type_c::date_type_name,            &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::tod_type_name,           &search_constant_type_c::time_type_name,            &search_constant_type_c::tod_type_name,          ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::tod_type_name,           &search_constant_type_c::tod_type_name,             &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::dt_type_name,            &search_constant_type_c::time_type_name,            &search_constant_type_c::dt_type_name,           ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::dt_type_name,            &search_constant_type_c::dt_type_name,              &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS },        
+
+    /*******************************/
+    /* SAFE version on the left... */
+    /*******************************/
+    { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::time_type_name,            &search_constant_type_c::time_type_name,         widen_entry::ok                 },
+    { &search_constant_type_c::safedate_type_name,      &search_constant_type_c::date_type_name,            &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::safetod_type_name,       &search_constant_type_c::time_type_name,            &search_constant_type_c::tod_type_name,          ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::safetod_type_name,       &search_constant_type_c::tod_type_name,             &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::safedt_type_name,        &search_constant_type_c::time_type_name,            &search_constant_type_c::dt_type_name,           ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::safedt_type_name,        &search_constant_type_c::dt_type_name,              &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS },        
+
+    /********************************/
+    /* SAFE version on the right... */
+    /********************************/
+    { &search_constant_type_c::time_type_name,          &search_constant_type_c::safetime_type_name,        &search_constant_type_c::time_type_name,         widen_entry::ok                 },
+    { &search_constant_type_c::date_type_name,          &search_constant_type_c::safedate_type_name,        &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::tod_type_name,           &search_constant_type_c::safetime_type_name,        &search_constant_type_c::tod_type_name,          ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::tod_type_name,           &search_constant_type_c::safetod_type_name,         &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::dt_type_name,            &search_constant_type_c::safetime_type_name,        &search_constant_type_c::dt_type_name,           ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::dt_type_name,            &search_constant_type_c::safedt_type_name,          &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS },        
+
+    /*************************************/
+    /* SAFE version on left and right... */
+    /*************************************/
+    { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::safetime_type_name,        &search_constant_type_c::safetime_type_name,     widen_entry::ok                 },
+    { &search_constant_type_c::safedate_type_name,      &search_constant_type_c::safedate_type_name,        &search_constant_type_c::safetime_type_name,     ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::safetod_type_name,       &search_constant_type_c::safetime_type_name,        &search_constant_type_c::safetod_type_name,      ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::safetod_type_name,       &search_constant_type_c::safetod_type_name,         &search_constant_type_c::safetime_type_name,     ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::safedt_type_name,        &search_constant_type_c::safetime_type_name,        &search_constant_type_c::safedt_type_name,       ANYTIME_OPER_DEPRECATION_STATUS },
+    { &search_constant_type_c::safedt_type_name,        &search_constant_type_c::safedt_type_name,          &search_constant_type_c::safetime_type_name,     ANYTIME_OPER_DEPRECATION_STATUS },        
+
+    { NULL, NULL, NULL, widen_entry::ok },
+};
+
+
+
+
+
+
+
+const struct widen_entry widen_MUL_table[] = {
+#define __mul(TYPE)       \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok                 },
+    __ANY_NUM(__mul)
+#undef __mul
+
+    /*******************************************/
+    /*******************************************/
+    /*** Operations with TIME, DT and TOD... ***/
+    /*******************************************/
+    /*******************************************/ 
+#define __multime(TYPE)       \
+    { &search_constant_type_c::time_type_name,          &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS }, \
+    { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS }, \
+    { &search_constant_type_c::time_type_name,          &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS }, \
+    { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::safetime_type_name,     ANYTIME_OPER_DEPRECATION_STATUS }, \
+    /* NOTE: the standard des not explicitly support the following semantics. However, since 'multiplication' is supposed to be commutative, we add it anyway... */                 \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::time_type_name,            &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::time_type_name,            &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS }, \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::safetime_type_name,        &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::safetime_type_name,        &search_constant_type_c::safetime_type_name,     ANYTIME_OPER_DEPRECATION_STATUS },
+    __ANY_NUM(__multime)
+#undef __multime
+
+    { NULL, NULL, NULL, widen_entry::ok },
+};
+
+
+
+
+
+const struct widen_entry widen_DIV_table[] = {
+#define __div(TYPE)       \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok                 },
+    __ANY_NUM(__div)
+#undef __div
+
+    /*******************************************/
+    /*******************************************/
+    /*** Operations with TIME, DT and TOD... ***/
+    /*******************************************/
+    /*******************************************/ 
+#define __divtime(TYPE)       \
+    { &search_constant_type_c::time_type_name,          &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS }, \
+    { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS }, \
+    { &search_constant_type_c::time_type_name,          &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::time_type_name,         ANYTIME_OPER_DEPRECATION_STATUS }, \
+    { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::safetime_type_name,     ANYTIME_OPER_DEPRECATION_STATUS },
+    __ANY_NUM(__divtime)
+#undef __divtime
+
+    { NULL, NULL, NULL, widen_entry::ok },
+ };
+
+ 
+
+
+const struct widen_entry widen_MOD_table[] = {
+#define __mod(TYPE)       \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok                 },
+    __ANY_NUM(__mod)
+#undef __mod
+
+    { NULL, NULL, NULL, widen_entry::ok },
+};
+ 
+ 
+
+
+const struct widen_entry widen_EXPT_table[] = {
+#define __expt(IN2TYPE, IN1TYPE)       \
+    { &search_constant_type_c::IN1TYPE##_type_name,        &search_constant_type_c::IN2TYPE##_type_name,          &search_constant_type_c::IN1TYPE##_type_name,       widen_entry::ok        }, \
+    { &search_constant_type_c::safe##IN1TYPE##_type_name,  &search_constant_type_c::IN2TYPE##_type_name,          &search_constant_type_c::IN1TYPE##_type_name,       widen_entry::ok        }, \
+    { &search_constant_type_c::IN1TYPE##_type_name,        &search_constant_type_c::safe##IN2TYPE##_type_name,    &search_constant_type_c::IN1TYPE##_type_name,       widen_entry::ok        }, \
+    { &search_constant_type_c::safe##IN1TYPE##_type_name,  &search_constant_type_c::safe##IN2TYPE##_type_name,    &search_constant_type_c::safe##IN1TYPE##_type_name, widen_entry::ok        },
+#define __IN2_anynum_(IN1_TYPENAME)   __ANY_NUM_1(__expt,IN1_TYPENAME)
+    __ANY_REAL(__IN2_anynum_)
+#undef __expt
+#undef __IN2_anynum_
+    { NULL, NULL, NULL, widen_entry::ok },
+};
+
+
+
+/**************************************************************/
+/**************************************************************/
+/**************************************************************/
+/*******                                                *******/
+/*******  TABLE 26: Standard bitwise Boolean functions  *******/
+/*******                                                *******/
+/**************************************************************/
+/**************************************************************/
+/**************************************************************/
+/* table used by AND and ANDN operators, and and_expression */
+const struct widen_entry widen_AND_table[] = {
+#define __and(TYPE)       \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok                 },
+    __ANY_BIT(__and)
+#undef __and
+
+    { NULL, NULL, NULL, widen_entry::ok },
+};
+
+/* table used by OR and ORN operators, and or_expression */
+const struct widen_entry widen_OR_table[] = {
+#define __or(TYPE)       \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok                 },
+    __ANY_BIT(__or)
+#undef __or
+
+    { NULL, NULL, NULL, widen_entry::ok },
+};
+
+
+/* table used by XOR and XORN operators, and xor_expression */
+const struct widen_entry widen_XOR_table[] = {
+#define __xor(TYPE)       \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::TYPE##_type_name,       widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::safe##TYPE##_type_name, widen_entry::ok                 },
+    __ANY_BIT(__xor)
+#undef __xor
+
+    { NULL, NULL, NULL, widen_entry::ok },
+};
+
+/**************************************************************/
+/**************************************************************/
+/**************************************************************/
+/*******                                                *******/
+/*******  TABLE 28: Standard comparison functions       *******/
+/*******                                                *******/
+/**************************************************************/
+/**************************************************************/
+/**************************************************************/
+/* table used by GT, GE, EQ, LE, LT, and NE  operators, and equivalent ST expressions. */
+const struct widen_entry widen_CMP_table[] = {
+#define __cmp(TYPE)       \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::bool_type_name,         widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::bool_type_name,         widen_entry::ok                 }, \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::bool_type_name,         widen_entry::ok                 }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::safebool_type_name,     widen_entry::ok                 },
+    __ANY_ELEMENTARY(__cmp)
+#undef __cmp
+
+    { NULL, NULL, NULL, widen_entry::ok },
+};
+
+
+/* Search for a datatype inside a candidate_datatypes list.
+ * Returns: position of datatype in the list, or -1 if not found.
+ */
+int search_in_candidate_datatype_list(symbol_c *datatype, const std::vector <symbol_c *> &candidate_datatypes) {
+	if (NULL == datatype) 
+		return -1;
+
+	for(unsigned int i = 0; i < candidate_datatypes.size(); i++)
+		if (is_type_equal(datatype, candidate_datatypes[i]))
+			return i;
+	/* Not found ! */
+	return -1;
+}
+
+/* Remove a datatype inside a candidate_datatypes list.
+ * Returns: If successful it returns true, false otherwise.
+ */
+bool remove_from_candidate_datatype_list(symbol_c *datatype, std::vector <symbol_c *> &candidate_datatypes) {
+	int pos = search_in_candidate_datatype_list(datatype, candidate_datatypes);
+	if (pos < 0)
+		return false;
+	
+	candidate_datatypes.erase(candidate_datatypes.begin() + pos);
+	return true;
+}
+
+
+
+/* Intersect two candidate_datatype_lists.
+ * Remove from list1 (origin, dest.) all elements that are not found in list2 (with).
+ * In essence, list1 will contain the result of the intersection of list1 with list2.
+ * In other words, modify list1 so it only contains the elelements that are simultaneously in list1 and list2!
+ */
+void intersect_candidate_datatype_list(symbol_c *list1 /*origin, dest.*/, symbol_c *list2 /*with*/) {
+	if ((NULL == list1) || (NULL == list2))
+		/* In principle, we should never call it with NULL values. Best to abort the compiler just in case! */
+		return;
+
+	for(std::vector<symbol_c *>::iterator i = list1->candidate_datatypes.begin(); i < list1->candidate_datatypes.end(); ) {
+		/* Note that we do _not_ increment i in the for() loop!
+		 * When we erase an element from position i, a new element will take it's place, that must also be tested! 
+		 */
+		if (search_in_candidate_datatype_list(*i, list2->candidate_datatypes) < 0)
+			/* remove this element! This will change the value of candidate_datatypes.size() */
+			list1->candidate_datatypes.erase(i);
+		else i++;
+	}
+}
+
+
+
+
+/* intersect the candidate_datatype lists of all prev_il_intructions, and set the local candidate_datatype list to the result! */
+void intersect_prev_candidate_datatype_lists(il_instruction_c *symbol) {
+	if (symbol->prev_il_instruction.empty())
+		return;
+	
+	symbol->candidate_datatypes = symbol->prev_il_instruction[0]->candidate_datatypes;
+	for (unsigned int i = 1; i < symbol->prev_il_instruction.size(); i++) {
+		intersect_candidate_datatype_list(symbol /*origin, dest.*/, symbol->prev_il_instruction[i] /*with*/);
+	}  
+}
+
+
+
+
+/* A helper function... */
+bool is_ANY_ELEMENTARY_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  return is_ANY_MAGNITUDE_type(type_symbol)
+      || is_ANY_BIT_type      (type_symbol)
+      || is_ANY_STRING_type   (type_symbol)
+      || is_ANY_DATE_type     (type_symbol);
+}
+
+/* A helper function... */
+bool is_ANY_SAFEELEMENTARY_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  return is_ANY_SAFEMAGNITUDE_type(type_symbol)
+      || is_ANY_SAFEBIT_type      (type_symbol)
+      || is_ANY_SAFESTRING_type   (type_symbol)
+      || is_ANY_SAFEDATE_type     (type_symbol);
+}
+
+/* A helper function... */
+bool is_ANY_ELEMENTARY_compatible(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  /* NOTE: doing
+   *          return is_ANY_SAFEELEMENTARY_type() || is_ANY_ELEMENTARY_type()
+   *       is incorrect, as the literals would never be considered compatible...
+   */
+  return is_ANY_MAGNITUDE_compatible(type_symbol)
+      || is_ANY_BIT_compatible      (type_symbol)
+      || is_ANY_STRING_compatible   (type_symbol)
+      || is_ANY_DATE_compatible     (type_symbol);
+}
+
+
+/* A helper function... */
+bool is_ANY_MAGNITUDE_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(time_type_name_c)) {return true;}
+  return is_ANY_NUM_type(type_symbol);
+}
+
+/* A helper function... */
+bool is_ANY_signed_MAGNITUDE_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(time_type_name_c)) {return true;}
+  return is_ANY_signed_NUM_type(type_symbol);
+}
+
+/* A helper function... */
+bool is_ANY_SAFEMAGNITUDE_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(safetime_type_name_c)) {return true;}
+  return is_ANY_SAFENUM_type(type_symbol);
+}
+
+/* A helper function... */
+bool is_ANY_signed_SAFEMAGNITUDE_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(safetime_type_name_c)) {return true;}
+  return is_ANY_signed_SAFENUM_type(type_symbol);
+}
+
+/* A helper function... */
+bool is_ANY_MAGNITUDE_compatible(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (is_ANY_MAGNITUDE_type    (type_symbol))              {return true;}
+  if (is_ANY_SAFEMAGNITUDE_type(type_symbol))              {return true;}
+  return is_ANY_NUM_compatible(type_symbol);
+}
+
+/* A helper function... */
+bool is_ANY_signed_MAGNITUDE_compatible(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (is_ANY_signed_MAGNITUDE_type    (type_symbol))       {return true;}
+  if (is_ANY_signed_SAFEMAGNITUDE_type(type_symbol))       {return true;}
+  return is_ANY_signed_NUM_compatible(type_symbol);
+}
+
+/* A helper function... */
+bool is_ANY_NUM_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (is_ANY_REAL_type(type_symbol))                       {return true;}
+  if (is_ANY_INT_type(type_symbol))                        {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_signed_NUM_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (is_ANY_REAL_type(type_symbol))                       {return true;}
+  if (is_ANY_signed_INT_type(type_symbol))                 {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_SAFENUM_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  return is_ANY_SAFEREAL_type(type_symbol)
+      || is_ANY_SAFEINT_type (type_symbol);
+}
+
+/* A helper function... */
+bool is_ANY_signed_SAFENUM_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  return is_ANY_SAFEREAL_type(type_symbol)
+      || is_ANY_signed_SAFEINT_type (type_symbol);
+}
+
+/* A helper function... */
+bool is_ANY_NUM_compatible(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (is_ANY_REAL_compatible(type_symbol))                       {return true;}
+  if (is_ANY_INT_compatible(type_symbol))                        {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_signed_NUM_compatible(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (is_ANY_REAL_compatible(type_symbol))                       {return true;}
+  if (is_ANY_signed_INT_compatible(type_symbol))                 {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_DATE_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(date_type_name_c)) {return true;}
+  if (typeid(*type_symbol) == typeid(tod_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(dt_type_name_c))   {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_SAFEDATE_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(safedate_type_name_c)) {return true;}
+  if (typeid(*type_symbol) == typeid(safetod_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(safedt_type_name_c))   {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_DATE_compatible(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (is_ANY_DATE_type    (type_symbol))              {return true;}
+  if (is_ANY_SAFEDATE_type(type_symbol))              {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_STRING_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(string_type_name_c)) {return true;}
+  if (typeid(*type_symbol) == typeid(wstring_type_name_c)) {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_SAFESTRING_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(safestring_type_name_c)) {return true;}
+  if (typeid(*type_symbol) == typeid(safewstring_type_name_c)) {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_STRING_compatible(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (is_ANY_STRING_type    (type_symbol))              {return true;}
+  if (is_ANY_SAFESTRING_type(type_symbol))              {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_INT_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(sint_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(int_type_name_c))   {return true;}
+  if (typeid(*type_symbol) == typeid(dint_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(lint_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(usint_type_name_c)) {return true;}
+  if (typeid(*type_symbol) == typeid(uint_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(udint_type_name_c)) {return true;}
+  if (typeid(*type_symbol) == typeid(ulint_type_name_c)) {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_signed_INT_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(sint_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(int_type_name_c))   {return true;}
+  if (typeid(*type_symbol) == typeid(dint_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(lint_type_name_c))  {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_signed_SAFEINT_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(safesint_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(safeint_type_name_c))   {return true;}
+  if (typeid(*type_symbol) == typeid(safedint_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(safelint_type_name_c))  {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_SAFEINT_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(safesint_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(safeint_type_name_c))   {return true;}
+  if (typeid(*type_symbol) == typeid(safedint_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(safelint_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(safeusint_type_name_c)) {return true;}
+  if (typeid(*type_symbol) == typeid(safeuint_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(safeudint_type_name_c)) {return true;}
+  if (typeid(*type_symbol) == typeid(safeulint_type_name_c)) {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_signed_INT_compatible(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (is_ANY_signed_INT_type    (type_symbol))              {return true;}
+  if (is_ANY_signed_SAFEINT_type(type_symbol))              {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_INT_compatible(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (is_ANY_INT_type    (type_symbol))              {return true;}
+  if (is_ANY_SAFEINT_type(type_symbol))              {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_REAL_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(real_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(lreal_type_name_c)) {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_SAFEREAL_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(safereal_type_name_c))  {return true;}
+  if (typeid(*type_symbol) == typeid(safelreal_type_name_c)) {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_REAL_compatible(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (is_ANY_REAL_type    (type_symbol))              {return true;}
+  if (is_ANY_SAFEREAL_type(type_symbol))              {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_BIT_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(bool_type_name_c))     {return true;}
+  if (typeid(*type_symbol) == typeid(byte_type_name_c))     {return true;}
+  if (typeid(*type_symbol) == typeid(word_type_name_c))     {return true;}
+  if (typeid(*type_symbol) == typeid(dword_type_name_c))    {return true;}
+  if (typeid(*type_symbol) == typeid(lword_type_name_c))    {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_SAFEBIT_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(safebool_type_name_c))     {return true;}
+  if (typeid(*type_symbol) == typeid(safebyte_type_name_c))     {return true;}
+  if (typeid(*type_symbol) == typeid(safeword_type_name_c))     {return true;}
+  if (typeid(*type_symbol) == typeid(safedword_type_name_c))    {return true;}
+  if (typeid(*type_symbol) == typeid(safelword_type_name_c))    {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_BIT_compatible(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (is_ANY_BIT_type    (type_symbol))              {return true;}
+  if (is_ANY_SAFEBIT_type(type_symbol))              {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_BOOL_type(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(bool_type_name_c))      {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_SAFEBOOL_type(symbol_c *type_symbol){
+  if (type_symbol == NULL) {return false;}
+  if (typeid(*type_symbol) == typeid(safebool_type_name_c))  {return true;}
+  return false;
+}
+
+/* A helper function... */
+bool is_ANY_BOOL_compatible(symbol_c *type_symbol) {
+  if (type_symbol == NULL) {return false;}
+  if (is_BOOL_type    (type_symbol))              {return true;}
+  if (is_SAFEBOOL_type(type_symbol))              {return true;}
+  return false;
+}
+
+
+
+
+
+bool is_type_equal(symbol_c *first_type, symbol_c *second_type) {
+  if ((NULL == first_type) || (NULL == second_type))
+      return false;
+  if (typeid(* first_type) == typeid(invalid_type_name_c))
+      return false;
+  if (typeid(*second_type) == typeid(invalid_type_name_c))
+      return false;
+    
+  if (is_ANY_ELEMENTARY_type(first_type)) {
+      if (typeid(*first_type) == typeid(*second_type))
+          return true;
+  } else   /* ANY_DERIVED */
+      return (first_type == second_type);
+
+  return false;
+}
+
+
+
+bool is_type_valid(symbol_c *type) {
+  if (NULL == type)
+      return false;
+  if (typeid(*type) == typeid(invalid_type_name_c))
+      return false;
+
+  return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/datatype_functions.hh	Wed Aug 22 16:46:17 2012 +0200
@@ -0,0 +1,220 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2009-2012  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2012       Manuele Conti  (conti.ma@alice.it)
+ *
+ *  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.
+ */
+
+#ifndef _HELPER_FUNCTIONS_HH_
+#define _HELPER_FUNCTIONS_HH_
+
+#include "../absyntax/visitor.hh"
+#include <typeinfo>
+
+
+
+
+
+typedef struct {
+  symbol_c *function_name;
+  symbol_c *nonformal_operand_list;
+  symbol_c *   formal_operand_list;
+
+  enum {POU_FB, POU_function} POU_type;
+//symbol_c &*datatype;
+//std::vector <symbol_c *> &candidate_datatypes;
+  std::vector <symbol_c *> &candidate_functions;
+  symbol_c *&called_function_declaration;
+  int      &extensible_param_count;
+} generic_function_call_t;
+
+
+
+/* A small helper class, to transform elementary data type to string.
+ * this allows us to generate more relevant error messages...
+ */
+
+class elementary_type_c: public null_visitor_c {
+  protected:
+    elementary_type_c(void)  {};
+    ~elementary_type_c(void) {};
+
+  private:
+    /* singleton class! */
+    static elementary_type_c *singleton;
+
+  public:
+    static const char * to_string(symbol_c *symbol);
+
+
+    /***********************************/
+    /* B 1.3.1 - Elementary Data Types */
+    /***********************************/
+    void *visit(time_type_name_c        *symbol) {return (void *)"TIME";        };
+    void *visit(bool_type_name_c        *symbol) {return (void *)"BOOL";        };
+    void *visit(sint_type_name_c        *symbol) {return (void *)"SINT";        };
+    void *visit(int_type_name_c         *symbol) {return (void *)"INT";         };
+    void *visit(dint_type_name_c        *symbol) {return (void *)"DINT";        };
+    void *visit(lint_type_name_c        *symbol) {return (void *)"LINT";        };
+    void *visit(usint_type_name_c       *symbol) {return (void *)"USINT";       };
+    void *visit(uint_type_name_c        *symbol) {return (void *)"UINT";        };
+    void *visit(udint_type_name_c       *symbol) {return (void *)"UDINT";       };
+    void *visit(ulint_type_name_c       *symbol) {return (void *)"ULINT";       };
+    void *visit(real_type_name_c        *symbol) {return (void *)"REAL";        };
+    void *visit(lreal_type_name_c       *symbol) {return (void *)"LREAL";       };
+    void *visit(date_type_name_c        *symbol) {return (void *)"DATE";        };
+    void *visit(tod_type_name_c         *symbol) {return (void *)"TOD";         };
+    void *visit(dt_type_name_c          *symbol) {return (void *)"DT";          };
+    void *visit(byte_type_name_c        *symbol) {return (void *)"BYTE";        };
+    void *visit(word_type_name_c        *symbol) {return (void *)"WORD";        };
+    void *visit(lword_type_name_c       *symbol) {return (void *)"LWORD";       };
+    void *visit(dword_type_name_c       *symbol) {return (void *)"DWORD";       };
+    void *visit(string_type_name_c      *symbol) {return (void *)"STRING";      };
+    void *visit(wstring_type_name_c     *symbol) {return (void *)"WSTRING";     };
+
+    void *visit(safetime_type_name_c    *symbol) {return (void *)"SAFETIME";    };
+    void *visit(safebool_type_name_c    *symbol) {return (void *)"SAFEBOOL";    };
+    void *visit(safesint_type_name_c    *symbol) {return (void *)"SAFESINT";    };
+    void *visit(safeint_type_name_c     *symbol) {return (void *)"SAFEINT";     };
+    void *visit(safedint_type_name_c    *symbol) {return (void *)"SAFEDINT";    };
+    void *visit(safelint_type_name_c    *symbol) {return (void *)"SAFELINT";    };
+    void *visit(safeusint_type_name_c   *symbol) {return (void *)"SAFEUSINT";   };
+    void *visit(safeuint_type_name_c    *symbol) {return (void *)"SAFEUINT";    };
+    void *visit(safeudint_type_name_c   *symbol) {return (void *)"SAFEUDINT";   };
+    void *visit(safeulint_type_name_c   *symbol) {return (void *)"SAFEULINT";   };
+    void *visit(safereal_type_name_c    *symbol) {return (void *)"SAFEREAL";    };
+    void *visit(safelreal_type_name_c   *symbol) {return (void *)"SAFELREAL";   };
+    void *visit(safedate_type_name_c    *symbol) {return (void *)"SAFEDATE";    };
+    void *visit(safetod_type_name_c     *symbol) {return (void *)"SAFETOD";     };
+    void *visit(safedt_type_name_c      *symbol) {return (void *)"SAFEDT";      };
+    void *visit(safebyte_type_name_c    *symbol) {return (void *)"SAFEBYTE";    };
+    void *visit(safeword_type_name_c    *symbol) {return (void *)"SAFEWORD";    };
+    void *visit(safelword_type_name_c   *symbol) {return (void *)"SAFELWORD";   };
+    void *visit(safedword_type_name_c   *symbol) {return (void *)"SAFEDWORD";   };
+    void *visit(safestring_type_name_c  *symbol) {return (void *)"SAFESTRING";  };
+    void *visit(safewstring_type_name_c *symbol) {return (void *)"SAFEWSTRING"; };
+};
+
+
+
+
+
+
+/* Widening Primitive Conversion */
+struct widen_entry {
+	symbol_c *left;
+	symbol_c *right;
+	symbol_c *result;
+	enum {ok, deprecated} status;
+};
+/*
+ * 2.5.1.5.6 Functions of time data types
+ * Table 30 - page 64
+ */
+extern const struct widen_entry widen_ADD_table[];
+extern const struct widen_entry widen_SUB_table[];
+extern const struct widen_entry widen_MUL_table[];
+extern const struct widen_entry widen_DIV_table[];
+extern const struct widen_entry widen_MOD_table[];
+extern const struct widen_entry widen_EXPT_table[];
+extern const struct widen_entry widen_AND_table[];
+extern const struct widen_entry widen_OR_table[];
+extern const struct widen_entry widen_XOR_table[];
+extern const struct widen_entry widen_CMP_table[];
+
+/* Search for a datatype inside a candidate_datatypes list.
+ * Returns: position of datatype in the list, or -1 if not found.
+ */
+int search_in_candidate_datatype_list(symbol_c *datatype, const std::vector <symbol_c *> &candidate_datatypes);
+
+/* Remove a datatype inside a candidate_datatypes list.
+ * Returns: If successful it returns true, false otherwise.
+ */
+bool remove_from_candidate_datatype_list(symbol_c *datatype, std::vector <symbol_c *> &candidate_datatypes);
+
+/* Intersect two candidate_datatype_lists.
+ * Remove from list1 (origin, dest.) all elements that are not found in list2 (with).
+ * In essence, list1 will contain the result of the intersection of list1 with list2.
+ * In other words, modify list1 so it only contains the elelements that are simultaneously in list1 and list2!
+ */
+void intersect_candidate_datatype_list(symbol_c *list1 /*origin, dest.*/, symbol_c *list2 /*with*/);
+
+/* intersect the candidate_datatype lists of all prev_il_intructions, and set the local candidate_datatype list to the result! */
+void intersect_prev_candidate_datatype_lists(il_instruction_c *symbol);
+
+
+
+/* A helper function... */
+bool is_ANY_ELEMENTARY_type                (symbol_c *type_symbol);
+bool is_ANY_SAFEELEMENTARY_type            (symbol_c *type_symbol);
+bool is_ANY_ELEMENTARY_compatible          (symbol_c *type_symbol);
+
+bool is_ANY_MAGNITUDE_type                 (symbol_c *type_symbol);
+bool is_ANY_SAFEMAGNITUDE_type             (symbol_c *type_symbol);
+bool is_ANY_MAGNITUDE_compatible           (symbol_c *type_symbol);
+
+bool is_ANY_signed_MAGNITUDE_type          (symbol_c *type_symbol);
+bool is_ANY_signed_SAFEMAGNITUDE_type      (symbol_c *type_symbol);
+bool is_ANY_signed_MAGNITUDE_compatible    (symbol_c *type_symbol);
+
+bool is_ANY_DATE_type                      (symbol_c *type_symbol);
+bool is_ANY_SAFEDATE_type                  (symbol_c *type_symbol);
+bool is_ANY_DATE_compatible                (symbol_c *type_symbol);
+
+bool is_ANY_STRING_type                    (symbol_c *type_symbol);
+bool is_ANY_SAFESTRING_type                (symbol_c *type_symbol);
+bool is_ANY_STRING_compatible              (symbol_c *type_symbol);
+
+bool is_ANY_INT_type                       (symbol_c *type_symbol);
+bool is_ANY_SAFEINT_type                   (symbol_c *type_symbol);
+bool is_ANY_INT_compatible                 (symbol_c *type_symbol);
+
+bool is_ANY_signed_INT_type                (symbol_c *type_symbol);
+bool is_ANY_signed_SAFEINT_type            (symbol_c *type_symbol);
+bool is_ANY_signed_INT_compatible          (symbol_c *type_symbol);
+
+bool is_ANY_REAL_type                      (symbol_c *type_symbol);
+bool is_ANY_SAFEREAL_type                  (symbol_c *type_symbol);
+bool is_ANY_REAL_compatible                (symbol_c *type_symbol);
+
+bool is_ANY_NUM_type                       (symbol_c *type_symbol);
+bool is_ANY_SAFENUM_type                   (symbol_c *type_symbol);
+bool is_ANY_NUM_compatible                 (symbol_c *type_symbol);
+
+bool is_ANY_signed_NUM_type                (symbol_c *type_symbol);
+bool is_ANY_signed_SAFENUM_type            (symbol_c *type_symbol);
+bool is_ANY_signed_NUM_compatible          (symbol_c *type_symbol);
+
+bool is_ANY_BIT_type                       (symbol_c *type_symbol);
+bool is_ANY_SAFEBIT_type                   (symbol_c *type_symbol);
+bool is_ANY_BIT_compatible                 (symbol_c *type_symbol);
+
+bool is_BOOL_type                          (symbol_c *type_symbol);
+bool is_SAFEBOOL_type                      (symbol_c *type_symbol);
+bool is_ANY_BOOL_compatible                (symbol_c *type_symbol);
+
+
+bool is_type_equal(symbol_c *first_type, symbol_c *second_type);
+bool is_type_valid(symbol_c *type);
+
+
+
+
+#endif /* _HELPER_FUNCTIONS_HH_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/fill_candidate_datatypes.cc	Wed Aug 22 16:46:17 2012 +0200
@@ -0,0 +1,1571 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2009-2012  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2012       Manuele Conti (manuele.conti@sirius-es.it)
+ *  Copyright (C) 2012       Matteo Facchinetti (matteo.facchinetti@sirius-es.it)
+ *
+ *  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)
+ *
+ */
+
+
+/* TODO - things yet not checked by this data type checker...
+ *
+ * - check variable declarations
+ * - check data type declarations
+ * - check inside configurations (variable declarations)
+ * - check SFC code
+ * - must fix S and R IL functions (includes potientialy fixing stage4 code!) 
+ */
+
+
+/* NOTE: The algorithm implemented here assumes that flow control analysis has already been completed!
+ *       BEFORE running this visitor, be sure to CALL the flow_control_analysis_c visitor!
+ */
+
+
+/*
+ *  Fill the candidate datatype list for all symbols that may legally 'have' a data type (e.g. variables, literals, function calls, expressions, etc.)
+ * 
+ *  The candidate datatype list will be filled with a list of all the data types that expression may legally take.
+ *  For example, the very simple literal '0' (as in foo := 0), may represent a:
+ *    BOOL, BYTE, WORD, DWORD, LWORD, USINT, SINT, UINT, INT, UDINT, DINT, ULINT, LINT (as well as the SAFE versions of these data tyes too!)
+ */
+
+#include <../main.hh>         /* required for UINT64_MAX, INT64_MAX, INT64_MIN, ... */
+#include "fill_candidate_datatypes.hh"
+#include "datatype_functions.hh"
+#include <typeinfo>
+#include <list>
+#include <string>
+#include <string.h>
+#include <strings.h>
+
+#define GET_CVALUE(dtype, symbol)             ((symbol)->const_value._##dtype.value)
+#define VALID_CVALUE(dtype, symbol)           (symbol_c::cs_const_value == (symbol)->const_value._##dtype.status)
+#define IS_OVERFLOW(dtype, symbol)            (symbol_c::cs_overflow == (symbol)->const_value._##dtype.status)
+
+/* set to 1 to see debug info during execution */
+static int debug = 0;
+
+fill_candidate_datatypes_c::fill_candidate_datatypes_c(symbol_c *ignore) {
+}
+
+fill_candidate_datatypes_c::~fill_candidate_datatypes_c(void) {
+}
+
+symbol_c *fill_candidate_datatypes_c::widening_conversion(symbol_c *left_type, symbol_c *right_type, const struct widen_entry widen_table[]) {
+	int k;
+	/* find a widening table entry compatible */
+	for (k = 0; NULL != widen_table[k].left;  k++)
+		if ((typeid(*left_type) == typeid(*widen_table[k].left)) && (typeid(*right_type) == typeid(*widen_table[k].right)))
+                      return widen_table[k].result;
+	return NULL;
+}
+
+
+/* add a data type to a candidate data type list, while guaranteeing no duplicate entries! */
+/* Returns true if it really did add the datatype to the list, or false if it was already present in the list! */
+bool fill_candidate_datatypes_c::add_datatype_to_candidate_list(symbol_c *symbol, symbol_c *datatype) {
+  /* If it is an invalid data type, do not insert!
+   * NOTE: it reduces overall code size to do this test here, instead of doing every time before calling the add_datatype_to_candidate_list() function. 
+   */
+  if (!is_type_valid(datatype)) /* checks for NULL and invalid_type_name_c */
+    return false;
+
+  if (search_in_candidate_datatype_list(datatype, symbol->candidate_datatypes) >= 0) 
+    /* already in the list, Just return! */
+    return false;
+  
+  /* not yet in the candidate data type list, so we insert it now! */
+  symbol->candidate_datatypes.push_back(datatype);
+  return true;
+}
+    
+    
+bool fill_candidate_datatypes_c::add_2datatypes_to_candidate_list(symbol_c *symbol, symbol_c *datatype1, symbol_c *datatype2) {
+  add_datatype_to_candidate_list(symbol, datatype1);
+  add_datatype_to_candidate_list(symbol, datatype2);
+  return true;
+}
+
+
+
+void fill_candidate_datatypes_c::remove_incompatible_datatypes(symbol_c *symbol) {
+  #ifdef __REMOVE__
+    #error __REMOVE__ macro already exists. Choose another name!
+  #endif
+  #define __REMOVE__(datatype)\
+      remove_from_candidate_datatype_list(&search_constant_type_c::datatype,       symbol->candidate_datatypes);\
+      remove_from_candidate_datatype_list(&search_constant_type_c::safe##datatype, symbol->candidate_datatypes);
+  
+  {/* Remove unsigned data types */
+    uint64_t value = 0;
+    if (VALID_CVALUE( uint64, symbol)) value = GET_CVALUE(uint64, symbol);
+    if (IS_OVERFLOW ( uint64, symbol)) value = (uint64_t)UINT32_MAX + (uint64_t)1;
+    
+    if (value > 1          )          {__REMOVE__(bool_type_name);}
+    if (value > UINT8_MAX  )          {__REMOVE__(usint_type_name);  __REMOVE__( byte_type_name);}
+    if (value > UINT16_MAX )          {__REMOVE__( uint_type_name);  __REMOVE__( word_type_name);}
+    if (value > UINT32_MAX )          {__REMOVE__(udint_type_name);  __REMOVE__(dword_type_name);}
+    if (IS_OVERFLOW( uint64, symbol)) {__REMOVE__(ulint_type_name);  __REMOVE__(lword_type_name);}
+  }
+
+  {/* Remove signed data types */
+    int64_t value = 0;
+    if (VALID_CVALUE(  int64, symbol)) value = GET_CVALUE(int64, symbol);
+    if (IS_OVERFLOW (  int64, symbol)) value = (int64_t)INT32_MAX + (int64_t)1;
+    
+    if ((value <  INT8_MIN) || (value >  INT8_MAX)) {__REMOVE__(sint_type_name);}
+    if ((value < INT16_MIN) || (value > INT16_MAX)) {__REMOVE__( int_type_name);}
+    if ((value < INT32_MIN) || (value > INT32_MAX)) {__REMOVE__(dint_type_name);}
+    if (IS_OVERFLOW( int64, symbol))                {__REMOVE__(lint_type_name);}
+  }
+    
+  {/* Remove floating point data types */
+    real64_t value = 0;
+    if (VALID_CVALUE( real64, symbol)) value = GET_CVALUE(real64, symbol);
+    if (IS_OVERFLOW ( real64, symbol)) value = (real64_t)REAL32_MAX + (real64_t)1;
+    if (value >  REAL32_MAX )         {__REMOVE__( real_type_name);}
+    if (value < -REAL32_MAX )         {__REMOVE__( real_type_name);}
+    if (IS_OVERFLOW( real64, symbol)) {__REMOVE__(lreal_type_name);}
+  }
+  #undef __REMOVE__
+}
+    
+
+/* returns true if compatible function/FB invocation, otherwise returns false */
+/* Assumes that the candidate_datatype lists of all the parameters being passed haved already been filled in */
+/*
+ * All parameters being passed to the called function MUST be in the parameter list to which f_call points to!
+ * This means that, for non formal function calls in IL, de current (default value) must be artificially added to the
+ * beginning of the parameter list BEFORE calling handle_function_call().
+ */
+bool fill_candidate_datatypes_c::match_nonformal_call(symbol_c *f_call, symbol_c *f_decl) {
+	symbol_c *call_param_value,  *param_datatype;
+	identifier_c *param_name;
+	function_param_iterator_c       fp_iterator(f_decl);
+	function_call_param_iterator_c fcp_iterator(f_call);
+	int extensible_parameter_highest_index = -1;
+	unsigned int i;
+
+	/* Iterating through the non-formal parameters of the function call */
+	while((call_param_value = fcp_iterator.next_nf()) != NULL) {
+		/* Iterate to the next parameter of the function being called.
+		 * Get the name of that parameter, and ignore if EN or ENO.
+		 */
+		do {
+			param_name = fp_iterator.next();
+			/* If there is no other parameter declared, then we are passing too many parameters... */
+			if(param_name == NULL) return false;
+		} while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0));
+
+		/* TODO: verify if it is lvalue when INOUT or OUTPUT parameters! */
+		/* Get the parameter type */
+		param_datatype = base_type(fp_iterator.param_type());
+		
+		/* check whether one of the candidate_data_types of the value being passed is the same as the param_type */
+		if (search_in_candidate_datatype_list(param_datatype, call_param_value->candidate_datatypes) < 0)
+			return false; /* return false if param_type not in the list! */
+	}
+	/* call is compatible! */
+	return true;
+}
+
+
+
+/* returns true if compatible function/FB invocation, otherwise returns false */
+/* Assumes that the candidate_datatype lists of all the parameters being passed haved already been filled in */
+bool fill_candidate_datatypes_c::match_formal_call(symbol_c *f_call, symbol_c *f_decl, symbol_c **first_param_datatype) {
+	symbol_c *call_param_value, *call_param_name, *param_datatype;
+	symbol_c *verify_duplicate_param;
+	identifier_c *param_name;
+	function_param_iterator_c       fp_iterator(f_decl);
+	function_call_param_iterator_c fcp_iterator(f_call);
+	int extensible_parameter_highest_index = -1;
+	identifier_c *extensible_parameter_name;
+	unsigned int i;
+	bool is_first_param = true;
+
+	/* Iterating through the formal parameters of the function call */
+	while((call_param_name = fcp_iterator.next_f()) != NULL) {
+		/* Obtaining the value being passed in the function call */
+		call_param_value = fcp_iterator.get_current_value();
+		/* the following should never occur. If it does, then we have a bug in our code... */
+		if (NULL == call_param_value) ERROR;
+
+		/* Obtaining the assignment direction:  := (assign_in) or => (assign_out) */
+		function_call_param_iterator_c::assign_direction_t call_param_dir = fcp_iterator.get_assign_direction();
+
+		/* Checking if there are duplicated parameter values */
+		verify_duplicate_param = fcp_iterator.search_f(call_param_name);
+		if(verify_duplicate_param != call_param_value)
+			return false;
+
+		/* Obtaining the type of the value being passed in the function call */
+		std::vector <symbol_c *>&call_param_types = call_param_value->candidate_datatypes;
+
+		/* Find the corresponding parameter in function declaration */
+		param_name = fp_iterator.search(call_param_name);
+		if(param_name == NULL) return false;
+		/* Get the parameter data type */
+		param_datatype = base_type(fp_iterator.param_type());
+		/* Get the parameter direction: IN, OUT, IN_OUT */
+		function_param_iterator_c::param_direction_t param_dir = fp_iterator.param_direction();
+
+		/* check whether direction (IN, OUT, IN_OUT) and assignment types (:= , =>) are compatible !!! */
+		if          (function_call_param_iterator_c::assign_in  == call_param_dir) {
+			if ((function_param_iterator_c::direction_in    != param_dir) &&
+			    (function_param_iterator_c::direction_inout != param_dir))
+				return false;
+		} else if   (function_call_param_iterator_c::assign_out == call_param_dir) {
+			if ((function_param_iterator_c::direction_out   != param_dir))
+				return false;
+		} else ERROR;
+		
+		/* check whether one of the candidate_data_types of the value being passed is the same as the param_type */
+		if (search_in_candidate_datatype_list(param_datatype, call_param_types) < 0)
+			return false; /* return false if param_type not in the list! */
+		
+		/* If this is the first parameter, then copy the datatype to *first_param_datatype */
+		if (is_first_param)
+			if (NULL != first_param_datatype)
+				*first_param_datatype = param_datatype;
+		is_first_param = false;
+	}
+	/* call is compatible! */
+	return true;
+}
+
+
+
+
+/* Handle a generic function call!
+ * Assumes that the parameter_list containing the values being passed in this function invocation
+ * has already had all the candidate_datatype lists filled in!
+ *
+ * All parameters being passed to the called function MUST be in the parameter list to which f_call points to!
+ * This means that, for non formal function calls in IL, de current (default value) must be artificially added to the
+ * beginning of the parameter list BEFORE calling handle_function_call().
+ */
+/*
+typedef struct {
+  symbol_c *function_name,
+  symbol_c *nonformal_operand_list,
+  symbol_c *   formal_operand_list,
+
+  std::vector <symbol_c *> &candidate_functions,  
+  symbol_c &*called_function_declaration,
+  int      &extensible_param_count
+} generic_function_call_t;
+*/
+/*
+void narrow_candidate_datatypes_c::narrow_function_invocation(symbol_c *fcall, generic_function_call_t fcall_data) {
+void *fill_candidate_datatypes_c::handle_function_call(symbol_c *f_call, symbol_c *function_name, invocation_type_t invocation_type,
+                                                       std::vector <symbol_c *> *candidate_datatypes,
+                                                       std::vector <symbol_c *> *candidate_functions) {
+  */
+void fill_candidate_datatypes_c::handle_function_call(symbol_c *fcall, generic_function_call_t fcall_data) {
+	function_declaration_c *f_decl;
+	list_c *parameter_list;
+	list_c *parameter_candidate_datatypes;
+	symbol_c *returned_parameter_type;
+
+	if (debug) std::cout << "function()\n";
+
+	function_symtable_t::iterator lower = function_symtable.lower_bound(fcall_data.function_name);
+	function_symtable_t::iterator upper = function_symtable.upper_bound(fcall_data.function_name);
+	/* If the name of the function being called is not found in the function symbol table, then this is an invalid call */
+	/* Since the lexical parser already checks for this, then if this occurs then we have an internal compiler error. */
+	if (lower == function_symtable.end()) ERROR;
+	
+	/* Look for all compatible function declarations, and add their return datatypes 
+	 * to the candidate_datatype list of this function invocation. 
+	 *
+	 * If only one function exists, we add its return datatype to the candidate_datatype list,
+	 * even if the parameters passed to it are invalid.
+	 * This guarantees that the remainder of the expression in which the function call is inserted
+	 * is treated as if the function call returns correctly, and therefore does not generate
+	 * spurious error messages.
+	 * Even if the parameters to the function call are invalid, doing this is still safe, as the 
+	 * expressions inside the function call will themselves have erros and will  guarantee that 
+	 * compilation is aborted in stage3 (in print_datatypes_error_c).
+	 */
+	if (function_symtable.multiplicity(fcall_data.function_name) == 1) {
+		f_decl = function_symtable.get_value(lower);
+		returned_parameter_type = base_type(f_decl->type_name);
+		if (add_datatype_to_candidate_list(fcall, returned_parameter_type))
+			/* we only add it to the function declaration list if this entry was not already present in the candidate datatype list! */
+			fcall_data.candidate_functions.push_back(f_decl);
+		
+	}
+	for(; lower != upper; lower++) {
+		bool compatible = false;
+		
+		f_decl = function_symtable.get_value(lower);
+		/* Check if function declaration in symbol_table is compatible with parameters */
+		if (NULL != fcall_data.nonformal_operand_list) compatible=match_nonformal_call(fcall, f_decl);
+		if (NULL != fcall_data.   formal_operand_list) compatible=   match_formal_call(fcall, f_decl);
+		if (compatible) {
+			/* Add the data type returned by the called functions. 
+			 * However, only do this if this data type is not already present in the candidate_datatypes list_c
+			 */
+			returned_parameter_type = base_type(f_decl->type_name);		
+			if (add_datatype_to_candidate_list(fcall, returned_parameter_type))
+				/* we only add it to the function declaration list if this entry was not already present in the candidate datatype list! */
+				fcall_data.candidate_functions.push_back(f_decl);
+		}
+	}
+	if (debug) std::cout << "end_function() [" << fcall->candidate_datatypes.size() << "] result.\n";
+	return;
+}
+
+
+/* handle implicit FB call in IL.
+ * e.g.  CLK ton_var
+ *        CU counter_var
+ */
+void *fill_candidate_datatypes_c::handle_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name, symbol_c *&called_fb_declaration) {
+	symbol_c *fb_type_id = search_varfb_instance_type->get_basetype_id(il_operand);
+  	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
+	if (NULL == fb_type_id) ERROR;
+
+	function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(fb_type_id);
+	if (function_block_type_symtable.end_value() == fb_decl)
+		/* The il_operand is not the name of a FB instance. Most probably it is the name of a variable of some other type.
+		 * this is a semantic error.
+		 */
+		fb_decl = NULL;
+	
+	/* The narrow_candidate_datatypes_c does not rely on this called_fb_declaration pointer being == NULL to conclude that
+	 * we have a datatype incompatibility error, so we set it to fb_decl to allow the print_datatype_error_c to print out
+	 * more informative error messages!
+	 */
+	called_fb_declaration = fb_decl;
+
+	/* This implicit FB call does not change the value stored in the current/default IL variable */
+	/* It does, however, require that the datatype be compatible with the input parameter of the FB being called. 
+	 * If we were to follow the filling & narrowing algorithm correctly (implemented in fill_candidate_datatypes_c
+	 * & narrow_candidate_datatypes_c respectively), we should be restricting the candidate_datatpes to the datatypes
+	 * that are compatible to the FB call. 
+	 * However, doing the above will often result in some very confusing error messages for the user, especially in the case
+	 * in which the FB call is wrong, so the resulting cadidate datatypes is an empty list. In this case, the user would see
+	 * many error messages related to the IL instructions that follow the FB call, even though those IL instructions may be perfectly
+	 * correct.
+	 * For now, we will simply let the narrow_candidate_datatypes_c verify if the datatypes are compatible (something that should be done
+	 * here).
+	 */
+	if (NULL != prev_il_instruction)
+		il_instruction->candidate_datatypes = prev_il_instruction->candidate_datatypes; 
+
+	if (debug) std::cout << "handle_implicit_il_fb_call() [" << prev_il_instruction->candidate_datatypes.size() << "] ==> " << il_instruction->candidate_datatypes.size() << " result.\n";
+	return NULL;
+}
+
+
+
+
+/* handle a binary IL operator, like ADD, SUB, etc... */
+void *fill_candidate_datatypes_c::handle_binary_operator(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr) {
+	if (NULL == l_expr) /* if no prev_il_instruction */
+		return NULL; 
+
+	for(unsigned int i = 0; i < l_expr->candidate_datatypes.size(); i++)
+		for(unsigned int j = 0; j < r_expr->candidate_datatypes.size(); j++)
+			/* NOTE: add_datatype_to_candidate_list() will only really add the datatype if it is != NULL !!! */
+			add_datatype_to_candidate_list(symbol, widening_conversion(l_expr->candidate_datatypes[i], r_expr->candidate_datatypes[j], widen_table));
+	remove_incompatible_datatypes(symbol);
+	if (debug) std::cout <<  "[" << l_expr->candidate_datatypes.size() << "," << r_expr->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
+	return NULL;
+}
+
+
+/* handle a binary ST expression, like '+', '-', etc... */
+void *fill_candidate_datatypes_c::handle_binary_expression(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr) {
+	l_expr->accept(*this);
+	r_expr->accept(*this);
+	return handle_binary_operator(widen_table, symbol, l_expr, r_expr);
+}
+
+
+
+
+/* a helper function... */
+symbol_c *fill_candidate_datatypes_c::base_type(symbol_c *symbol) {
+	/* NOTE: symbol == NULL is valid. It will occur when, for e.g., an undefined/undeclared symbolic_variable is used
+	 *       in the code.
+	 */
+	if (symbol == NULL) return NULL;
+	return (symbol_c *)symbol->accept(search_base_type);
+}
+
+/*********************/
+/* B 1.2 - Constants */
+/*********************/
+/******************************/
+/* B 1.2.1 - Numeric Literals */
+/******************************/
+#define sizeoftype(symbol) get_sizeof_datatype_c::getsize(symbol)
+
+void *fill_candidate_datatypes_c::handle_any_integer(symbol_c *symbol) {
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::bool_type_name,  &search_constant_type_c::safebool_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::byte_type_name,  &search_constant_type_c::safebyte_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::word_type_name,  &search_constant_type_c::safeword_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::dword_type_name, &search_constant_type_c::safedword_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lword_type_name, &search_constant_type_c::safelword_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::sint_type_name,  &search_constant_type_c::safesint_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::int_type_name,   &search_constant_type_c::safeint_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::dint_type_name,  &search_constant_type_c::safedint_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lint_type_name,  &search_constant_type_c::safelint_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::usint_type_name, &search_constant_type_c::safeusint_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::uint_type_name,  &search_constant_type_c::safeuint_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::udint_type_name, &search_constant_type_c::safeudint_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::ulint_type_name, &search_constant_type_c::safeulint_type_name);
+	remove_incompatible_datatypes(symbol);
+	if (debug) std::cout << "ANY_INT [" << symbol->candidate_datatypes.size()<< "]" << std::endl;
+	return NULL;
+}
+
+
+
+void *fill_candidate_datatypes_c::handle_any_real(symbol_c *symbol) {
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::real_type_name,  &search_constant_type_c::safereal_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lreal_type_name, &search_constant_type_c::safelreal_type_name);
+	remove_incompatible_datatypes(symbol);
+	if (debug) std::cout << "ANY_REAL [" << symbol->candidate_datatypes.size() << "]" << std::endl;
+	return NULL;
+}
+
+
+
+void *fill_candidate_datatypes_c::handle_any_literal(symbol_c *symbol, symbol_c *symbol_value, symbol_c *symbol_type) {
+	symbol_value->accept(*this);
+	if (search_in_candidate_datatype_list(symbol_type, symbol_value->candidate_datatypes) >= 0)
+		add_datatype_to_candidate_list(symbol, symbol_type);
+	remove_incompatible_datatypes(symbol);
+	if (debug) std::cout << "XXX_LITERAL [" << symbol->candidate_datatypes.size() << "]\n";
+	return NULL;
+}
+
+
+
+void *fill_candidate_datatypes_c::visit(    real_c *symbol) {return handle_any_real(symbol);}
+void *fill_candidate_datatypes_c::visit(neg_real_c *symbol) {return handle_any_real(symbol);}
+
+
+
+void *fill_candidate_datatypes_c::visit(neg_integer_c *symbol) {
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::int_type_name, &search_constant_type_c::safeint_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::sint_type_name, &search_constant_type_c::safesint_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::dint_type_name, &search_constant_type_c::safedint_type_name);
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lint_type_name, &search_constant_type_c::safelint_type_name);
+	remove_incompatible_datatypes(symbol);
+	if (debug) std::cout << "neg ANY_INT [" << symbol->candidate_datatypes.size() << "]" << std::endl;
+	return NULL;
+}
+
+
+
+void *fill_candidate_datatypes_c::visit(integer_c        *symbol) {return handle_any_integer(symbol);}
+void *fill_candidate_datatypes_c::visit(binary_integer_c *symbol) {return handle_any_integer(symbol);}
+void *fill_candidate_datatypes_c::visit(octal_integer_c  *symbol) {return handle_any_integer(symbol);}
+void *fill_candidate_datatypes_c::visit(hex_integer_c    *symbol) {return handle_any_integer(symbol);}
+
+
+
+// SYM_REF2(integer_literal_c, type, value)
+/*
+ * integer_literal:
+ *   integer_type_name '#' signed_integer
+ * | integer_type_name '#' binary_integer
+ * | integer_type_name '#' octal_integer
+ * | integer_type_name '#' hex_integer
+ */
+void *fill_candidate_datatypes_c::visit(   integer_literal_c *symbol) {return handle_any_literal(symbol, symbol->value, symbol->type);}
+void *fill_candidate_datatypes_c::visit(      real_literal_c *symbol) {return handle_any_literal(symbol, symbol->value, symbol->type);}
+void *fill_candidate_datatypes_c::visit(bit_string_literal_c *symbol) {return handle_any_literal(symbol, symbol->value, symbol->type);}
+
+void *fill_candidate_datatypes_c::visit(   boolean_literal_c *symbol) {
+	if (NULL != symbol->type) return handle_any_literal(symbol, symbol->value, symbol->type);
+
+	symbol->value->accept(*this);
+	symbol->candidate_datatypes = symbol->value->candidate_datatypes;
+	return NULL;
+}
+
+
+void *fill_candidate_datatypes_c::visit(boolean_true_c *symbol) {
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::bool_type_name, &search_constant_type_c::safebool_type_name);
+	return NULL;
+}
+
+void *fill_candidate_datatypes_c::visit(boolean_false_c *symbol) {
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::bool_type_name, &search_constant_type_c::safebool_type_name);
+	return NULL;
+}
+
+/*******************************/
+/* B.1.2.2   Character Strings */
+/*******************************/
+void *fill_candidate_datatypes_c::visit(double_byte_character_string_c *symbol) {
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::wstring_type_name, &search_constant_type_c::safewstring_type_name);
+	return NULL;
+}
+
+void *fill_candidate_datatypes_c::visit(single_byte_character_string_c *symbol) {
+	add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::string_type_name, &search_constant_type_c::safestring_type_name);
+	return NULL;
+}
+
+/***************************/
+/* B 1.2.3 - Time Literals */
+/***************************/
+/************************/
+/* B 1.2.3.1 - Duration */
+/************************/
+void *fill_candidate_datatypes_c::visit(duration_c *symbol) {
+	/* TODO: check whether the literal follows the rules specified in section '2.2.3.1 Duration' of the standard! */
+	
+	add_datatype_to_candidate_list(symbol, symbol->type_name);
+	if (debug) std::cout << "TIME_LITERAL [" << symbol->candidate_datatypes.size() << "]\n";
+	return NULL;
+}
+
+/************************************/
+/* B 1.2.3.2 - Time of day and Date */
+/************************************/
+void *fill_candidate_datatypes_c::visit(time_of_day_c   *symbol) {add_datatype_to_candidate_list(symbol, symbol->type_name); return NULL;}
+void *fill_candidate_datatypes_c::visit(date_c          *symbol) {add_datatype_to_candidate_list(symbol, symbol->type_name); return NULL;}
+void *fill_candidate_datatypes_c::visit(date_and_time_c *symbol) {add_datatype_to_candidate_list(symbol, symbol->type_name); return NULL;}
+
+/**********************/
+/* B 1.3 - Data types */
+/**********************/
+/********************************/
+/* B 1.3.3 - Derived data types */
+/********************************/
+
+/* simple_specification ASSIGN constant */
+// SYM_REF2(simple_spec_init_c, simple_specification, constant)
+void *fill_candidate_datatypes_c::visit(simple_spec_init_c *symbol) {
+	if (NULL != symbol->constant) symbol->constant->accept(*this);
+	add_datatype_to_candidate_list(symbol->simple_specification, base_type(symbol->simple_specification));
+	symbol->candidate_datatypes = symbol->simple_specification->candidate_datatypes;
+	/* NOTE: Even if the constant and the type are of incompatible data types, we let the
+	 *       simple_spec_init_c object inherit the data type of the type declaration (simple_specification)
+	 *       This will let us produce more informative error messages when checking data type compatibility
+	 *       with located variables (AT %QW3.4 : WORD).
+	 */
+	// if (NULL != symbol->constant) intersect_candidate_datatype_list(symbol /*origin, dest.*/, symbol->constant /*with*/);
+	return NULL;
+}
+
+/*  signed_integer DOTDOT signed_integer */
+// SYM_REF2(subrange_c, lower_limit, upper_limit)
+void *fill_candidate_datatypes_c::visit(subrange_c *symbol) {
+	symbol->lower_limit->accept(*this);
+	symbol->upper_limit->accept(*this);
+	
+	for (unsigned int u = 0; u < symbol->upper_limit->candidate_datatypes.size(); u++) {
+		for(unsigned int l = 0; l < symbol->lower_limit->candidate_datatypes.size(); l++) {
+			if (is_type_equal(symbol->upper_limit->candidate_datatypes[u], symbol->lower_limit->candidate_datatypes[l]))
+				add_datatype_to_candidate_list(symbol, symbol->lower_limit->candidate_datatypes[l]);
+		}
+	}
+	return NULL;
+}
+
+/*  TYPE type_declaration_list END_TYPE */
+// SYM_REF1(data_type_declaration_c, type_declaration_list)
+/* NOTE: Not required. already handled by iterator_visitor_c base class */
+/*
+void *fill_candidate_datatypes_c::visit(data_type_declaration_c *symbol) {
+	symbol->type_declaration_list->accept(*this);
+	return NULL;
+}
+*/
+
+void *fill_candidate_datatypes_c::visit(enumerated_value_c *symbol) {
+	symbol_c *enumerated_type;
+
+	if (NULL != symbol->type)
+		enumerated_type = symbol->type;
+	else {
+		enumerated_type = enumerated_value_symtable.find_value(symbol->value);
+		if (enumerated_type == enumerated_value_symtable.end_value())
+			enumerated_type = NULL;
+	}
+	enumerated_type = base_type(enumerated_type);
+	if (NULL != enumerated_type)
+		add_datatype_to_candidate_list(symbol, enumerated_type);
+
+	if (debug) std::cout << "ENUMERATE [" << symbol->candidate_datatypes.size() << "]\n";
+	return NULL;
+}
+
+
+/*********************/
+/* B 1.4 - Variables */
+/*********************/
+void *fill_candidate_datatypes_c::visit(symbolic_variable_c *symbol) {
+	add_datatype_to_candidate_list(symbol, search_varfb_instance_type->get_basetype_decl(symbol)); /* will only add if non NULL */
+	if (debug) std::cout << "VAR [" << symbol->candidate_datatypes.size() << "]\n";
+	return NULL;
+}
+
+
+/********************************************/
+/* B 1.4.1 - Directly Represented Variables */
+/********************************************/
+void *fill_candidate_datatypes_c::visit(direct_variable_c *symbol) {
+	/* Comment added by mario:
+	 * The following code is safe, actually, as the lexical parser guarantees the correct IEC61131-3 syntax was used.
+	 */
+	/* However, we should probably add an assertion in case we later change the lexical parser! */
+	/* if (symbol->value == NULL) ERROR;
+	 * if (symbol->value[0] == '\0') ERROR;
+	 * if (symbol->value[1] == '\0') ERROR;
+	 */
+	switch (symbol->value[2]) {
+		case 'x': case 'X': /* bit   -  1 bit  */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::bool_type_name);  break;
+		case 'b': case 'B': /* byte  -  8 bits */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::byte_type_name);  break;
+		case 'w': case 'W': /* word  - 16 bits */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::word_type_name);  break;
+		case 'd': case 'D': /* dword - 32 bits */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::dword_type_name); break;
+		case 'l': case 'L': /* lword - 64 bits */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::lword_type_name); break;
+        	          /* if none of the above, then the empty string was used <=> boolean */
+		default:                        add_datatype_to_candidate_list(symbol, &search_constant_type_c::bool_type_name);  break;
+	}
+	return NULL;
+}
+
+/*************************************/
+/* B 1.4.2 - Multi-element variables */
+/*************************************/
+/*  subscripted_variable '[' subscript_list ']' */
+// SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
+void *fill_candidate_datatypes_c::visit(array_variable_c *symbol) {
+	/* get the declaration of the data type __stored__ in the array... */
+	/* if we were to want the data type of the array itself, then we should call_param_name
+	 * search_varfb_instance_type->get_basetype_decl(symbol->subscripted_variable)
+	 */
+	symbol_c *result = search_varfb_instance_type->get_basetype_decl(symbol);
+	if (NULL != result) add_datatype_to_candidate_list(symbol, result);
+	
+	/* recursively call the subscript list, so we can check the data types of the expressions used for the subscripts */
+	symbol->subscript_list->accept(*this);
+
+	if (debug) std::cout << "ARRAY_VAR [" << symbol->candidate_datatypes.size() << "]\n";	
+	return NULL;
+}
+
+
+/* subscript_list ',' subscript */
+// SYM_LIST(subscript_list_c)
+/* NOTE: we inherit from iterator visitor, so we do not need to implement this method... */
+// void *fill_candidate_datatypes_c::visit(subscript_list_c *symbol)
+
+
+/*  record_variable '.' field_selector */
+/*  WARNING: input and/or output variables of function blocks
+ *           may be accessed as fields of a structured variable!
+ *           Code handling a structured_variable_c must take
+ *           this into account!
+ */
+// SYM_REF2(structured_variable_c, record_variable, field_selector)
+/* NOTE: We do not need to recursively determine the data types of each field_selector, as the search_varfb_instance_type
+ * will do that for us. So we determine the candidate datatypes only for the full structured_variable.
+ */
+void *fill_candidate_datatypes_c::visit(structured_variable_c *symbol) {
+	add_datatype_to_candidate_list(symbol, search_varfb_instance_type->get_basetype_decl(symbol));  /* will only add if non NULL */
+	return NULL;
+}
+
+
+
+/******************************************/
+/* B 1.4.3 - Declaration & Initialisation */
+/******************************************/
+
+void *fill_candidate_datatypes_c::visit(var1_list_c *symbol) {
+#if 0   /* We don't really need to set the datatype of each variable. We just check the declaration itself! */
+  for(int i = 0; i < symbol->n; i++) {
+    add_datatype_to_candidate_list(symbol->elements[i], search_varfb_instance_type->get_basetype_decl(symbol->elements[i])); /* will only add if non NULL */
+  }
+#endif
+  return NULL;
+}  
+
+
+/*  AT direct_variable */
+// SYM_REF1(location_c, direct_variable)
+void *fill_candidate_datatypes_c::visit(location_c *symbol) {
+ /* This is a special situation. 
+  *
+  * The reason is that a located variable may be declared to be of any data type, as long as the size
+  * matches the location (lines 1 3 and 4 of table 17). For example:
+  *   var1 AT %MB42.0 : BYTE;
+  *   var1 AT %MB42.1 : SINT;
+  *   var1 AT %MB42.2 : USINT;
+  *   var1 AT %MW64   : INT;
+  *   var1 AT %MD56   : DINT;
+  *   var1 AT %MD57   : REAL;
+  *  are all valid!!
+  *
+  *  However, when used inside an expression, the direct variable (uses the same syntax as the location
+  *  of a located variable) is limited to the following (ANY_BIT) data types:
+  *    %MX --> BOOL
+  *    %MB --> BYTE
+  *    %MW --> WORD
+  *    %MD --> DWORD
+  *    %ML --> LWORD
+  *
+  *  So, in order to be able to analyse expressions with direct variables
+  *   e.g:  var1 := 66 OR %MW34
+  *  where the direct variable may only take the ANY_BIT data types, the fill_candidate_datatypes_c
+  *  considers that only the ANY_BIT data types are allowed for a direct variable.
+  *  However, it appears from the examples in the standard (lines 1 3 and 4 of table 17)
+  *  a location may have any data type (presumably as long as the size in bits match).
+  *  For this reason, a location_c may have more allowable data types than a direct_variable_c