merging with Laurent's changes.
authorMario de Sousa <msousa@fe.up.pt>
Sat, 31 Mar 2012 15:36:08 +0100
changeset 497 5b7a0d9838d2
parent 496 fa43fed1084c (diff)
parent 405 7b5d67d1aeef (current diff)
child 498 0637a4490c8c
merging with Laurent's changes.
stage4/generate_c/generate_c_il.cc
stage4/generate_c/generate_c_st.cc
--- a/absyntax/absyntax.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/absyntax/absyntax.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -61,6 +61,7 @@
   this->last_line    = last_line;
   this->last_column  = last_column;
   this->last_order   = last_order;
+  this->datatype     = NULL;
 }
 
 
@@ -130,18 +131,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 Feb 21 22:31:38 2012 +0100
+++ b/absyntax/absyntax.def	Sat Mar 31 15:36:08 2012 +0100
@@ -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)
@@ -913,18 +900,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' and 'overloaded_return_type' are 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; symbol_c *overloaded_return_type; 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 +930,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' and 'overloaded_return_type' 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; symbol_c *overloaded_return_type; 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 +946,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 +971,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 +1041,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 +1052,36 @@
 
 /*    formal_param_list -> may be NULL ! */
 /* nonformal_param_list -> may be NULL ! */
-/* NOTE: The parameters 'called_function_declaration' and 'overloaded_return_type' are 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; symbol_c *overloaded_return_type; 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 +1106,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 Feb 21 22:31:38 2012 +0100
+++ b/absyntax/absyntax.hh	Sat Mar 31 15:36:08 2012 +0100
@@ -47,6 +47,7 @@
 
 
 #include <stdio.h> // required for NULL
+#include <vector>
 
 /* Forward declaration of the visitor interface
  * dclared in the visitor.hh file
@@ -76,6 +77,14 @@
     int last_column;
     const char *last_file;  /* filename referenced by last line/column */
     long int last_order;    /* relative order in which it is read by lexcial analyser */
+    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;    
+
 
   public:
     /* default constructor */
@@ -125,6 +134,8 @@
      /* 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);
+     /* remove element at position pos. */
+    virtual void remove_element(int pos = 0);
 };
 
 
--- a/absyntax/visitor.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/absyntax/visitor.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -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 Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/Makefile.am	Sat Mar 31 15:36:08 2012 +0100
@@ -13,6 +13,7 @@
 	function_param_iterator.cc \
 	get_function_type.cc \
 	get_sizeof_datatype.cc \
+	search_il_label.cc \
 	search_base_type.cc \
 	search_constant_type.cc \
 	search_expression_type.cc \
--- a/absyntax_utils/Makefile.in	Tue Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/Makefile.in	Sat Mar 31 15:36:08 2012 +0100
@@ -78,8 +78,8 @@
 	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) \
-	search_constant_type.$(OBJEXT) \
+	get_sizeof_datatype.$(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) \
 	search_varfb_instance_type.$(OBJEXT) \
@@ -213,6 +213,7 @@
 	function_param_iterator.cc \
 	get_function_type.cc \
 	get_sizeof_datatype.cc \
+	search_il_label.cc \
 	search_base_type.cc \
 	search_constant_type.cc \
 	search_expression_type.cc \
@@ -319,6 +320,7 @@
 @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 Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/absyntax_utils.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -294,7 +294,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 Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/absyntax_utils.hh	Sat Mar 31 15:36:08 2012 +0100
@@ -120,7 +120,7 @@
 #include "add_en_eno_param_decl.hh"
 #include "get_sizeof_datatype.hh"
 #include "get_function_type.h"
-
+#include "search_il_label.hh"
 
 /***********************************************************************/
 /***********************************************************************/
--- a/absyntax_utils/function_call_param_iterator.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/function_call_param_iterator.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -184,6 +184,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 +202,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 +214,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 +236,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 +348,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 +365,7 @@
   if (NULL == symb_var)
     ERROR;
 
+  current_assign_direction = assign_out;
   return handle_parameter_assignment(symb_var->var_name, symbol->data_sink);
 }
 
@@ -459,6 +470,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 +478,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 +577,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 +588,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 Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/function_call_param_iterator.hh	Sat Mar 31 15:36:08 2012 +0100
@@ -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 Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/function_param_iterator.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -206,7 +206,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 +225,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 +251,7 @@
     return current_param_name;
   }
   
+  last_returned_parameter = NULL; 
   param_count = 0;
   en_eno_param_implicit = false;
   next_param++;
@@ -268,6 +272,7 @@
   if (identifier == NULL)
     ERROR;
   current_param_name = identifier;
+  last_returned_parameter = current_param_name; 
   return current_param_name;
 }
 
@@ -281,35 +286,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 +346,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 Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/function_param_iterator.hh	Sat Mar 31 15:36:08 2012 +0100
@@ -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/get_sizeof_datatype.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/get_sizeof_datatype.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -80,6 +80,7 @@
 /* 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
+#include <errno.h>
 
 
 #define ERROR error_exit(__FILE__,__LINE__)
@@ -158,8 +159,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 +335,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 ! */
--- a/absyntax_utils/search_base_type.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/search_base_type.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -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
@@ -55,16 +55,29 @@
 
 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 +91,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 */
 /*********************/
@@ -205,8 +247,7 @@
 /* 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;
+  return (void *)symbol;
 }
 
 /* enumerated_type_name '#' identifier */
@@ -222,14 +263,16 @@
 /* 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);
+  return symbol;
 }
 
 /* helper symbol for array_specification */
--- a/absyntax_utils/search_base_type.hh	Tue Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/search_base_type.hh	Sat Mar 31 15:36:08 2012 +0100
@@ -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
--- a/absyntax_utils/search_constant_type.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/search_constant_type.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -133,6 +133,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 +161,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 Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/search_constant_type.hh	Sat Mar 31 15:36:08 2012 +0100
@@ -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 */
   /**********************/
@@ -79,7 +91,6 @@
 
 /* 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 +107,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);
@@ -164,5 +191,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	Sat Mar 31 15:36:08 2012 +0100
@@ -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	Sat Mar 31 15:36:08 2012 +0100
@@ -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 Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/search_var_instance_decl.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -77,10 +77,14 @@
   return (symbol_c *)search_scope->accept(*this);
 }
 
-unsigned int search_var_instance_decl_c::get_vartype(void) {
+unsigned int search_var_instance_decl_c::get_vartype(symbol_c *variable_instance_name) {
+  this->current_vartype = none_vt;
+  this->search_name = variable_instance_name;
+  search_scope->accept(*this);
   return current_vartype;
 }
 
+
 /***************************/
 /* B 0 - Programming Model */
 /***************************/
--- a/absyntax_utils/search_var_instance_decl.hh	Tue Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/search_var_instance_decl.hh	Sat Mar 31 15:36:08 2012 +0100
@@ -77,7 +77,8 @@
   public:
     search_var_instance_decl_c(symbol_c *search_scope);
     symbol_c *get_decl(symbol_c *variable_instance_name);
-    unsigned int get_vartype(void);
+    
+    unsigned int get_vartype(symbol_c *variable_instance_name);
 
   public:
 
--- a/absyntax_utils/search_varfb_instance_type.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/search_varfb_instance_type.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -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,155 @@
  *
  * 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;
+  this->is_complex = false;
+}
+
+
 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!
-   */
-  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;
+  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) {
-  symbol_c *res = get_type_decl(variable_name);
-  if (NULL == res) return NULL;
-  return (symbol_c *)base_type(res);
+  this->init();
+  variable_name->accept(*this);
+  return current_basetype_decl;
 }  
 
 
+
+
+
 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;
-}
+  this->init();
+  return search_var_instance_decl.get_vartype(variable_name);
+}
+
+
 
 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.
+
+
+
+/*************************/
+/* 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!
    */
-  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
@@ -304,51 +234,42 @@
 /* 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! */
@@ -364,6 +285,73 @@
 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) {
+  this->is_complex = true;
+
+  /* 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);
+  
+  /* Now we determine the 'Stored_Data_Type', i.e. the data type of the variable stored in the array. */
+  if (NULL != current_basetype_decl) {
+    current_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!
+ */
+// SYM_REF2(structured_variable_c, record_variable, field_selector)
+void *search_varfb_instance_type_c::visit(structured_variable_c *symbol) {
+  this->is_complex = true;
+  symbol->record_variable->accept(*this);
+  
+  /* 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 != current_basetype_decl) {
+    current_field_selector = symbol->field_selector;
+    current_basetype_decl->accept(*this);
+    current_field_selector = NULL;
+  }
+  
+  return NULL;
+}
+
+
 
 /**************************************/
 /* B.1.5 - Program organization units */
@@ -371,46 +359,18 @@
 /*****************************/
 /* 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;
+}
--- a/absyntax_utils/search_varfb_instance_type.hh	Tue Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/search_varfb_instance_type.hh	Sat Mar 31 15:36:08 2012 +0100
@@ -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,41 +77,44 @@
  *
  * 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;
+    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;
+
     bool is_complex;
+    
+    /* 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_basetype_id  (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.
+    /* NOTE: I have a feeling that 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);
@@ -125,17 +128,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);
     
@@ -170,7 +173,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 */
     /**************************************/
--- a/absyntax_utils/type_initial_value.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/type_initial_value.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -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 Feb 21 22:31:38 2012 +0100
+++ b/absyntax_utils/type_initial_value.hh	Sat Mar 31 15:36:08 2012 +0100
@@ -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/lib/create_standard_function_txt.sh	Tue Feb 21 22:31:38 2012 +0100
+++ b/lib/create_standard_function_txt.sh	Sat Mar 31 15:36:08 2012 +0100
@@ -711,6 +711,13 @@
     /**************/
 /* Should be for: ANY_ELEMENTARY, but we currently do not support WSTRING yet... */
 /* However, we can call __ANY_ELEMENTARY since the __ANY_STRING macro does not call DO(WSTRING) */
+/* NOTE (by mjs) : The following declaration is worng, as it assumes that only 2 parameter may be used!
+ *                 The NE function is actually an extensible function, that may be called with more than 2 parameters!
+ *                 This needs to be fixed!!
+ *       The correct definition is:
+ *   __function_1e(NE, BOOL, IN, TYPENAME, 1)             
+ *   __function_1e(NE_##TYPENAME, BOOL, IN, TYPENAME, 1) 
+ */
 #define __iec_(TYPENAME) \
 __function_2p(NE, BOOL, IN1, TYPENAME, IN2, TYPENAME)            /* overloaded function */ \
 __function_2p(NE_##TYPENAME, BOOL, IN1, TYPENAME, IN2, TYPENAME) /* explicitly typed function */
--- a/lib/iec_std_lib.h	Tue Feb 21 22:31:38 2012 +0100
+++ b/lib/iec_std_lib.h	Sat Mar 31 15:36:08 2012 +0100
@@ -1753,6 +1753,10 @@
     /*     NE     */
     /**************/
 
+/* NOTE (by mjs) : The following declaration is worng, as it assumes that only 2 parameter may be used!
+ *                 The NE function is actually an extensible function, that may be called with more than 2 parameters!
+ *                 This needs to be fixed!!
+ */
 #define __ne_num(fname, TYPENAME) \
 static inline BOOL fname(EN_ENO_PARAMS, TYPENAME op1, TYPENAME op2){\
   TEST_EN(BOOL)\
--- a/readme	Tue Feb 21 22:31:38 2012 +0100
+++ b/readme	Sat Mar 31 15:36:08 2012 +0100
@@ -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 Feb 21 22:31:38 2012 +0100
+++ b/stage1_2/iec_bison.yy	Sat Mar 31 15:36:08 2012 +0100
@@ -250,17 +250,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 +261,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
+
 }
 
 
@@ -2797,7 +2791,7 @@
 | signed_integer DOTDOT error
 	{$$ = NULL;
 	 if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no value defined for upper bound in subrange definition.");}
-	 else {print_err_msg(locf(@3), locl(@3), "invalid value for upper bound in subrange definition."); yyclearin;}
+	 else {print_err_msg(locf(@3), locl(@3), "invalid value for lower bound in subrange definition."); yyclearin;}
 	 yyerrok;
 	}
 /* ERROR_CHECK_END */
@@ -3407,7 +3401,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(@$));}
 ;
 
 
@@ -6643,8 +6637,11 @@
 
 il_simple_instruction:
   il_simple_operation eol_list
+	{$$ = new il_simple_instruction_c($1, locloc(@$));}
 | il_expression eol_list
+	{$$ = new il_simple_instruction_c($1, locloc(@$));}
 | il_formal_funct_call eol_list
+	{$$ = new il_simple_instruction_c($1, locloc(@$));}
 /* ERROR_CHECK_BEGIN */
 | il_expression error
   {$$ = NULL; print_err_msg(locl(@1), locf(@2), "EOL missing after expression IL instruction."); yyerrok;}
--- a/stage1_2/iec_flex.ll	Tue Feb 21 22:31:38 2012 +0100
+++ b/stage1_2/iec_flex.ll	Sat Mar 31 15:36:08 2012 +0100
@@ -171,8 +171,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 +209,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...
--- a/stage3/Makefile.am	Tue Feb 21 22:31:38 2012 +0100
+++ b/stage3/Makefile.am	Sat Mar 31 15:36:08 2012 +0100
@@ -4,5 +4,9 @@
 
 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
 
--- a/stage3/Makefile.in	Tue Feb 21 22:31:38 2012 +0100
+++ b/stage3/Makefile.in	Sat Mar 31 15:36:08 2012 +0100
@@ -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,10 @@
 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)
 libstage3_a_OBJECTS = $(am_libstage3_a_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/config
 depcomp = $(SHELL) $(top_srcdir)/config/depcomp
@@ -188,7 +191,11 @@
 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
 
 all: all-am
 
@@ -267,8 +274,12 @@
 distclean-compile:
 	-rm -f *.tab.c
 
+@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)/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	Sat Mar 31 15:36:08 2012 +0100
@@ -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/datatype_functions.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -0,0 +1,790 @@
+/*
+ *  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>
+// #include <algorithm>
+
+
+
+
+
+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) {
+	  int i = 1;
+  }
+  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        *******/
+/**************************************************************/
+/**************************************************************/
+/**************************************************************/
+
+
+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,      widen_entry::deprecated },
+    /* 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,      widen_entry::deprecated },
+    { &search_constant_type_c::dt_type_name,            &search_constant_type_c::time_type_name,            &search_constant_type_c::dt_type_name,       widen_entry::deprecated },         
+    /* 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,       widen_entry::deprecated },         
+
+    /*******************************/
+    /* 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,      widen_entry::deprecated },
+    /* 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,      widen_entry::deprecated },
+    { &search_constant_type_c::safedt_type_name,        &search_constant_type_c::time_type_name,            &search_constant_type_c::dt_type_name,       widen_entry::deprecated },         
+    /* 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,       widen_entry::deprecated },         
+
+    /********************************/
+    /* 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,      widen_entry::deprecated },
+    /* 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,      widen_entry::deprecated },
+    { &search_constant_type_c::dt_type_name,            &search_constant_type_c::safetime_type_name,        &search_constant_type_c::dt_type_name,       widen_entry::deprecated },         
+    /* 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,       widen_entry::deprecated },         
+
+    /*************************************/
+    /* 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,  widen_entry::deprecated },
+    /* 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,  widen_entry::deprecated },
+    { &search_constant_type_c::safedt_type_name,        &search_constant_type_c::safetime_type_name,        &search_constant_type_c::safedt_type_name,   widen_entry::deprecated },         
+    /* 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,   widen_entry::deprecated },
+   
+    { 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,     widen_entry::deprecated },
+    { &search_constant_type_c::tod_type_name,           &search_constant_type_c::time_type_name,            &search_constant_type_c::tod_type_name,      widen_entry::deprecated },
+    { &search_constant_type_c::tod_type_name,           &search_constant_type_c::tod_type_name,             &search_constant_type_c::time_type_name,     widen_entry::deprecated },
+    { &search_constant_type_c::dt_type_name,            &search_constant_type_c::time_type_name,            &search_constant_type_c::dt_type_name,       widen_entry::deprecated },
+    { &search_constant_type_c::dt_type_name,            &search_constant_type_c::dt_type_name,              &search_constant_type_c::time_type_name,     widen_entry::deprecated },        
+
+    /*******************************/
+    /* 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,     widen_entry::deprecated },
+    { &search_constant_type_c::safetod_type_name,       &search_constant_type_c::time_type_name,            &search_constant_type_c::tod_type_name,      widen_entry::deprecated },
+    { &search_constant_type_c::safetod_type_name,       &search_constant_type_c::tod_type_name,             &search_constant_type_c::time_type_name,     widen_entry::deprecated },
+    { &search_constant_type_c::safedt_type_name,        &search_constant_type_c::time_type_name,            &search_constant_type_c::dt_type_name,       widen_entry::deprecated },
+    { &search_constant_type_c::safedt_type_name,        &search_constant_type_c::dt_type_name,              &search_constant_type_c::time_type_name,     widen_entry::deprecated },        
+
+    /********************************/
+    /* 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,     widen_entry::deprecated },
+    { &search_constant_type_c::tod_type_name,           &search_constant_type_c::safetime_type_name,        &search_constant_type_c::tod_type_name,      widen_entry::deprecated },
+    { &search_constant_type_c::tod_type_name,           &search_constant_type_c::safetod_type_name,         &search_constant_type_c::time_type_name,     widen_entry::deprecated },
+    { &search_constant_type_c::dt_type_name,            &search_constant_type_c::safetime_type_name,        &search_constant_type_c::dt_type_name,       widen_entry::deprecated },
+    { &search_constant_type_c::dt_type_name,            &search_constant_type_c::safedt_type_name,          &search_constant_type_c::time_type_name,     widen_entry::deprecated },        
+
+    /*************************************/
+    /* 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, widen_entry::deprecated },
+    { &search_constant_type_c::safetod_type_name,       &search_constant_type_c::safetime_type_name,        &search_constant_type_c::safetod_type_name,  widen_entry::deprecated },
+    { &search_constant_type_c::safetod_type_name,       &search_constant_type_c::safetod_type_name,         &search_constant_type_c::safetime_type_name, widen_entry::deprecated },
+    { &search_constant_type_c::safedt_type_name,        &search_constant_type_c::safetime_type_name,        &search_constant_type_c::safedt_type_name,   widen_entry::deprecated },
+    { &search_constant_type_c::safedt_type_name,        &search_constant_type_c::safedt_type_name,          &search_constant_type_c::safetime_type_name, widen_entry::deprecated },        
+
+    { 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,     widen_entry::deprecated }, \
+    { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::time_type_name,     widen_entry::deprecated }, \
+    { &search_constant_type_c::time_type_name,          &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::time_type_name,     widen_entry::deprecated }, \
+    { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::safetime_type_name, widen_entry::deprecated }, \
+    /* 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,     widen_entry::deprecated }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::time_type_name,            &search_constant_type_c::time_type_name,     widen_entry::deprecated }, \
+    { &search_constant_type_c::TYPE##_type_name,        &search_constant_type_c::safetime_type_name,        &search_constant_type_c::time_type_name,     widen_entry::deprecated }, \
+    { &search_constant_type_c::safe##TYPE##_type_name,  &search_constant_type_c::safetime_type_name,        &search_constant_type_c::safetime_type_name, widen_entry::deprecated },
+    __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,     widen_entry::deprecated }, \
+    { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::TYPE##_type_name,          &search_constant_type_c::time_type_name,     widen_entry::deprecated }, \
+    { &search_constant_type_c::time_type_name,          &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::time_type_name,     widen_entry::deprecated }, \
+    { &search_constant_type_c::safetime_type_name,      &search_constant_type_c::safe##TYPE##_type_name,    &search_constant_type_c::safetime_type_name, widen_entry::deprecated },
+    __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, 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;
+}
+
+
+
+
+
+
+
+/* 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	Sat Mar 31 15:36:08 2012 +0100
@@ -0,0 +1,215 @@
+/*
+ *  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, 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	Sat Mar 31 15:36:08 2012 +0100
@@ -0,0 +1,1391 @@
+/*
+ *  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)
+ *
+ */
+
+
+/*
+ *  Fill candidate list of data types for all symbols
+ */
+
+#include "fill_candidate_datatypes.hh"
+#include "datatype_functions.hh"
+#include <typeinfo>
+#include <list>
+#include <string>
+#include <string.h>
+#include <strings.h>
+
+/* 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;
+}
+    
+
+/* 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));
+
+	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) {
+	int calc_size = sizeoftype(symbol);
+
+	if (calc_size <= sizeoftype(&search_constant_type_c::bool_type_name))
+	        add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::bool_type_name, &search_constant_type_c::safebool_type_name);
+	if (calc_size <= sizeoftype(&search_constant_type_c::byte_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::byte_type_name, &search_constant_type_c::safebyte_type_name);
+	if (calc_size <= sizeoftype(&search_constant_type_c::word_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::word_type_name, &search_constant_type_c::safeword_type_name);
+	if (calc_size <= sizeoftype(&search_constant_type_c::dword_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::dword_type_name, &search_constant_type_c::safedword_type_name);
+	if (calc_size <= sizeoftype(&search_constant_type_c::lword_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lword_type_name, &search_constant_type_c::safelword_type_name);
+
+	if (calc_size < sizeoftype(&search_constant_type_c::sint_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::sint_type_name, &search_constant_type_c::safesint_type_name);
+	if (calc_size < sizeoftype(&search_constant_type_c::int_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::int_type_name, &search_constant_type_c::safeint_type_name);
+	if (calc_size < sizeoftype(&search_constant_type_c::dint_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::dint_type_name, &search_constant_type_c::safedint_type_name);
+	if (calc_size < sizeoftype(&search_constant_type_c::lint_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lint_type_name, &search_constant_type_c::safelint_type_name);
+	if (calc_size <= sizeoftype(&search_constant_type_c::usint_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::usint_type_name, &search_constant_type_c::safeusint_type_name);
+	if (calc_size <= sizeoftype(&search_constant_type_c::uint_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::uint_type_name, &search_constant_type_c::safeuint_type_name);
+	if (calc_size <= sizeoftype(&search_constant_type_c::udint_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::udint_type_name, &search_constant_type_c::safeudint_type_name);
+	if (calc_size <= sizeoftype(&search_constant_type_c::ulint_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::ulint_type_name, &search_constant_type_c::safeulint_type_name);
+
+	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) {
+	int calc_size = sizeoftype(symbol);
+
+	if (calc_size <= sizeoftype(&search_constant_type_c::real_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::real_type_name,  &search_constant_type_c::safereal_type_name);
+	if (calc_size <= sizeoftype(&search_constant_type_c::lreal_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lreal_type_name, &search_constant_type_c::safelreal_type_name);
+	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);
+	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) {
+	int calc_size = sizeoftype(symbol);
+
+	if (calc_size <= sizeoftype(&search_constant_type_c::int_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::int_type_name, &search_constant_type_c::safeint_type_name);
+	if (calc_size <= sizeoftype(&search_constant_type_c::sint_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::sint_type_name, &search_constant_type_c::safesint_type_name);
+	if (calc_size <= sizeoftype(&search_constant_type_c::dint_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::dint_type_name, &search_constant_type_c::safedint_type_name);
+	if (calc_size <= sizeoftype(&search_constant_type_c::lint_type_name))
+		add_2datatypes_to_candidate_list(symbol, &search_constant_type_c::lint_type_name, &search_constant_type_c::safelint_type_name);
+	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 */
+/********************************/
+/*  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': /* bit   -  1 bit  */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::bool_type_name);  break;
+		case 'B': /* byte  -  8 bits */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::byte_type_name);  break;
+		case 'W': /* word  - 16 bits */ add_datatype_to_candidate_list(symbol, &search_constant_type_c::word_type_name);  break;
+		case 'D': /* dword - 32 bits */	add_datatype_to_candidate_list(symbol, &search_constant_type_c::dword_type_name); break;
+		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.5 Program organization units */
+/************************************/
+/*********************/
+/* B 1.5.1 Functions */
+/*********************/
+void *fill_candidate_datatypes_c::visit(function_declaration_c *symbol) {
+	if (debug) printf("Filling candidate data types list of function %s\n", ((token_c *)(symbol->derived_function_name))->value);
+	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
+	symbol->var_declarations_list->accept(*this);
+	symbol->function_body->accept(*this);
+	delete search_varfb_instance_type;
+	search_varfb_instance_type = NULL;
+	return NULL;
+}
+
+/***************************/
+/* B 1.5.2 Function blocks */
+/***************************/
+void *fill_candidate_datatypes_c::visit(function_block_declaration_c *symbol) {
+	if (debug) printf("Filling candidate data types list of FB %s\n", ((token_c *)(symbol->fblock_name))->value);
+	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
+	symbol->var_declarations->accept(*this);
+	symbol->fblock_body->accept(*this);
+	delete search_varfb_instance_type;
+	search_varfb_instance_type = NULL;
+	return NULL;
+}
+
+/**********************/
+/* B 1.5.3 - Programs */
+/**********************/
+void *fill_candidate_datatypes_c::visit(program_declaration_c *symbol) {
+	if (debug) printf("Filling candidate data types list in program %s\n", ((token_c *)(symbol->program_type_name))->value);
+	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
+	symbol->var_declarations->accept(*this);
+	symbol->function_block_body->accept(*this);
+	delete search_varfb_instance_type;
+	search_varfb_instance_type = NULL;
+	return NULL;
+}
+
+
+
+/********************************/
+/* B 1.7 Configuration elements */
+/********************************/
+void *fill_candidate_datatypes_c::visit(configuration_declaration_c *symbol) {
+	// TODO !!!
+	/* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */
+	return NULL;
+}
+
+/****************************************/
+/* B.2 - Language IL (Instruction List) */
+/****************************************/
+/***********************************/
+/* B 2.1 Instructions and Operands */
+/***********************************/
+
+/*| instruction_list il_instruction */
+// SYM_LIST(instruction_list_c)
+void *fill_candidate_datatypes_c::visit(instruction_list_c *symbol) {
+	/* In order to fill the data type candidates correctly
+	 * in IL instruction lists containing JMPs to labels that come before the JMP instruction
+	 * itself, we need to run the fill candidate datatypes algorithm twice on the Instruction List.
+	 * e.g.:  ...
+	 *          ld 23
+	 *   label1:st byte_var
+	 *          ld 34
+	 *          JMP label1     
+	 *
+	 * Note that the second time we run the algorithm, most of the candidate datatypes are already filled
+	 * in, so it will be able to produce tha correct candidate datatypes for the IL instruction referenced
+	 * by the label, as in the 2nd pass we already know the candidate datatypes of the JMP instruction!
+	 */
+	for(int j = 0; j < 2; j++) {
+		for(int i = 0; i < symbol->n; i++) {
+			symbol->elements[i]->accept(*this);
+		}
+	}
+	return NULL;
+}
+
+
+
+/* | label ':' [il_incomplete_instruction] eol_list */
+// SYM_REF2(il_instruction_c, label, il_instruction)
+// void *visit(instruction_list_c *symbol);
+void *fill_candidate_datatypes_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_candidate_datatype_lists(symbol);
+	} else {
+		il_instruction_c fake_prev_il_instruction = *symbol;
+		intersect_prev_candidate_datatype_lists(&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 candidate datatypes as the il_instruction */
+		symbol->candidate_datatypes = symbol->il_instruction->candidate_datatypes;
+	}
+
+	return NULL;
+}
+
+
+
+void *fill_candidate_datatypes_c::visit(il_simple_operation_c *symbol) {
+	/* determine the data type of the operand */
+	if (NULL != symbol->il_operand) {
+		symbol->il_operand->accept(*this);
+	}
+	/* recursive call to fill the candidate data types list */
+	il_operand = symbol->il_operand;
+	symbol->il_simple_operator->accept(*this);
+	il_operand = NULL;
+	/* This object has (inherits) the same candidate datatypes as the il_simple_operator */
+	symbol->candidate_datatypes = symbol->il_simple_operator->candidate_datatypes;
+	return NULL;
+}
+
+
+/* | 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 *fill_candidate_datatypes_c::visit(il_function_call_c *symbol) {
+	/* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction)
+	 * In order to be able to handle this without coding special cases, we will simply prepend that symbol
+	 * to the il_operand_list, and remove it after calling handle_function_call().
+	 *
+	 * However, if no further paramters are given, then il_operand_list will be NULL, and we will
+	 * need to create a new object to hold the pointer to prev_il_instruction.
+	 */
+	if (NULL == symbol->il_operand_list)  symbol->il_operand_list = new il_operand_list_c;
+	if (NULL == symbol->il_operand_list)  ERROR;
+
+	symbol->il_operand_list->accept(*this);
+
+	if (NULL != prev_il_instruction) {
+		((list_c *)symbol->il_operand_list)->insert_element(prev_il_instruction, 0);	
+
+		generic_function_call_t fcall_param = {
+			/* fcall_param.function_name               = */ symbol->function_name,
+			/* fcall_param.nonformal_operand_list      = */ symbol->il_operand_list,
+			/* fcall_param.formal_operand_list         = */ NULL,
+			/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_function,
+			/* fcall_param.candidate_functions         = */ symbol->candidate_functions,
+			/* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
+			/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
+		};
+		handle_function_call(symbol, fcall_param);
+
+		/* Undo the changes to the abstract syntax tree we made above... */
+		((list_c *)symbol->il_operand_list)->remove_element(0);
+	}
+
+	/* Undo the changes to the abstract syntax tree we made above... */
+	if (((list_c *)symbol->il_operand_list)->n == 0) {
+		/* if the list becomes empty, then that means that it did not exist before we made these changes, so we delete it! */
+		delete 	symbol->il_operand_list;
+		symbol->il_operand_list = NULL;
+	}
+	
+	if (debug) std::cout << "il_function_call_c [" << symbol->candidate_datatypes.size() << "] result.\n";
+	return NULL;
+}
+
+
+/* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */
+// SYM_REF3(il_expression_c, il_expr_operator, il_operand, simple_instr_list);
+void *fill_candidate_datatypes_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 check the if the data type semantics of operation are correct,  */
+  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 the same candidate datatypes as the il_expr_operator. */
+  symbol->candidate_datatypes = symbol->il_expr_operator->candidate_datatypes;
+  return NULL;
+}
+
+
+void *fill_candidate_datatypes_c::visit(il_jump_operation_c *symbol) {
+  /* recursive call to fill the candidate data types list */
+  il_operand = NULL;
+  symbol->il_jump_operator->accept(*this);
+  il_operand = NULL;
+  /* This object has the same candidate datatypes as the il_jump_operator. */
+  symbol->candidate_datatypes = symbol->il_jump_operator->candidate_datatypes;
+  return NULL;
+}
+
+
+/*   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 *fill_candidate_datatypes_c::visit(il_fb_call_c *symbol) {
+	/* We do not call
+	 * fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name);
+	 * because we want to make sure it is a FB instance, and not some other data type...
+	 */
+	symbol_c *fb_type_id = search_varfb_instance_type->get_basetype_id(symbol->fb_name);
+	/* 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 fb_name not the name of a FB instance. Most probably it is the name of a variable of some other type. */
+		fb_decl = NULL;
+
+	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
+	if (NULL == fb_decl) ERROR;
+
+	if (symbol->  il_param_list != NULL) symbol->il_param_list->accept(*this);
+	if (symbol->il_operand_list != NULL) symbol->il_operand_list->accept(*this);
+
+	/* The print_datatypes_error_c does not rely on this called_fb_declaration pointer being != NULL to conclude that
+	 * we have a datat type incompatibility error, so setting it to the correct fb_decl is actually safe,
+	 * as the compiler will never reach the compilation stage!
+	 */
+	symbol->called_fb_declaration = fb_decl;
+
+	/* Let the il_call_operator (CAL, CALC, or CALCN) determine the candidate datatypes of the il_fb_call_c... */
+	/* NOTE: We ignore whether the call is 'compatible' or not when filling in the candidate datatypes list.
+	 *       Even if it is not compatible, we fill in the candidate datatypes list correctly so that the following
+	 *       IL instructions may be handled correctly and debuged.
+	 *       Doing this is actually safe, as the parameter_list will still contain errors that will be found by
+	 *       print_datatypes_error_c, so the code will never reach stage 4!
+	 */
+	symbol->il_call_operator->accept(*this);
+	symbol->candidate_datatypes = symbol->il_call_operator->candidate_datatypes;
+
+	if (debug) std::cout << "FB [] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
+	return NULL;
+}
+
+
+/* | 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 *fill_candidate_datatypes_c::visit(il_formal_funct_call_c *symbol) {
+	symbol->il_param_list->accept(*this);
+
+	generic_function_call_t fcall_param = {
+		/* fcall_param.function_name               = */ symbol->function_name,
+		/* fcall_param.nonformal_operand_list      = */ NULL,
+		/* fcall_param.formal_operand_list         = */ symbol->il_param_list,
+		/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_function,
+		/* fcall_param.candidate_functions         = */ symbol->candidate_functions,
+		/* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
+		/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
+	};
+	handle_function_call(symbol, fcall_param);
+
+	if (debug) std::cout << "il_formal_funct_call_c [" << symbol->candidate_datatypes.size() << "] result.\n";
+	return NULL;
+}
+
+
+//     void *visit(il_operand_list_c *symbol);
+
+
+/* | simple_instr_list il_simple_instruction */
+/* This object is referenced by il_expression_c objects */
+void *fill_candidate_datatypes_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 candidate datatypes as the last il_instruction */
+  symbol->candidate_datatypes = symbol->elements[symbol->n-1]->candidate_datatypes;
+  
+  if (debug) std::cout << "simple_instr_list_c [" << symbol->candidate_datatypes.size() << "] result.\n";
+  return NULL;
+}
+
+
+
+
+// SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;)
+void *fill_candidate_datatypes_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 candidate datatypes as the il_simple_instruction it points to */
+  symbol->candidate_datatypes = symbol->il_simple_instruction->candidate_datatypes;
+  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 *fill_candidate_datatypes_c::visit(LD_operator_c *symbol) {
+	for(unsigned int i = 0; i < il_operand->candidate_datatypes.size(); i++) {
+		add_datatype_to_candidate_list(symbol, il_operand->candidate_datatypes[i]);
+	}
+	if (debug) std::cout << "LD [" <<  il_operand->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
+	return NULL;
+}
+
+void *fill_candidate_datatypes_c::visit(LDN_operator_c *symbol) {
+	for(unsigned int i = 0; i < il_operand->candidate_datatypes.size(); i++) {
+		if      (is_ANY_BIT_compatible(il_operand->candidate_datatypes[i]))
+			add_datatype_to_candidate_list(symbol, il_operand->candidate_datatypes[i]);
+	}
+	if (debug) std::cout << "LDN [" << il_operand->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
+	return NULL;
+}
+
+void *fill_candidate_datatypes_c::visit(ST_operator_c *symbol) {
+	symbol_c *prev_instruction_type, *operand_type;
+
+	if (NULL == prev_il_instruction) return NULL;
+	for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) {
+		for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) {
+			prev_instruction_type = prev_il_instruction->candidate_datatypes[i];
+			operand_type = il_operand->candidate_datatypes[j];
+			if (is_type_equal(prev_instruction_type, operand_type))
+				add_datatype_to_candidate_list(symbol, prev_instruction_type);
+		}
+	}
+	if (debug) std::cout << "ST [" << prev_il_instruction->candidate_datatypes.size() << "," << il_operand->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
+	return NULL;
+}
+
+void *fill_candidate_datatypes_c::visit(STN_operator_c *symbol) {
+	symbol_c *prev_instruction_type, *operand_type;
+
+	if (NULL == prev_il_instruction) return NULL;
+	for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) {
+		for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) {
+			prev_instruction_type = prev_il_instruction->candidate_datatypes[i];
+			operand_type = il_operand->candidate_datatypes[j];
+			if (is_type_equal(prev_instruction_type,operand_type) && is_ANY_BIT_compatible(operand_type))
+				add_datatype_to_candidate_list(symbol, prev_instruction_type);
+		}
+	}
+	if (debug) std::cout << "STN [" << prev_il_instruction->candidate_datatypes.size() << "," << il_operand->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
+	return NULL;
+}
+
+void *fill_candidate_datatypes_c::visit(NOT_operator_c *symbol) {
+	/* 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!
+	 */
+	if (NULL == prev_il_instruction) return NULL;
+	for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) {
+		if (is_ANY_BIT_compatible(prev_il_instruction->candidate_datatypes[i]))
+			add_datatype_to_candidate_list(symbol, prev_il_instruction->candidate_datatypes[i]);
+	}
+	if (debug) std::cout <<  "NOT_operator [" << prev_il_instruction->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
+	return NULL;
+}
+
+
+void *fill_candidate_datatypes_c::visit(S_operator_c *symbol) {
+  /* TODO: what if this is a FB call ?? */
+	symbol_c *prev_instruction_type, *operand_type;
+
+	if (NULL == prev_il_instruction) return NULL;
+	for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) {
+		for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) {
+			prev_instruction_type = prev_il_instruction->candidate_datatypes[i];
+			operand_type = il_operand->candidate_datatypes[j];
+			/* TODO: I believe the following is wrong! The data types of prev_instruction_type and operand_type DO NOT have to be equal.
+			 * the prev_instruction_type MUST be BOOL compatible.
+			 * I am not too sure about operand_type, does it have to be BOOL compatible, or can it be ANY_BIT compatible? Must check!
+			 */
+			if (is_type_equal(prev_instruction_type,operand_type) && is_ANY_BOOL_compatible(operand_type))
+				add_datatype_to_candidate_list(symbol, prev_instruction_type);
+		}
+	}
+	if (debug) std::cout << "S [" << prev_il_instruction->candidate_datatypes.size() << "," << il_operand->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
+	return NULL;
+}
+
+
+void *fill_candidate_datatypes_c::visit(R_operator_c *symbol) {
+  /* TODO: what if this is a FB call ?? */
+	symbol_c *prev_instruction_type, *operand_type;
+
+	if (NULL == prev_il_instruction) return NULL;
+	for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) {
+		for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) {
+			prev_instruction_type = prev_il_instruction->candidate_datatypes[i];
+			operand_type = il_operand->candidate_datatypes[j];
+			/* TODO: I believe the following is wrong! The data types of prev_instruction_type and operand_type DO NOT have to be equal.
+			 * the prev_instruction_type MUST be BOOL compatible.
+			 * I am not too sure about operand_type, does it have to be BOOL compatible, or can it be ANY_BIT compatible? Must check!
+			 */
+			if (is_type_equal(prev_instruction_type,operand_type) && is_ANY_BOOL_compatible(operand_type))
+				add_datatype_to_candidate_list(symbol, prev_instruction_type);
+		}
+	}
+	if (debug) std::cout << "R [" << prev_il_instruction->candidate_datatypes.size() << "," << il_operand->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
+	return NULL;
+}
+
+
+void *fill_candidate_datatypes_c::visit( S1_operator_c  *symbol) {return handle_implicit_il_fb_call(symbol,  "S1", symbol->called_fb_declaration);}
+void *fill_candidate_datatypes_c::visit( R1_operator_c  *symbol) {return handle_implicit_il_fb_call(symbol,  "R1", symbol->called_fb_declaration);}
+void *fill_candidate_datatypes_c::visit( CLK_operator_c *symbol) {return handle_implicit_il_fb_call(symbol, "CLK", symbol->called_fb_declaration);}
+void *fill_candidate_datatypes_c::visit( CU_operator_c  *symbol) {return handle_implicit_il_fb_call(symbol,  "CU", symbol->called_fb_declaration);}
+void *fill_candidate_datatypes_c::visit( CD_operator_c  *symbol) {return handle_implicit_il_fb_call(symbol,  "CD", symbol->called_fb_declaration);}
+void *fill_candidate_datatypes_c::visit( PV_operator_c  *symbol) {return handle_implicit_il_fb_call(symbol,  "PV", symbol->called_fb_declaration);}
+void *fill_candidate_datatypes_c::visit( IN_operator_c  *symbol) {return handle_implicit_il_fb_call(symbol,  "IN", symbol->called_fb_declaration);}
+void *fill_candidate_datatypes_c::visit( PT_operator_c  *symbol) {return handle_implicit_il_fb_call(symbol,  "PT", symbol->called_fb_declaration);}
+
+void *fill_candidate_datatypes_c::visit( AND_operator_c *symbol) {return handle_binary_operator(widen_AND_table, symbol, prev_il_instruction, il_operand);}
+void *fill_candidate_datatypes_c::visit(  OR_operator_c *symbol) {return handle_binary_operator( widen_OR_table, symbol, prev_il_instruction, il_operand);}
+void *fill_candidate_datatypes_c::visit( XOR_operator_c *symbol) {return handle_binary_operator(widen_XOR_table, symbol, prev_il_instruction, il_operand);}
+void *fill_candidate_datatypes_c::visit(ANDN_operator_c *symbol) {return handle_binary_operator(widen_AND_table, symbol, prev_il_instruction, il_operand);}
+void *fill_candidate_datatypes_c::visit( ORN_operator_c *symbol) {return handle_binary_operator( widen_OR_table, symbol, prev_il_instruction, il_operand);}
+void *fill_candidate_datatypes_c::visit(XORN_operator_c *symbol) {return handle_binary_operator(widen_XOR_table, symbol, prev_il_instruction, il_operand);}
+
+void *fill_candidate_datatypes_c::visit( ADD_operator_c *symbol) {return handle_binary_operator(widen_ADD_table, symbol, prev_il_instruction, il_operand);}
+void *fill_candidate_datatypes_c::visit( SUB_operator_c *symbol) {return handle_binary_operator(widen_SUB_table, symbol, prev_il_instruction, il_operand);}
+void *fill_candidate_datatypes_c::visit( MUL_operator_c *symbol) {return handle_binary_operator(widen_MUL_table, symbol, prev_il_instruction, il_operand);}
+void *fill_candidate_datatypes_c::visit( DIV_operator_c *symbol) {return handle_binary_operator(widen_DIV_table, symbol, prev_il_instruction, il_operand);}
+void *fill_candidate_datatypes_c::visit( MOD_operator_c *symbol) {return handle_binary_operator(widen_MOD_table, symbol, prev_il_instruction, il_operand);}
+
+void *fill_candidate_datatypes_c::visit(  GT_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);}
+void *fill_candidate_datatypes_c::visit(  GE_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);}
+void *fill_candidate_datatypes_c::visit(  EQ_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);}
+void *fill_candidate_datatypes_c::visit(  LT_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);}
+void *fill_candidate_datatypes_c::visit(  LE_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);}
+void *fill_candidate_datatypes_c::visit(  NE_operator_c *symbol) {return handle_binary_operator(widen_CMP_table, symbol, prev_il_instruction, il_operand);}
+
+
+
+void *fill_candidate_datatypes_c::handle_conditional_il_flow_control_operator(symbol_c *symbol) {
+	if (NULL == prev_il_instruction) return NULL;
+	for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) {
+		if (is_ANY_BOOL_compatible(prev_il_instruction->candidate_datatypes[i]))
+			add_datatype_to_candidate_list(symbol, prev_il_instruction->candidate_datatypes[i]);
+	}
+	return NULL;
+}
+
+void *fill_candidate_datatypes_c::visit(  CAL_operator_c *symbol) {if (NULL != prev_il_instruction) symbol->candidate_datatypes = prev_il_instruction->candidate_datatypes; return NULL;}
+void *fill_candidate_datatypes_c::visit(  RET_operator_c *symbol) {if (NULL != prev_il_instruction) symbol->candidate_datatypes = prev_il_instruction->candidate_datatypes; return NULL;}
+void *fill_candidate_datatypes_c::visit(  JMP_operator_c *symbol) {if (NULL != prev_il_instruction) symbol->candidate_datatypes = prev_il_instruction->candidate_datatypes; return NULL;}
+void *fill_candidate_datatypes_c::visit( CALC_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);}
+void *fill_candidate_datatypes_c::visit(CALCN_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);}
+void *fill_candidate_datatypes_c::visit( RETC_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);}
+void *fill_candidate_datatypes_c::visit(RETCN_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);}
+void *fill_candidate_datatypes_c::visit( JMPC_operator_c *symbol) {return handle_conditional_il_flow_control_operator(symbol);}
+void *fill_candidate_datatypes_c::visit(JMPCN_operator_c *symbol) {return handle_conditional_il_flow_control_operator(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 *fill_candidate_datatypes_c::visit(   or_expression_c  *symbol) {return handle_binary_expression(widen_OR_table,  symbol, symbol->l_exp, symbol->r_exp);}
+void *fill_candidate_datatypes_c::visit(   xor_expression_c *symbol) {return handle_binary_expression(widen_XOR_table, symbol, symbol->l_exp, symbol->r_exp);}
+void *fill_candidate_datatypes_c::visit(   and_expression_c *symbol) {return handle_binary_expression(widen_AND_table, symbol, symbol->l_exp, symbol->r_exp);}
+
+void *fill_candidate_datatypes_c::visit(   equ_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
+void *fill_candidate_datatypes_c::visit(notequ_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
+void *fill_candidate_datatypes_c::visit(    lt_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
+void *fill_candidate_datatypes_c::visit(    gt_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
+void *fill_candidate_datatypes_c::visit(    le_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
+void *fill_candidate_datatypes_c::visit(    ge_expression_c *symbol) {return handle_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
+
+
+/* The following code is correct when handling the addition of 2 symbolic_variables
+ * In this case, adding two variables (e.g. USINT_var1 + USINT_var2) will always yield
+ * the same data type, even if the result of the adition could not fit inside the same
+ * data type (due to overflowing)
+ *
+ * However, when adding two literals (e.g. USINT#42 + USINT#3)
+ * we should be able to detect overflows of the result, and therefore not consider
+ * that the result may be of type USINT.
+ * Currently we do not yet detect these overflows, and allow handling the sum of two USINTs
+ * as always resulting in an USINT, even in the following expression
+ * (USINT#65535 + USINT#2).
+ *
+ * In the future we can add some code to reduce
+ * all the expressions that are based on literals into the resulting literal
+ * value (maybe some visitor class that will run before or after data type
+ * checking). Since this class will have to be very careful to make sure it implements the same mathematical
+ * details (e.g. how to round and truncate numbers) as defined in IEC 61131-3, we will leave this to the future.
+ * Also, the question will arise if we should also replace calls to standard
+ * functions if the input parameters are all literals (e.g. ADD(42, 42)). This
+ * means this class will be more difficult than it appears at first.
+ */
+void *fill_candidate_datatypes_c::visit(  add_expression_c *symbol) {return handle_binary_expression(widen_ADD_table,  symbol, symbol->l_exp, symbol->r_exp);}
+void *fill_candidate_datatypes_c::visit(  sub_expression_c *symbol) {return handle_binary_expression(widen_SUB_table,  symbol, symbol->l_exp, symbol->r_exp);}
+void *fill_candidate_datatypes_c::visit(  mul_expression_c *symbol) {return handle_binary_expression(widen_MUL_table,  symbol, symbol->l_exp, symbol->r_exp);}
+void *fill_candidate_datatypes_c::visit(  div_expression_c *symbol) {return handle_binary_expression(widen_DIV_table,  symbol, symbol->l_exp, symbol->r_exp);}
+void *fill_candidate_datatypes_c::visit(  mod_expression_c *symbol) {return handle_binary_expression(widen_MOD_table,  symbol, symbol->l_exp, symbol->r_exp);}
+void *fill_candidate_datatypes_c::visit(power_expression_c *symbol) {return handle_binary_expression(widen_EXPT_table, symbol, symbol->l_exp, symbol->r_exp);}
+
+
+void *fill_candidate_datatypes_c::visit(neg_expression_c *symbol) {
+  /* NOTE: The standard defines the syntax for this 'negation' operation, but
+   *       does not define the its semantics.
+   *
+   *       We could be tempted to consider that the semantics of the
+   *       'negation' operation are similar/identical to the semantics of the 
+   *       SUB expression/operation. This would include assuming that the
+   *       possible datatypes for the 'negation' operation is also
+   *       the same as those for the SUB expression/operation, namely ANY_MAGNITUDE.
+   *
+   *       However, this would then mean that the following ST code would be 
+   *       syntactically and semantically correct:
+   *       uint_var := - (uint_var);
+   *
+   *       According to the standard, the above code should result in a 
+   *       runtime error, when we try to apply a negative value to the
+   *       UINT typed variable 'uint_var'.
+   *
+   *       It is much easier for the compiler to detect this at compile time,
+   *       and it is probably safer to the resulting code too.
+   *
+   *       To detect these tyes of errors at compile time, the easisest solution
+   *       is to only allow ANY_NUM datatytpes that are signed.
+   *        So, that is what we do here!
+   */
+	symbol->exp->accept(*this);
+	for (unsigned int i = 0; i < symbol->exp->candidate_datatypes.size(); i++) {
+		if (is_ANY_signed_MAGNITUDE_compatible(symbol->exp->candidate_datatypes[i]))
+			add_datatype_to_candidate_list(symbol, symbol->exp->candidate_datatypes[i]);
+	}
+	if (debug) std::cout << "neg [" << symbol->exp->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
+	return NULL;
+}
+
+
+void *fill_candidate_datatypes_c::visit(not_expression_c *symbol) {
+	symbol->exp->accept(*this);
+	for (unsigned int i = 0; i < symbol->exp->candidate_datatypes.size(); i++) {
+		if      (is_ANY_BIT_compatible(symbol->exp->candidate_datatypes[i]))
+			add_datatype_to_candidate_list(symbol, symbol->exp->candidate_datatypes[i]);
+	}
+	if (debug) std::cout << "not [" << symbol->exp->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
+	return NULL;
+}
+
+
+void *fill_candidate_datatypes_c::visit(function_invocation_c *symbol) {
+	if      (NULL != symbol->formal_param_list)        symbol->   formal_param_list->accept(*this);
+	else if (NULL != symbol->nonformal_param_list)     symbol->nonformal_param_list->accept(*this);
+	else ERROR;
+
+	generic_function_call_t fcall_param = {
+		/* fcall_param.function_name               = */ symbol->function_name,
+		/* fcall_param.nonformal_operand_list      = */ symbol->nonformal_param_list,
+		/* fcall_param.formal_operand_list         = */ symbol->formal_param_list,
+		/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_function,
+		/* fcall_param.candidate_functions         = */ symbol->candidate_functions,
+		/* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
+		/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
+	};
+	handle_function_call(symbol, fcall_param);
+
+	if (debug) std::cout << "function_invocation_c [" << symbol->candidate_datatypes.size() << "] result.\n";
+	return NULL;
+}
+
+
+
+/********************/
+/* B 3.2 Statements */
+/********************/
+// SYM_LIST(statement_list_c)
+/* The visitor of the base class search_visitor_c will handle calling each instruction in the list.
+ * We do not need to do anything here...
+ */
+// void *fill_candidate_datatypes_c::visit(statement_list_c *symbol)
+
+
+/*********************************/
+/* B 3.2.1 Assignment Statements */
+/*********************************/
+void *fill_candidate_datatypes_c::visit(assignment_statement_c *symbol) {
+	symbol_c *left_type, *right_type;
+
+	symbol->l_exp->accept(*this);
+	symbol->r_exp->accept(*this);
+	for (unsigned int i = 0; i < symbol->l_exp->candidate_datatypes.size(); i++) {
+		for(unsigned int j = 0; j < symbol->r_exp->candidate_datatypes.size(); j++) {
+			left_type = symbol->l_exp->candidate_datatypes[i];
+			right_type = symbol->r_exp->candidate_datatypes[j];
+			if (is_type_equal(left_type, right_type))
+				add_datatype_to_candidate_list(symbol, left_type);
+		}
+	}
+	if (debug) std::cout << ":= [" << symbol->l_exp->candidate_datatypes.size() << "," << symbol->r_exp->candidate_datatypes.size() << "] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
+	return NULL;
+}
+
+/*****************************************/
+/* B 3.2.2 Subprogram Control Statements */
+/*****************************************/
+void *fill_candidate_datatypes_c::visit(fb_invocation_c *symbol) {
+	symbol_c *fb_type_id = search_varfb_instance_type->get_basetype_id(symbol->fb_name);
+	/* 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 fb_name not the name of a FB instance. Most probably it is the name of a variable of some other type. */
+		fb_decl = NULL;
+
+	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
+	if (NULL == fb_decl) ERROR;
+	
+	if (symbol->   formal_param_list != NULL) symbol->formal_param_list->accept(*this);
+	if (symbol->nonformal_param_list != NULL) symbol->nonformal_param_list->accept(*this);
+
+	/* The print_datatypes_error_c does not rely on this called_fb_declaration pointer being != NULL to conclude that
+	 * we have a datat type incompatibility error, so setting it to the correct fb_decl is actually safe,
+	 * as the compiler will never reach the compilation stage!
+	 */
+	symbol->called_fb_declaration = fb_decl;
+
+	if (debug) std::cout << "FB [] ==> "  << symbol->candidate_datatypes.size() << " result.\n";
+	return NULL;
+}
+
+
+
+/********************************/
+/* B 3.2.3 Selection Statements */
+/********************************/
+void *fill_candidate_datatypes_c::visit(if_statement_c *symbol) {
+	symbol->expression->accept(*this);
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	if (NULL != symbol->elseif_statement_list)
+		symbol->elseif_statement_list->accept(*this);
+	if (NULL != symbol->else_statement_list)
+		symbol->else_statement_list->accept(*this);
+	return NULL;
+}
+
+
+void *fill_candidate_datatypes_c::visit(elseif_statement_c *symbol) {
+	symbol->expression->accept(*this);
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	return NULL;
+}
+
+/* CASE expression OF case_element_list ELSE statement_list END_CASE */
+// SYM_REF3(case_statement_c, expression, case_element_list, statement_list)
+void *fill_candidate_datatypes_c::visit(case_statement_c *symbol) {
+	symbol->expression->accept(*this);
+	if (NULL != symbol->case_element_list)
+		symbol->case_element_list->accept(*this);
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	return NULL;
+}
+
+
+/* helper symbol for case_statement */
+// SYM_LIST(case_element_list_c)
+/* NOTE: visitor method for case_element_list_c is not required since we inherit from iterator_visitor_c */
+
+/*  case_list ':' statement_list */
+// SYM_REF2(case_element_c, case_list, statement_list)
+/* NOTE: visitor method for case_element_c is not required since we inherit from iterator_visitor_c */
+
+// SYM_LIST(case_list_c)
+/* NOTE: visitor method for case_list_c is not required since we inherit from iterator_visitor_c */
+
+/********************************/
+/* B 3.2.4 Iteration Statements */
+/********************************/
+
+void *fill_candidate_datatypes_c::visit(for_statement_c *symbol) {
+	symbol->control_variable->accept(*this);
+	symbol->beg_expression->accept(*this);
+	symbol->end_expression->accept(*this);
+	if (NULL != symbol->by_expression)
+		symbol->by_expression->accept(*this);
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	return NULL;
+}
+
+
+void *fill_candidate_datatypes_c::visit(while_statement_c *symbol) {
+	symbol->expression->accept(*this);
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	return NULL;
+}
+
+
+void *fill_candidate_datatypes_c::visit(repeat_statement_c *symbol) {
+	symbol->expression->accept(*this);
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	return NULL;
+}
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/fill_candidate_datatypes.hh	Sat Mar 31 15:36:08 2012 +0100
@@ -0,0 +1,335 @@
+/*
+ *  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)
+ *
+ */
+
+
+#include "../absyntax_utils/absyntax_utils.hh"
+#include "datatype_functions.hh"
+
+class fill_candidate_datatypes_c: public iterator_visitor_c {
+
+  private:
+    search_varfb_instance_type_c *search_varfb_instance_type;
+    search_base_type_c search_base_type;
+    /* When calling a function block, we must first find it's type,
+     * by searching through the declarations of the variables currently
+     * in scope.
+     * This class does just that...
+     * A new object instance is instantiated whenever we start checking semantics
+     * for a function block type declaration, or a program declaration.
+     * This object instance will then later be called while the
+     * function block's or the program's body is being handled.
+     *
+     * Note that functions cannot contain calls to function blocks,
+     * so we do not create an object instance when handling
+     * a function declaration.
+     */
+    //     search_var_instance_decl_c *search_var_instance_decl;
+
+    /* This variable was created to pass information from
+     * fill_candidate_datatypes_c::visit(case_statement_c *symbol) function to
+     * fill_candidate_datatypes_c::visit(case_list_c *symbol) function.
+     */
+//     symbol_c *case_expression_type;
+
+    /* In IL code, once we find a type mismatch error, it is best to
+     * ignore any further errors until the end of the logical operation,
+     * i.e. until the next LD.
+     * However, we cannot clear the il_error flag on all LD operations,
+     * as these may also be used within parenthesis. LD operations
+     * within parenthesis may not clear the error flag.
+     * We therefore need a counter to know how deep inside a parenthesis
+     * structure we are.
+     */
+//     int  il_parenthesis_level;
+//     bool error_found;
+
+    /* the current data type of the data stored in the IL stack, i.e. the default variable */
+    symbol_c *prev_il_instruction;
+    /* the current IL operand being analyzed - its symbol and its data type */
+    symbol_c *il_operand_type;
+    symbol_c *il_operand;
+    symbol_c *widening_conversion(symbol_c *left_type, symbol_c *right_type, const struct widen_entry widen_table[]);
+
+    /* Match a function declaration with a function call through their parameters.*/
+    /* returns true if compatible function/FB invocation, otherwise returns false */
+    bool  match_nonformal_call(symbol_c *f_call, symbol_c *f_decl);
+    bool  match_formal_call   (symbol_c *f_call, symbol_c *f_decl, symbol_c **first_param_datatype = NULL);
+    void  handle_function_call(symbol_c *fcall, generic_function_call_t fcall_data);
+    void *handle_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name, symbol_c *&called_fb_declaration);
+    void *handle_binary_expression(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr);
+    void *handle_binary_operator  (const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr);
+    void *handle_conditional_il_flow_control_operator(symbol_c *symbol);
+    
+    /* a helper function... */
+    symbol_c *base_type(symbol_c *symbol);    
+    
+    /* 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 add_datatype_to_candidate_list  (symbol_c *symbol, symbol_c *datatype);
+    bool add_2datatypes_to_candidate_list(symbol_c *symbol, symbol_c *datatype1, symbol_c *datatype2);
+    
+    
+  public:
+    fill_candidate_datatypes_c(symbol_c *ignore);
+    virtual ~fill_candidate_datatypes_c(void);
+
+
+    /*********************/
+    /* B 1.2 - Constants */
+    /*********************/
+    /******************************/
+    /* B 1.2.1 - Numeric Literals */
+    /******************************/
+    void *handle_any_integer(symbol_c *symbol);
+    void *handle_any_real   (symbol_c *symbol);
+    void *handle_any_literal(symbol_c *symbol, symbol_c *symbol_value, symbol_c *symbol_type);
+    
+    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.1.2.2   Character Strings */
+    /*******************************/
+    void *visit(double_byte_character_string_c *symbol);
+    void *visit(single_byte_character_string_c *symbol);
+
+    /***************************/
+    /* B 1.2.3 - Time Literals */
+    /***************************/
+    /************************/
+    /* B 1.2.3.1 - Duration */
+    /************************/
+    void *visit(duration_c *symbol);
+
+    /************************************/
+    /* B 1.2.3.2 - Time of day and Date */
+    /************************************/
+    void *visit(time_of_day_c *symbol);
+    void *visit(date_c *symbol);
+    void *visit(date_and_time_c *symbol);
+
+
+    /**********************/
+    /* B 1.3 - Data types */
+    /**********************/
+    /********************************/
+    /* B 1.3.3 - Derived data types */
+    /********************************/
+    void *visit(subrange_c *symbol);
+//  void *visit(data_type_declaration_c *symbol);
+    void *visit(enumerated_value_c *symbol);
+
+    /*********************/
+    /* B 1.4 - Variables */
+    /*********************/
+    void *visit(symbolic_variable_c *symbol);
+
+    /********************************************/
+    /* B 1.4.1 - Directly Represented Variables */
+    /********************************************/
+    void *visit(direct_variable_c *symbol);
+
+    /*************************************/
+    /* 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 */
+    /**************************************/
+    /***********************/
+    /* 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);
+
+    /********************************/
+    /* B 1.7 Configuration elements */
+    /********************************/
+    void *visit(configuration_declaration_c *symbol);
+
+    /****************************************/
+    /* 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_jump_operation_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);
+
+    /*******************/
+    /* 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);
+
+    /*********************************/
+    /* B 3.2.1 Assignment Statements */
+    /*********************************/
+    void *visit(assignment_statement_c *symbol);
+
+    /*****************************************/
+    /* B 3.2.2 Subprogram Control Statements */
+    /*****************************************/
+    void *visit(fb_invocation_c *symbol);
+
+    /********************************/
+    /* B 3.2.3 Selection Statements */
+    /********************************/
+    void *visit(if_statement_c *symbol);
+    //     void *visit(elseif_statement_list_c *symbol);
+    void *visit(elseif_statement_c *symbol);
+    void *visit(case_statement_c *symbol);
+
+    /********************************/
+    /* B 3.2.4 Iteration Statements */
+    /********************************/
+    void *visit(for_statement_c *symbol);
+    void *visit(while_statement_c *symbol);
+    void *visit(repeat_statement_c *symbol);
+
+}; // fill_candidate_datatypes_c
+
+
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/flow_control_analysis.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -0,0 +1,373 @@
+/*
+ *  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)
+ *
+ */
+
+
+/*
+ *  Do flow control analysis of the IEC 61131-3 code.
+ *
+ *  We currently only do this for IL code.
+ *  This class will annotate the abstract syntax tree, by filling in the
+ *  prev_il_instruction variable in the il_instruction_c, so it points to
+ *  the previous il_instruction_c object in the instruction list instruction_list_c.
+ *
+ *  Since IL code can contain jumps (JMP), the same il_instruction may effectively have
+ *  several previous il_instructions. In order to accommodate this, each il_instruction
+ *  will maintain a vector (i..e an array) of pointers to all the previous il_instructions.
+ *  We do however attempt to guarantee that the first element in the vector (array) will preferentially
+ *  point to the il instruction that is right before / imediately preceding the current il instructions, 
+ *  i.e. the first element in the array will tend to point to the previous il_instruction
+ *  that is not a jump JMP IL instruction!
+ *
+ *  The result will essentially be a graph of il_instruction_c objects, each 
+ *  pointing to the previous il_instruction_c object.
+ *
+ *  The reality is we will get several independent and isolated linked lists
+ *  (actually, since we now process labels correctly, this is really a graph):
+ *  one for each block of IL code (e.g. inside a Function, FB or Program).
+ *  Additionally, when the IL code has an expression (expression_c object), we will actually
+ *  have one more isolated linked list for the IL code inside that expression.
+ *
+ *  e.g.
+ *       line_1:   LD 1
+ *       line_2:   ADD (42
+ *       line_3:        ADD B
+ *       line_4:        ADD C 
+ *       line_5:       )
+ *       line_6:   ADD D
+ *       line_7:   ST  E
+ * 
+ *     will result in two independent linked lists:
+ *       main list:  line_7 -> line_6 -> line2 -> line_1
+ *       expr list:  lin4_4 -> line_3 -> (operand of line_2, i.e. '42')
+ * 
+ * 
+ *     In the main list, each:
+ *        line_x: IL_operation IL_operand
+ *      is encoded as
+ *          il_instruction_c(label, il_incomplete_instruction)
+ *      these il_instruction_c objects will point back to the previous il_instruction_c object.
+ *
+ *     In the expr list, each 
+ *        line_x:        IL_operation IL_operand
+ *      is encoded as
+ *          il_simple_instruction_c(il_simple_instruction)
+ *      these il_simple_instruction_c objects will point back to the previous il_simple_instruction_c object,
+ *      except the for the first il_simple_instruction_c object in the list, which will point back to
+ *      the first il_operand (in the above example, '42'), or NULL is it does not exist.
+ *          
+ *
+ * label:
+ *   identifier_c  
+ *   
+ * il_incomplete_instruction:
+ *   il_simple_operation   (il_simple_operation_c, il_function_call_c)
+ * | il_expression         (il_expression_c)
+ * | il_jump_operation     (il_jump_operation_c)
+ * | il_fb_call            (il_fb_call_c)
+ * | il_formal_funct_call  (il_formal_funct_call_c)
+ * | il_return_operator    (RET_operator_c, RETC_operator_c, RETCN_operator_c)
+ *  
+ * 
+ * il_expression_c(il_expr_operator, il_operand, simple_instr_list)
+ * 
+ * il_operand:
+ *   variable            (symbolic_variable_c, direct_variable_c, array_variable_c, structured_variable_c)  
+ * | enumerated_value    (enumerated_value_c)
+ * | constant            (lots of literal classes _c)
+ * 
+ * simple_instr_list:
+ *   list of il_simple_instruction
+ * 
+ * il_simple_instruction:
+ *   il_simple_operation       (il_simple_operation_c, il_function_call_c)
+ * | il_expression             (il_expression_c)
+ * | il_formal_funct_call      (il_formal_funct_call_c)
+ * 
+ */
+
+#include "flow_control_analysis.hh"
+
+
+
+/* set to 1 to see debug info during execution */
+static int debug = 0;
+
+flow_control_analysis_c::flow_control_analysis_c(symbol_c *ignore) {
+  prev_il_instruction = NULL;
+  curr_il_instruction = NULL;
+}
+
+flow_control_analysis_c::~flow_control_analysis_c(void) {
+}
+
+
+
+/************************************/
+/* B 1.5 Program organization units */
+/************************************/
+/*********************/
+/* B 1.5.1 Functions */
+/*********************/
+void *flow_control_analysis_c::visit(function_declaration_c *symbol) {
+	search_il_label = new search_il_label_c(symbol);
+	if (debug) printf("Doing flow control analysis in body of function %s\n", ((token_c *)(symbol->derived_function_name))->value);
+	symbol->function_body->accept(*this);
+	delete search_il_label;
+	search_il_label = NULL;
+	return NULL;
+}
+
+/***************************/
+/* B 1.5.2 Function blocks */
+/***************************/
+void *flow_control_analysis_c::visit(function_block_declaration_c *symbol) {
+	search_il_label = new search_il_label_c(symbol);
+	if (debug) printf("Doing flow control analysis in body of FB %s\n", ((token_c *)(symbol->fblock_name))->value);
+	symbol->fblock_body->accept(*this);
+	delete search_il_label;
+	search_il_label = NULL;
+	return NULL;
+}
+
+/********************/
+/* B 1.5.3 Programs */
+/********************/
+void *flow_control_analysis_c::visit(program_declaration_c *symbol) {
+	search_il_label = new search_il_label_c(symbol);
+	if (debug) printf("Doing flow control analysis in body of program %s\n", ((token_c *)(symbol->program_type_name))->value);
+	symbol->function_block_body->accept(*this);
+	delete search_il_label;
+	search_il_label = NULL;
+	return NULL;
+}
+
+
+/********************************/
+/* B 1.7 Configuration elements */
+/********************************/
+void *flow_control_analysis_c::visit(configuration_declaration_c *symbol) {
+	return NULL;
+}
+
+
+/****************************************/
+/* B.2 - Language IL (Instruction List) */
+/****************************************/
+/***********************************/
+/* B 2.1 Instructions and Operands */
+/***********************************/
+
+/*| instruction_list il_instruction */
+// SYM_LIST(instruction_list_c)
+void *flow_control_analysis_c::visit(instruction_list_c *symbol) {
+	prev_il_instruction_is_JMP_or_RET = false;
+	for(int i = 0; i < symbol->n; i++) {
+		prev_il_instruction = NULL;
+		if (i > 0) prev_il_instruction = symbol->elements[i-1];
+		curr_il_instruction = symbol->elements[i];
+		curr_il_instruction->accept(*this);
+		curr_il_instruction = NULL;
+	}
+	return NULL;
+}
+
+/* | label ':' [il_incomplete_instruction] eol_list */
+// SYM_REF2(il_instruction_c, label, il_instruction)
+// void *visit(instruction_list_c *symbol);
+void *flow_control_analysis_c::visit(il_instruction_c *symbol) {
+	if ((NULL != prev_il_instruction) && (!prev_il_instruction_is_JMP_or_RET))
+		/* We try to guarantee that the previous il instruction that is in the previous line, will occupy the first element of the vector.
+		 * In order to do that, we use insert() instead of push_back()
+		 */
+		symbol->prev_il_instruction.insert(symbol->prev_il_instruction.begin() , prev_il_instruction);
+
+	/* check if it is an il_expression_c, a JMP[C[N]], or a RET, and if so, handle it correctly */
+	prev_il_instruction_is_JMP_or_RET = false;
+	if (NULL != symbol->il_instruction)
+		symbol->il_instruction->accept(*this);
+	return NULL;
+}
+
+
+
+/* | il_simple_operator [il_operand] */
+// SYM_REF2(il_simple_operation_c, il_simple_operator, il_operand)
+// void *flow_control_analysis_c::visit(il_simple_operation_c *symbol)
+
+
+
+/* | 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 *flow_control_analysis_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 *flow_control_analysis_c::visit(il_expression_c *symbol) {
+	if(NULL == symbol->simple_instr_list) 
+		/* nothing to do... */
+		return NULL;
+  
+	symbol_c *save_prev_il_instruction = prev_il_instruction;
+	prev_il_instruction = symbol->il_operand;
+	symbol->simple_instr_list->accept(*this);
+	prev_il_instruction = save_prev_il_instruction;
+	return NULL;
+}
+
+
+/*  il_jump_operator label */
+// SYM_REF2(il_jump_operation_c, il_jump_operator, label)
+void *flow_control_analysis_c::visit(il_jump_operation_c *symbol) {
+  /* search for the il_instruction_c containing the label */
+  il_instruction_c *destination = search_il_label->find_label(symbol->label);
+
+  /* give the visit(JMP_operator *) an oportunity to set the prev_il_instruction_is_JMP_or_RET flag! */
+  symbol->il_jump_operator->accept(*this);
+  /* add, to that il_instruction's list of prev_il_intsructions, the curr_il_instruction */
+  if (NULL != destination)
+    destination->prev_il_instruction.push_back(curr_il_instruction);
+  return NULL;
+}
+
+
+/*   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 *flow_control_analysis_c::visit(il_fb_call_c *symbol)
+
+
+/* | 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 *flow_control_analysis_c::visit(il_formal_funct_call_c *symbol)
+
+
+
+//  void *visit(il_operand_list_c *symbol);
+void *flow_control_analysis_c::visit(simple_instr_list_c *symbol) {
+	for(int i = 0; i < symbol->n; i++) {
+		/* The prev_il_instruction for element[0] was set in visit(il_expression_c *) */
+		if (i>0) prev_il_instruction = symbol->elements[i-1];
+		symbol->elements[i]->accept(*this);
+	}
+	return NULL;
+}
+
+
+// SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;)
+void *flow_control_analysis_c::visit(il_simple_instruction_c*symbol) {
+	if (NULL != prev_il_instruction)
+		/* We try to guarantee that the previous il instruction that is in the previous line, will occupy the first element of the vector.
+		 * In order to do that, we use insert() instead of push_back()
+		 */
+		symbol->prev_il_instruction.insert(symbol->prev_il_instruction.begin() , prev_il_instruction);
+	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 *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);
+
+/* this next visit function will be called directly from visit(il_instruction_c *) */
+void *flow_control_analysis_c::visit(  RET_operator_c *symbol) {
+	prev_il_instruction_is_JMP_or_RET = true;
+	return NULL;
+}
+
+// void *visit( RETC_operator_c *symbol);
+// void *visit(RETCN_operator_c *symbol);
+
+/* this next visit function will be called from visit(il_jump_operation_c *) */
+void *flow_control_analysis_c::visit(  JMP_operator_c *symbol) {
+	prev_il_instruction_is_JMP_or_RET = true;
+	return NULL;
+}
+
+// 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);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/flow_control_analysis.hh	Sat Mar 31 15:36:08 2012 +0100
@@ -0,0 +1,162 @@
+/*
+ *  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)
+ *
+ */
+
+
+/*
+ *  Do flow control analysis of the IEC 61131-3 code.
+ *
+ *  We currently only do this for IL code.
+ *  This class will annotate the abstract syntax tree, by filling in the
+ *  prev_il_instruction variable in the il_instruction_c, so it points to
+ *  the previous il_instruction_c object in the instruction list instruction_list_c.
+ */
+
+
+
+#include "../absyntax_utils/absyntax_utils.hh"
+
+
+class flow_control_analysis_c: public iterator_visitor_c {
+
+  private:
+    search_il_label_c *search_il_label;
+    symbol_c *prev_il_instruction;
+    symbol_c *curr_il_instruction;
+    bool      prev_il_instruction_is_JMP_or_RET;
+
+  public:
+    flow_control_analysis_c(symbol_c *ignore);
+    virtual ~flow_control_analysis_c(void);
+
+    /**************************************/
+    /* B 1.5 - Program organization 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);
+
+    /********************************/
+    /* B 1.7 Configuration elements */
+    /********************************/
+    void *visit(configuration_declaration_c *symbol);
+    
+    /****************************************/
+    /* 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_jump_operation_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);
+
+    /*******************/
+    /* 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);
+
+}; // flow_control_analysis_c
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/narrow_candidate_datatypes.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -0,0 +1,1257 @@
+/*
+ *  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)
+ *
+ */
+
+
+/*
+ *  Narrow class select and store a data type from candidate data types list for all symbols
+ */
+
+#include "narrow_candidate_datatypes.hh"
+#include "datatype_functions.hh"
+#include <typeinfo>
+#include <list>
+#include <string>
+#include <string.h>
+#include <strings.h>
+
+
+/* set to 1 to see debug info during execution */
+static int debug = 0;
+
+narrow_candidate_datatypes_c::narrow_candidate_datatypes_c(symbol_c *ignore) {
+}
+
+narrow_candidate_datatypes_c::~narrow_candidate_datatypes_c(void) {
+}
+
+
+/* Only set the symbol's desired datatype to 'datatype' if that datatype is in the candidate_datatype list */
+static void set_datatype(symbol_c *datatype, symbol_c *symbol) {
+  
+	/* If we are trying to set to the undefined type, and the symbol's datatype has already been set to something else, 
+	 * we abort the compoiler as I don't think this should ever occur. 
+	 * NOTE: In order to handle JMPs to labels that come before the JMP itself, we run the narrow algorithm twice.
+	 *       This means that this situation may legally occur, so we cannot abort the compiler here!
+	 */
+// 	if ((NULL == datatype) && (NULL != symbol->datatype)) ERROR;
+ 	if ((NULL == datatype) && (NULL != symbol->datatype)) return;
+	if ((NULL == datatype) && (NULL == symbol->datatype)) return;
+	
+	if (search_in_candidate_datatype_list(datatype, symbol->candidate_datatypes) < 0)
+		symbol->datatype = &(search_constant_type_c::invalid_type_name);   
+	else {
+		if (NULL == symbol->datatype)   
+			/* not yet set to anything, so we set it to the requested data type */
+			symbol->datatype = datatype; 
+		else {
+			/* had already been set previously to some data type. Let's check if they are the same! */
+			if (!is_type_equal(symbol->datatype, datatype))
+				symbol->datatype = &(search_constant_type_c::invalid_type_name);
+// 			else 
+				/* we leave it unchanged, as it is the same as the requested data type! */
+		}
+	}
+}
+
+
+
+/* Only set the symbol's desired datatype to 'datatype' if that datatype is in the candidate_datatype list */
+// static void set_datatype_in_prev_il_instructions(symbol_c *datatype, std::vector <symbol_c *> prev_il_instructions) {
+static void set_datatype_in_prev_il_instructions(symbol_c *datatype, il_instruction_c *symbol) {
+	if (NULL == symbol) ERROR;
+	for (unsigned int i = 0; i < symbol->prev_il_instruction.size(); i++)
+		set_datatype(datatype, symbol->prev_il_instruction[i]);
+}
+
+
+
+bool narrow_candidate_datatypes_c::is_widening_compatible(const struct widen_entry widen_table[], symbol_c *left_type, symbol_c *right_type, symbol_c *result_type, bool *deprecated_status) {
+	for (int 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))
+			&& (typeid(*result_type) == typeid(*widen_table[k].result))) {
+			if (NULL != deprecated_status)
+				*deprecated_status = (widen_table[k].status == widen_entry::deprecated);
+			return true;
+		}
+	}
+	return false;
+}
+
+/*
+ * 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().
+ */
+void narrow_candidate_datatypes_c::narrow_nonformal_call(symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count) {
+	symbol_c *call_param_value,  *param_type;
+	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;
+
+	if (NULL != ext_parm_count) *ext_parm_count = -1;
+
+	/* Iterating through the non-formal parameters of the function call */
+	while((call_param_value = fcp_iterator.next_nf()) != NULL) {
+		/* Obtaining the type of the value being passed in the function call */
+		/* 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... */
+			/* This error should have been caught in fill_candidate_datatypes_c, but may occur here again when we handle FB invocations! 
+			 * In this case, we carry on analysing the code in order to be able to provide relevant error messages
+			 * for that code too!
+			 */
+			if(param_name == NULL) break;
+		} while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0));
+
+		/* Set the desired datatype for this parameter, and call it recursively. */
+		/* Note that if the call has more parameters than those declared in the function/FB declaration,
+		 * we may be setting this to NULL!
+		 */
+		symbol_c *desired_datatype = base_type(fp_iterator.param_type());
+		if ((NULL != param_name) && (NULL == desired_datatype)) ERROR;
+		if ((NULL == param_name) && (NULL != desired_datatype)) ERROR;
+
+		/* NOTE: When we are handling a nonformal function call made from IL, the first parameter is the 'default' or 'current'
+		 *       il value. However, a pointer to a copy of the prev_il_instruction is pre-pended into the operand list, so 
+		 *       the call 
+		 *       call_param_value->accept(*this);
+		 *       may actually be calling an object of the base symbol_c .
+		 */
+		set_datatype(desired_datatype, call_param_value);
+		call_param_value->accept(*this);
+
+		if (NULL != param_name) 
+			if (extensible_parameter_highest_index < fp_iterator.extensible_param_index())
+				extensible_parameter_highest_index = fp_iterator.extensible_param_index();
+	}
+	/* In the case of a call to an extensible function, we store the highest index 
+	 * of the extensible parameters this particular call uses, in the symbol_c object
+	 * of the function call itself!
+	 * In calls to non-extensible functions, this value will be set to -1.
+	 * This information is later used in stage4 to correctly generate the
+	 * output code.
+	 */
+	if ((NULL != ext_parm_count) && (extensible_parameter_highest_index >=0) /* if call to extensible function */)
+		*ext_parm_count = 1 + extensible_parameter_highest_index - fp_iterator.first_extensible_param_index();
+}
+
+
+
+void narrow_candidate_datatypes_c::narrow_formal_call(symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count) {
+	symbol_c *call_param_value, *call_param_name, *param_type;
+	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;
+
+	if (NULL != ext_parm_count) *ext_parm_count = -1;
+	/* 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;
+
+		/* Find the corresponding parameter in function declaration */
+		param_name = fp_iterator.search(call_param_name);
+
+		/* Set the desired datatype for this parameter, and call it recursively. */
+		/* NOTE: When handling a FB call, this narrow_formal_call() may be called to analyse
+		 *       an invalid FB call (call with parameters that do not exist on the FB declaration).
+		 *       For this reason, the param_name may come out as NULL!
+		 */
+		symbol_c *desired_datatype = base_type(fp_iterator.param_type());
+		if ((NULL != param_name) && (NULL == desired_datatype)) ERROR;
+		if ((NULL == param_name) && (NULL != desired_datatype)) ERROR;
+
+		/* set the desired data type for this parameter */
+		set_datatype(desired_datatype, call_param_value);
+		/* And recursively call that parameter/expression, so it can propagate that info */
+		call_param_value->accept(*this);
+
+		/* set the extensible_parameter_highest_index, which will be needed in stage 4 */
+		/* This value says how many extensible parameters are being passed to the standard function */
+		if (NULL != param_name) 
+			if (extensible_parameter_highest_index < fp_iterator.extensible_param_index())
+				extensible_parameter_highest_index = fp_iterator.extensible_param_index();
+	}
+	/* call is compatible! */
+
+	/* In the case of a call to an extensible function, we store the highest index 
+	 * of the extensible parameters this particular call uses, in the symbol_c object
+	 * of the function call itself!
+	 * In calls to non-extensible functions, this value will be set to -1.
+	 * This information is later used in stage4 to correctly generate the
+	 * output code.
+	 */
+	if ((NULL != ext_parm_count) && (extensible_parameter_highest_index >=0) /* if call to extensible function */)
+		*ext_parm_count = 1 + extensible_parameter_highest_index - fp_iterator.first_extensible_param_index();
+}
+
+
+/*
+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) {
+	/* set the called_function_declaration. */
+	fcall_data.called_function_declaration = NULL;
+
+	/* set the called_function_declaration taking into account the datatype that we need to return */
+	for(unsigned int i = 0; i < fcall->candidate_datatypes.size(); i++) {
+		if (is_type_equal(fcall->candidate_datatypes[i], fcall->datatype)) {
+			fcall_data.called_function_declaration = fcall_data.candidate_functions[i];
+			break;
+		}
+	}
+
+	/* NOTE: If we can't figure out the declaration of the function being called, this is not 
+	 *       necessarily an internal compiler error. It could be because the symbol->datatype is NULL
+	 *       (because the ST code being analysed has an error _before_ this function invocation).
+	 *       However, we don't just give, up, we carry on recursivly analysing the code, so as to be
+	 *       able to print out any error messages related to the parameters being passed in this function 
+	 *       invocation.
+	 */
+	/* if (NULL == symbol->called_function_declaration) ERROR; */
+	if (fcall->candidate_datatypes.size() == 1) {
+		/* If only one function declaration, then we use that (even if symbol->datatypes == NULL)
+		 * so we can check for errors in the expressions used to pass parameters in this
+		 * function invocation.
+		 */
+		fcall_data.called_function_declaration = fcall_data.candidate_functions[0];
+	}
+
+	/* If an overloaded function is being invoked, and we cannot determine which version to use,
+	 * then we can not meaningfully verify the expressions used inside that function invocation.
+	 * We simply give up!
+	 */
+	if (NULL == fcall_data.called_function_declaration)
+		return;
+
+	if (NULL != fcall_data.nonformal_operand_list)  narrow_nonformal_call(fcall, fcall_data.called_function_declaration, &(fcall_data.extensible_param_count));
+	if (NULL != fcall_data.   formal_operand_list)     narrow_formal_call(fcall, fcall_data.called_function_declaration, &(fcall_data.extensible_param_count));
+
+	return;
+}
+
+
+
+
+/* narrow implicit FB call in IL.
+ * e.g.  CLK ton_var
+ *        CU counter_var
+ *
+ * The algorithm will be to build a fake il_fb_call_c equivalent to the implicit IL FB call, and let 
+ * the visit(il_fb_call_c *) method handle it!
+ */
+void *narrow_candidate_datatypes_c::narrow_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name, symbol_c *&called_fb_declaration) {
+
+	/* set the datatype of the il_operand, this is, the FB being called! */
+	if (NULL != il_operand) {
+		/* only set it if it is in the candidate datatypes list! */  
+		set_datatype(called_fb_declaration, il_operand);
+		il_operand->accept(*this);
+	}
+	symbol_c *fb_decl = il_operand->datatype;
+
+	if (0 == fake_prev_il_instruction->prev_il_instruction.size()) {
+		/* This IL implicit FB call (e.g. CLK ton_var) is not preceded by another IL instruction
+		 * (or list of instructions) that will set the IL current/default value.
+		 * We cannot proceed verifying type compatibility of something that does not exist.
+		 */
+		return NULL;
+	}
+
+	if (NULL == fb_decl) {
+		/* the il_operand is a not FB instance */
+		/* so we simply pass on the required datatype to the prev_il_instructions */
+		/* The invalid FB invocation will be caught in the print_datatypes_error_c by analysing NULL value in il_operand->datatype! */
+		set_datatype_in_prev_il_instructions(il_instruction->datatype, fake_prev_il_instruction);
+		return NULL;
+	}
+	
+
+	/* The value being passed to the 'param_name' parameter is actually the prev_il_instruction.
+	 * However, we do not place that object directly in the fake il_param_list_c that we will be
+	 * creating, since the visit(il_fb_call_c *) method will recursively call every object in that list.
+	 * The il_prev_intruction object will be visited once we have handled this implici IL FB call
+	 * (called from the instruction_list_c for() loop that works backwards). We DO NOT want to visit it twice.
+	 * (Anyway, if we let the visit(il_fb_call_c *) recursively visit the current prev_il_instruction, this pointer
+	 * would be changed to the IL instruction coming before the current prev_il_instruction! => things would get all messed up!)
+	 * The easiest way to work around this is to simply use a new object, and copy the relevant details to that object!
+	 */
+	symbol_c param_value = *fake_prev_il_instruction; /* copy the candidate_datatypes list ! */
+
+	identifier_c variable_name(param_name);
+	// SYM_REF1(il_assign_operator_c, variable_name)
+	il_assign_operator_c il_assign_operator(&variable_name);  
+	// SYM_REF3(il_param_assignment_c, il_assign_operator, il_operand, simple_instr_list)
+	il_param_assignment_c il_param_assignment(&il_assign_operator, &param_value/*il_operand*/, NULL);
+	il_param_list_c il_param_list;
+	il_param_list.add_element(&il_param_assignment);
+	// SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list, symbol_c *called_fb_declaration)
+	CAL_operator_c CAL_operator;
+	il_fb_call_c il_fb_call(&CAL_operator, il_operand, NULL, &il_param_list);
+	        
+	/* A FB call does not return any datatype, but the IL instructions that come after this
+	 * FB call may require a specific datatype in the il current/default variable, 
+	 * so we must pass this information up to the IL instruction before the FB call, since it will
+	 * be that IL instruction that will be required to produce the desired dtataype.
+	 *
+	 * The above will be done by the visit(il_fb_call_c *) method, so we must make sure to
+	 * correctly set up the il_fb_call.datatype variable!
+	 */
+	il_fb_call.called_fb_declaration = called_fb_declaration;
+	il_fb_call.accept(*this);
+
+	/* set the required datatype of the previous IL instruction! */
+	/* NOTE:
+	 * When handling these implicit IL calls, the parameter_value being passed to the FB parameter
+	 * is actually the prev_il_instruction.
+	 * 
+	 * However, since the FB call does not change the value in the current/default IL variable, this value
+	 * must also be used ny the IL instruction coming after this FB call.
+	 *
+	 * This means that we have two consumers/users for the same value. 
+	 * We must therefore check whether the datatype required by the IL instructions following this FB call 
+	 * is the same as that required for the first parameter. If not, then we have a semantic error,
+	 * and we set it to invalid_type_name.
+	 *
+	 * However, we only do that if:
+	 *  - The IL instruction that comes after this IL FB call actually asked this FB call for a specific 
+	 *     datatype in the current/default vairable, once this IL FB call returns.
+	 *     However, sometimes, (for e.g., this FB call is the last in the IL list) the subsequent FB to not aks this
+	 *     FB call for any datatype. In that case, then the datatype required to pass to the first parameter of the
+	 *     FB call must be left unchanged!
+	 */
+	if ((NULL == il_instruction->datatype) || (is_type_equal(param_value.datatype, il_instruction->datatype))) {
+		set_datatype_in_prev_il_instructions(param_value.datatype, fake_prev_il_instruction);
+	} else {
+		set_datatype_in_prev_il_instructions(&search_constant_type_c::invalid_type_name, fake_prev_il_instruction);
+	}
+	return NULL;
+}
+
+
+/* a helper function... */
+symbol_c *narrow_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.3 - Data types */
+/**********************/
+/********************************/
+/* B 1.3.3 - Derived data types */
+/********************************/
+/*  signed_integer DOTDOT signed_integer */
+// SYM_REF2(subrange_c, lower_limit, upper_limit)
+void *narrow_candidate_datatypes_c::visit(subrange_c *symbol) {
+	symbol->lower_limit->datatype = symbol->datatype;
+	symbol->lower_limit->accept(*this);
+	symbol->upper_limit->datatype = symbol->datatype;
+	symbol->upper_limit->accept(*this);
+	return NULL;
+}
+
+/* simple_specification ASSIGN constant */
+// SYM_REF2(simple_spec_init_c, simple_specification, constant)
+void *narrow_candidate_datatypes_c::visit(simple_spec_init_c *symbol) {
+	symbol_c *datatype = base_type(symbol->simple_specification); 
+	if (NULL != symbol->constant) {
+		int typeoffset = search_in_candidate_datatype_list(datatype, symbol->constant->candidate_datatypes);
+		if (typeoffset >= 0)
+			symbol->constant->datatype = symbol->constant->candidate_datatypes[typeoffset];
+	}
+	return NULL;
+}
+
+/*********************/
+/* B 1.4 - Variables */
+/*********************/
+
+/********************************************/
+/* B 1.4.1 - Directly Represented Variables */
+/********************************************/
+
+/*************************************/
+/* B 1.4.2 - Multi-element variables */
+/*************************************/
+/*  subscripted_variable '[' subscript_list ']' */
+// SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
+void *narrow_candidate_datatypes_c::visit(array_variable_c *symbol) {
+	/* we need to check the data types of the expressions used for the subscripts... */
+	symbol->subscript_list->accept(*this);
+	return NULL;
+}
+
+
+/* subscript_list ',' subscript */
+// SYM_LIST(subscript_list_c)
+void *narrow_candidate_datatypes_c::visit(subscript_list_c *symbol) {
+	for (int i = 0; i < symbol->n; i++) {
+		for (unsigned int k = 0; k < symbol->elements[i]->candidate_datatypes.size(); k++) {
+			if (is_ANY_INT_type(symbol->elements[i]->candidate_datatypes[k]))
+				symbol->elements[i]->datatype = symbol->elements[i]->candidate_datatypes[k];
+		}
+		symbol->elements[i]->accept(*this);
+	}
+	return NULL;  
+}
+
+
+
+/************************************/
+/* B 1.5 Program organization units */
+/************************************/
+/*********************/
+/* B 1.5.1 Functions */
+/*********************/
+void *narrow_candidate_datatypes_c::visit(function_declaration_c *symbol) {
+	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
+	symbol->var_declarations_list->accept(*this);
+	if (debug) printf("Narrowing candidate data types list in body of function %s\n", ((token_c *)(symbol->derived_function_name))->value);
+	symbol->function_body->accept(*this);
+	delete search_varfb_instance_type;
+	search_varfb_instance_type = NULL;
+	return NULL;
+}
+
+/***************************/
+/* B 1.5.2 Function blocks */
+/***************************/
+void *narrow_candidate_datatypes_c::visit(function_block_declaration_c *symbol) {
+	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
+	symbol->var_declarations->accept(*this);
+	if (debug) printf("Narrowing candidate data types list in body of FB %s\n", ((token_c *)(symbol->fblock_name))->value);
+	symbol->fblock_body->accept(*this);
+	delete search_varfb_instance_type;
+	search_varfb_instance_type = NULL;
+	return NULL;
+}
+
+/********************/
+/* B 1.5.3 Programs */
+/********************/
+void *narrow_candidate_datatypes_c::visit(program_declaration_c *symbol) {
+	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
+	symbol->var_declarations->accept(*this);
+	if (debug) printf("Narrowing candidate data types list in body of program %s\n", ((token_c *)(symbol->program_type_name))->value);
+	symbol->function_block_body->accept(*this);
+	delete search_varfb_instance_type;
+	search_varfb_instance_type = NULL;
+	return NULL;
+}
+
+
+/********************************/
+/* B 1.7 Configuration elements */
+/********************************/
+void *narrow_candidate_datatypes_c::visit(configuration_declaration_c *symbol) {
+	// TODO !!!
+	/* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */
+	return NULL;
+}
+
+
+/****************************************/
+/* B.2 - Language IL (Instruction List) */
+/****************************************/
+/***********************************/
+/* B 2.1 Instructions and Operands */
+/***********************************/
+
+/*| instruction_list il_instruction */
+// SYM_LIST(instruction_list_c)
+void *narrow_candidate_datatypes_c::visit(instruction_list_c *symbol) {
+	/* In order to execute the narrow algoritm correctly, we need to go through the instructions backwards,
+	 * so we can not use the base class' visitor 
+	 */
+	/* In order to execute the narrow algoritm correctly
+	 * in IL instruction lists containing JMPs to labels that come before the JMP instruction
+	 * itself, we need to run the narrow algorithm twice on the Instruction List.
+	 * e.g.:  ...
+	 *          ld 23
+	 *   label1:st byte_var
+	 *          ld 34
+	 *          JMP label1     
+	 *
+	 * Note that the second time we run the narrow, most of the datatypes are already filled
+	 * in, so it will be able to produce tha correct datatypes for the IL instruction referenced
+	 * by the label, as in the 2nd pass we already know the datatypes of the JMP instruction!
+	 */
+	for(int j = 0; j < 2; j++) {
+		for(int i = symbol->n-1; i >= 0; i--) {
+			symbol->elements[i]->accept(*this);
+		}
+	}
+	return NULL;
+}
+
+/* | label ':' [il_incomplete_instruction] eol_list */
+// SYM_REF2(il_instruction_c, label, il_instruction)
+// void *visit(instruction_list_c *symbol);
+void *narrow_candidate_datatypes_c::visit(il_instruction_c *symbol) {
+	if (NULL == symbol->il_instruction) {
+		/* this empty/null il_instruction cannot generate the desired datatype. We pass on the request to the previous il instruction. */
+		set_datatype_in_prev_il_instructions(symbol->datatype, symbol);
+	} else {
+		il_instruction_c tmp_prev_il_instruction(NULL, NULL);
+		/* the narrow algorithm will need access to the intersected candidate_datatype lists of all prev_il_instructions, as well as the 
+		 * list of the prev_il_instructions.
+		 * Instead of creating two 'global' (within the class) variables, we create a single il_instruction_c variable (fake_prev_il_instruction),
+		 * and shove that data into this single variable.
+		 */
+		tmp_prev_il_instruction.prev_il_instruction = symbol->prev_il_instruction;
+		intersect_prev_candidate_datatype_lists(&tmp_prev_il_instruction);
+		/* Tell the il_instruction the datatype that it must generate - this was chosen by the next il_instruction (remember: we are iterating backwards!) */
+		fake_prev_il_instruction = &tmp_prev_il_instruction;
+		symbol->il_instruction->datatype = symbol->datatype;
+		symbol->il_instruction->accept(*this);
+		fake_prev_il_instruction = NULL;
+	}
+	return NULL;
+}
+
+
+
+
+// void *visit(instruction_list_c *symbol);
+void *narrow_candidate_datatypes_c::visit(il_simple_operation_c *symbol) {
+	/* Tell the il_simple_operator the datatype that it must generate - this was chosen by the next il_instruction (we iterate backwards!) */
+	symbol->il_simple_operator->datatype = symbol->datatype;
+	/* recursive call to see whether data types are compatible */
+	il_operand = symbol->il_operand;
+	symbol->il_simple_operator->accept(*this);
+	il_operand = NULL;
+	return NULL;
+}
+
+/* | 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 *narrow_candidate_datatypes_c::visit(il_function_call_c *symbol) {
+	/* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction)
+	 * In order to be able to handle this without coding special cases, we will simply prepend that symbol
+	 * to the il_operand_list, and remove it after calling handle_function_call().
+	 * However, since handle_function_call() will be recursively calling all parameter, and we don't want
+	 * to do that for the prev_il_instruction (since it has already been visited by the fill_candidate_datatypes_c)
+	 * we create a new ____ symbol_c ____ object, and copy the relevant info to/from that object before/after
+	 * the call to handle_function_call().
+	 *
+	 * However, if no further paramters are given, then il_operand_list will be NULL, and we will
+	 * need to create a new object to hold the pointer to prev_il_instruction.
+	 * This change will also be undone later in print_datatypes_error_c.
+	 */
+	symbol_c param_value = *fake_prev_il_instruction; /* copy the candidate_datatypes list */
+	if (NULL == symbol->il_operand_list)  symbol->il_operand_list = new il_operand_list_c;
+	if (NULL == symbol->il_operand_list)  ERROR;
+
+	((list_c *)symbol->il_operand_list)->insert_element(&param_value, 0);
+
+	generic_function_call_t fcall_param = {
+		/* fcall_param.function_name               = */ symbol->function_name,
+		/* fcall_param.nonformal_operand_list      = */ symbol->il_operand_list,
+		/* fcall_param.formal_operand_list         = */ NULL,
+		/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_function,
+		/* fcall_param.candidate_functions         = */ symbol->candidate_functions,
+		/* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
+		/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
+	};
+
+	narrow_function_invocation(symbol, fcall_param);
+	set_datatype_in_prev_il_instructions(param_value.datatype, fake_prev_il_instruction);
+
+	/* Undo the changes to the abstract syntax tree we made above... */
+	((list_c *)symbol->il_operand_list)->remove_element(0);
+	if (((list_c *)symbol->il_operand_list)->n == 0) {
+		/* if the list becomes empty, then that means that it did not exist before we made these changes, so we delete it! */
+		delete 	symbol->il_operand_list;
+		symbol->il_operand_list = NULL;
+	}
+
+	return NULL;
+}
+
+
+/* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */
+// SYM_REF3(il_expression_c, il_expr_operator, il_operand, simple_instr_list);
+void *narrow_candidate_datatypes_c::visit(il_expression_c *symbol) {
+  /* first handle the operation (il_expr_operator) that will use the result coming from the parenthesised IL list (i.e. simple_instr_list) */
+  symbol->il_expr_operator->datatype = symbol->datatype;
+  il_operand = symbol->simple_instr_list; /* This is not a bug! The parenthesised expression will be used as the operator! */
+  symbol->il_expr_operator->accept(*this);
+
+  /* now give the parenthesised IL list a chance to narrow the datatypes */
+  /* The datatype that is must return was set by the call symbol->il_expr_operator->accept(*this) */
+  il_instruction_c *save_fake_prev_il_instruction = fake_prev_il_instruction; /*this is not really necessary, but lets play it safe */
+  symbol->simple_instr_list->accept(*this);
+  fake_prev_il_instruction = save_fake_prev_il_instruction;
+  return NULL;
+}
+
+
+
+
+/*  il_jump_operator label */
+void *narrow_candidate_datatypes_c::visit(il_jump_operation_c *symbol) {
+  /* recursive call to fill the datatype */
+  symbol->il_jump_operator->datatype = symbol->datatype;
+  symbol->il_jump_operator->accept(*this);
+  return NULL;
+}
+
+
+
+
+
+
+
+/*   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 *narrow_candidate_datatypes_c::visit(il_fb_call_c *symbol) {
+	symbol_c *fb_decl = symbol->called_fb_declaration;
+	
+	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
+	if (NULL == fb_decl) ERROR;
+	if (NULL != symbol->il_operand_list)  narrow_nonformal_call(symbol, fb_decl);
+	if (NULL != symbol->  il_param_list)     narrow_formal_call(symbol, fb_decl);
+
+	/* Let the il_call_operator (CAL, CALC, or CALCN) set the datatype of prev_il_instruction... */
+	symbol->il_call_operator->datatype = symbol->datatype;
+	symbol->il_call_operator->accept(*this);
+	return NULL;
+}
+
+
+/* | 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 *narrow_candidate_datatypes_c::visit(il_formal_funct_call_c *symbol) {
+	generic_function_call_t fcall_param = {
+		/* fcall_param.function_name               = */ symbol->function_name,
+		/* fcall_param.nonformal_operand_list      = */ NULL,
+		/* fcall_param.formal_operand_list         = */ symbol->il_param_list,
+		/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_function,
+		/* fcall_param.candidate_functions         = */ symbol->candidate_functions,
+		/* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
+		/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
+	};
+  
+	narrow_function_invocation(symbol, fcall_param);
+	/* The desired datatype of the previous il instruction was already set by narrow_function_invocation() */
+	return NULL;
+}
+
+
+//     void *visit(il_operand_list_c *symbol);
+
+
+/* | simple_instr_list il_simple_instruction */
+/* This object is referenced by il_expression_c objects */
+void *narrow_candidate_datatypes_c::visit(simple_instr_list_c *symbol) {
+	if (symbol->n > 0)
+		symbol->elements[symbol->n - 1]->datatype = symbol->datatype;
+
+	for(int i = symbol->n-1; i >= 0; i--) {
+		symbol->elements[i]->accept(*this);
+	}
+	return NULL;
+}
+
+
+// SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;)
+void *narrow_candidate_datatypes_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! */
+    
+  il_instruction_c tmp_prev_il_instruction(NULL, NULL);
+  /* the narrow algorithm will need access to the intersected candidate_datatype lists of all prev_il_instructions, as well as the 
+   * list of the prev_il_instructions.
+   * Instead of creating two 'global' (within the class) variables, we create a single il_instruction_c variable (fake_prev_il_instruction),
+   * and shove that data into this single variable.
+   */
+  if (symbol->prev_il_instruction.size() > 0)
+    tmp_prev_il_instruction.candidate_datatypes = symbol->prev_il_instruction[0]->candidate_datatypes;
+  tmp_prev_il_instruction.prev_il_instruction = symbol->prev_il_instruction;
+  
+   /* copy the candidate_datatypes list */
+  fake_prev_il_instruction = &tmp_prev_il_instruction;
+  symbol->il_simple_instruction->datatype = symbol->datatype;
+  symbol->il_simple_instruction->accept(*this);
+  fake_prev_il_instruction = NULL;
+  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 *narrow_candidate_datatypes_c::narrow_binary_operator(const struct widen_entry widen_table[], symbol_c *symbol, bool *deprecated_operation) {
+	symbol_c *prev_instruction_type, *operand_type;
+	int count = 0;
+
+	if (NULL == symbol->datatype)
+		/* next IL instructions were unable to determine the datatype this instruction should produce */
+		return NULL;
+
+        if (NULL != deprecated_operation)
+		*deprecated_operation = false;
+
+	/* NOTE 1: the il_operand __may__ be pointing to a parenthesized list of IL instructions. 
+	 * e.g.  LD 33
+	 *       AND ( 45
+	 *            OR 56
+	 *            )
+	 *       When we handle the first 'AND' IL_operator, the il_operand will point to an simple_instr_list_c.
+	 *       In this case, when we call il_operand->accept(*this);, the prev_il_instruction pointer will be overwritten!
+	 *
+	 *       We must therefore set the prev_il_instruction->datatype = symbol->datatype;
+	 *       __before__ calling il_operand->accept(*this) !!
+	 *
+	 * NOTE 2: We do not need to call prev_il_instruction->accept(*this), as the object to which prev_il_instruction
+	 *         is pointing to will be later narrowed by the call from the for() loop of the instruction_list_c
+	 *         (or simple_instr_list_c), which iterates backwards.
+	 */
+	for(unsigned int i = 0; i < fake_prev_il_instruction->candidate_datatypes.size(); i++) {
+		for(unsigned int j = 0; j < il_operand->candidate_datatypes.size(); j++) {
+			prev_instruction_type = fake_prev_il_instruction->candidate_datatypes[i];
+			operand_type = il_operand->candidate_datatypes[j];
+			if (is_widening_compatible(widen_table, prev_instruction_type, operand_type, symbol->datatype, deprecated_operation)) {
+				/* set the desired datatype of the previous il instruction */
+				set_datatype_in_prev_il_instructions(prev_instruction_type, fake_prev_il_instruction);
+				/* set the datatype for the operand */
+				il_operand->datatype = operand_type;
+				
+				count ++;
+			}
+		}
+	}
+// 	if (count > 1) ERROR; /* Since we also support SAFE data types, this assertion is not necessarily always tru! */
+	if (is_type_valid(symbol->datatype) && (count <= 0)) ERROR;
+
+	il_operand->accept(*this);
+	return NULL;
+}
+
+
+
+
+
+void *narrow_candidate_datatypes_c::handle_il_instruction(symbol_c *symbol) {
+	if (NULL == symbol->datatype)
+		/* next IL instructions were unable to determine the datatype this instruction should produce */
+		return NULL;
+	/* NOTE 1: the il_operand __may__ be pointing to a parenthesized list of IL instructions. 
+	 * e.g.  LD 33
+	 *       AND ( 45
+	 *            OR 56
+	 *            )
+	 *       When we handle the first 'AND' IL_operator, the il_operand will point to an simple_instr_list_c.
+	 *       In this case, when we call il_operand->accept(*this);, the prev_il_instruction pointer will be overwritten!
+	 *
+	 *       We must therefore set the prev_il_instruction->datatype = symbol->datatype;
+	 *       __before__ calling il_operand->accept(*this) !!
+	 *
+	 * NOTE 2: We do not need to call prev_il_instruction->accept(*this), as the object to which prev_il_instruction
+	 *         is pointing to will be later narrowed by the call from the for() loop of the instruction_list_c
+	 *         (or simple_instr_list_c), which iterates backwards.
+	 */
+	/* set the desired datatype of the previous il instruction */
+	set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
+	  
+	/* set the datatype for the operand */
+	il_operand->datatype = symbol->datatype;
+	il_operand->accept(*this);
+	return NULL;
+}
+
+
+
+
+void *narrow_candidate_datatypes_c::visit(LD_operator_c *symbol)   {
+	if (NULL == symbol->datatype)
+		/* next IL instructions were unable to determine the datatype this instruction should produce */
+		return NULL;
+	/* set the datatype for the operand */
+	il_operand->datatype = symbol->datatype;
+	il_operand->accept(*this);
+	return NULL;
+}
+
+
+void *narrow_candidate_datatypes_c::visit(LDN_operator_c *symbol)  {
+	if (NULL == symbol->datatype)
+		/* next IL instructions were unable to determine the datatype this instruction should produce */
+		return NULL;
+	/* set the datatype for the operand */
+	il_operand->datatype = symbol->datatype;
+	il_operand->accept(*this);
+	return NULL;
+}
+
+void *narrow_candidate_datatypes_c::visit(ST_operator_c *symbol) {
+	if (symbol->candidate_datatypes.size() != 1)
+		return NULL;
+	symbol->datatype = symbol->candidate_datatypes[0];
+	/* set the datatype for the operand */
+	il_operand->datatype = symbol->datatype;
+	il_operand->accept(*this);
+	/* set the desired datatype of the previous il instruction */
+	set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
+	return NULL;
+}
+
+void *narrow_candidate_datatypes_c::visit(STN_operator_c *symbol) {
+	if (symbol->candidate_datatypes.size() != 1)
+		return NULL;
+	symbol->datatype = symbol->candidate_datatypes[0];
+	/* set the datatype for the operand */
+	il_operand->datatype = symbol->datatype;
+	il_operand->accept(*this);
+	/* set the desired datatype of the previous il instruction */
+	set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
+	return NULL;
+}
+
+void *narrow_candidate_datatypes_c::visit(NOT_operator_c *symbol) {
+	/* 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!
+	 */
+	/* We do not change the data type, we simply invert the bits in bit types! */
+	/* So, we set the desired datatype of the previous il instruction */
+	set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
+	return NULL;
+}
+
+void *narrow_candidate_datatypes_c::visit(S_operator_c *symbol)  {
+  /* TODO: what if this is a FB call? */
+	return handle_il_instruction(symbol);
+}
+void *narrow_candidate_datatypes_c::visit(R_operator_c *symbol)  {
+  /* TODO: what if this is a FB call? */
+	return handle_il_instruction(symbol);
+}
+
+
+void *narrow_candidate_datatypes_c::visit(  S1_operator_c *symbol)  {return narrow_implicit_il_fb_call(symbol, "S1",  symbol->called_fb_declaration);}
+void *narrow_candidate_datatypes_c::visit(  R1_operator_c *symbol)  {return narrow_implicit_il_fb_call(symbol, "R1",  symbol->called_fb_declaration);}
+void *narrow_candidate_datatypes_c::visit( CLK_operator_c *symbol)  {return narrow_implicit_il_fb_call(symbol, "CLK", symbol->called_fb_declaration);}
+void *narrow_candidate_datatypes_c::visit(  CU_operator_c *symbol)  {return narrow_implicit_il_fb_call(symbol, "CU",  symbol->called_fb_declaration);}
+void *narrow_candidate_datatypes_c::visit(  CD_operator_c *symbol)  {return narrow_implicit_il_fb_call(symbol, "CD",  symbol->called_fb_declaration);}
+void *narrow_candidate_datatypes_c::visit(  PV_operator_c *symbol)  {return narrow_implicit_il_fb_call(symbol, "PV",  symbol->called_fb_declaration);}
+void *narrow_candidate_datatypes_c::visit(  IN_operator_c *symbol)  {return narrow_implicit_il_fb_call(symbol, "IN",  symbol->called_fb_declaration);}
+void *narrow_candidate_datatypes_c::visit(  PT_operator_c *symbol)  {return narrow_implicit_il_fb_call(symbol, "PT",  symbol->called_fb_declaration);}
+
+void *narrow_candidate_datatypes_c::visit( AND_operator_c *symbol)  {return narrow_binary_operator(widen_AND_table, symbol);}
+void *narrow_candidate_datatypes_c::visit(  OR_operator_c *symbol)  {return narrow_binary_operator( widen_OR_table, symbol);}
+void *narrow_candidate_datatypes_c::visit( XOR_operator_c *symbol)  {return narrow_binary_operator(widen_XOR_table, symbol);}
+void *narrow_candidate_datatypes_c::visit(ANDN_operator_c *symbol)  {return narrow_binary_operator(widen_AND_table, symbol);}
+void *narrow_candidate_datatypes_c::visit( ORN_operator_c *symbol)  {return narrow_binary_operator( widen_OR_table, symbol);}
+void *narrow_candidate_datatypes_c::visit(XORN_operator_c *symbol)  {return narrow_binary_operator(widen_XOR_table, symbol);}
+void *narrow_candidate_datatypes_c::visit( ADD_operator_c *symbol)  {return narrow_binary_operator(widen_ADD_table, symbol, &(symbol->deprecated_operation));}
+void *narrow_candidate_datatypes_c::visit( SUB_operator_c *symbol)  {return narrow_binary_operator(widen_SUB_table, symbol, &(symbol->deprecated_operation));}
+void *narrow_candidate_datatypes_c::visit( MUL_operator_c *symbol)  {return narrow_binary_operator(widen_MUL_table, symbol, &(symbol->deprecated_operation));}
+void *narrow_candidate_datatypes_c::visit( DIV_operator_c *symbol)  {return narrow_binary_operator(widen_DIV_table, symbol, &(symbol->deprecated_operation));}
+void *narrow_candidate_datatypes_c::visit( MOD_operator_c *symbol)  {return narrow_binary_operator(widen_MOD_table, symbol);}
+void *narrow_candidate_datatypes_c::visit(  GT_operator_c *symbol)  {return narrow_binary_operator(widen_CMP_table, symbol);}
+void *narrow_candidate_datatypes_c::visit(  GE_operator_c *symbol)  {return narrow_binary_operator(widen_CMP_table, symbol);}
+void *narrow_candidate_datatypes_c::visit(  EQ_operator_c *symbol)  {return narrow_binary_operator(widen_CMP_table, symbol);}
+void *narrow_candidate_datatypes_c::visit(  LT_operator_c *symbol)  {return narrow_binary_operator(widen_CMP_table, symbol);}
+void *narrow_candidate_datatypes_c::visit(  LE_operator_c *symbol)  {return narrow_binary_operator(widen_CMP_table, symbol);}
+void *narrow_candidate_datatypes_c::visit(  NE_operator_c *symbol)  {return narrow_binary_operator(widen_CMP_table, symbol);}
+
+
+
+
+void *narrow_candidate_datatypes_c::narrow_conditional_flow_control_IL_instruction(symbol_c *symbol) {
+	/* if the next IL instructions needs us to provide a datatype other than a bool, 
+	 * then we have an internal compiler error - most likely in fill_candidate_datatypes_c 
+	 */
+	if ((NULL != symbol->datatype) && (!is_ANY_BOOL_compatible(symbol->datatype))) ERROR;
+	if (symbol->candidate_datatypes.size() > 1) ERROR;
+
+	/* NOTE: If there is no IL instruction following this CALC, CALCN, JMPC, JMPC, ..., instruction,
+	 *       we must still provide a bool_type_name_c datatype (if possible, i.e. if it exists in the candidate datatype list).
+	 *       If it is not possible, we set it to NULL
+	 */
+	if (symbol->candidate_datatypes.size() == 0)    symbol->datatype = NULL;
+	else    symbol->datatype = symbol->candidate_datatypes[0]; /* i.e. a bool_type_name_c! */
+	if ((NULL != symbol->datatype) && (!is_ANY_BOOL_compatible(symbol->datatype))) ERROR;
+
+	/* set the required datatype of the previous IL instruction, i.e. a bool_type_name_c! */
+	set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
+	return NULL;
+}
+
+
+// SYM_REF0(CAL_operator_c)
+// SYM_REF0(CALC_operator_c)
+// SYM_REF0(CALCN_operator_c)
+/* called from visit(il_fb_call_c *) {symbol->il_call_operator->accpet(*this)} */
+/* NOTE: The CAL, JMP and RET instructions simply set the desired datatype of the previous il instruction since they do not change the value in the current/default IL variable */
+/* called from il_fb_call_c (symbol->il_call_operator->accpet(*this) ) */
+void *narrow_candidate_datatypes_c::visit(  CAL_operator_c *symbol) {set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction); return NULL;}
+void *narrow_candidate_datatypes_c::visit(  RET_operator_c *symbol) {set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction); return NULL;}
+void *narrow_candidate_datatypes_c::visit(  JMP_operator_c *symbol) {set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction); return NULL;}
+void *narrow_candidate_datatypes_c::visit( CALC_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(CALCN_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit( RETC_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(RETCN_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit( JMPC_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(symbol);}
+void *narrow_candidate_datatypes_c::visit(JMPCN_operator_c *symbol) {return narrow_conditional_flow_control_IL_instruction(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 *narrow_candidate_datatypes_c::narrow_binary_expression(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr, bool *deprecated_operation) {
+	symbol_c *l_type, *r_type;
+	int count = 0;
+
+        if (NULL != deprecated_operation)
+		*deprecated_operation = false;
+
+	for(unsigned int i = 0; i < l_expr->candidate_datatypes.size(); i++) {
+		for(unsigned int j = 0; j < r_expr->candidate_datatypes.size(); j++) {
+			/* test widening compatibility */
+			l_type = l_expr->candidate_datatypes[i];
+			r_type = r_expr->candidate_datatypes[j];
+			if (is_widening_compatible(widen_table, l_type, r_type, symbol->datatype, deprecated_operation)) {
+				l_expr->datatype = l_type;
+				r_expr->datatype = r_type;
+				count ++;
+			}
+		}
+	}
+// 	if (count > 1) ERROR; /* Since we also support SAFE data types, this assertion is not necessarily always tru! */
+	if (is_type_valid(symbol->datatype) && (count <= 0)) ERROR;
+	
+	l_expr->accept(*this);
+	r_expr->accept(*this);
+	return NULL;
+}
+
+
+
+void *narrow_candidate_datatypes_c::visit(    or_expression_c *symbol) {return narrow_binary_expression( widen_OR_table, symbol, symbol->l_exp, symbol->r_exp);}
+void *narrow_candidate_datatypes_c::visit(   xor_expression_c *symbol) {return narrow_binary_expression(widen_XOR_table, symbol, symbol->l_exp, symbol->r_exp);}
+void *narrow_candidate_datatypes_c::visit(   and_expression_c *symbol) {return narrow_binary_expression(widen_AND_table, symbol, symbol->l_exp, symbol->r_exp);}
+
+void *narrow_candidate_datatypes_c::visit(   equ_expression_c *symbol) {return narrow_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
+void *narrow_candidate_datatypes_c::visit(notequ_expression_c *symbol) {return narrow_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
+void *narrow_candidate_datatypes_c::visit(    lt_expression_c *symbol) {return narrow_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
+void *narrow_candidate_datatypes_c::visit(    gt_expression_c *symbol) {return narrow_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
+void *narrow_candidate_datatypes_c::visit(    le_expression_c *symbol) {return narrow_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
+void *narrow_candidate_datatypes_c::visit(    ge_expression_c *symbol) {return narrow_binary_expression(widen_CMP_table, symbol, symbol->l_exp, symbol->r_exp);}
+
+void *narrow_candidate_datatypes_c::visit(   add_expression_c *symbol) {return narrow_binary_expression(widen_ADD_table, symbol, symbol->l_exp, symbol->r_exp, &symbol->deprecated_operation);}
+void *narrow_candidate_datatypes_c::visit(   sub_expression_c *symbol) {return narrow_binary_expression(widen_SUB_table, symbol, symbol->l_exp, symbol->r_exp, &symbol->deprecated_operation);}
+void *narrow_candidate_datatypes_c::visit(   mul_expression_c *symbol) {return narrow_binary_expression(widen_MUL_table, symbol, symbol->l_exp, symbol->r_exp, &symbol->deprecated_operation);}
+void *narrow_candidate_datatypes_c::visit(   div_expression_c *symbol) {return narrow_binary_expression(widen_DIV_table, symbol, symbol->l_exp, symbol->r_exp, &symbol->deprecated_operation);}
+void *narrow_candidate_datatypes_c::visit(   mod_expression_c *symbol) {return narrow_binary_expression(widen_MOD_table, symbol, symbol->l_exp, symbol->r_exp);}
+void *narrow_candidate_datatypes_c::visit( power_expression_c *symbol) {return narrow_binary_expression(widen_EXPT_table,symbol, symbol->l_exp, symbol->r_exp);}
+
+
+void *narrow_candidate_datatypes_c::visit(neg_expression_c *symbol) {
+	symbol->exp->datatype = symbol->datatype;
+	symbol->exp->accept(*this);
+	return NULL;
+}
+
+
+void *narrow_candidate_datatypes_c::visit(not_expression_c *symbol) {
+	symbol->exp->datatype = symbol->datatype;
+	symbol->exp->accept(*this);
+	return NULL;
+}
+
+
+
+/* NOTE: The parameter 'called_function_declaration', 'extensible_param_count' and 'candidate_functions' are used to pass data between the stage 3 and stage 4. */
+/*    formal_param_list -> may be NULL ! */
+/* nonformal_param_list -> may be NULL ! */
+// 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;)
+void *narrow_candidate_datatypes_c::visit(function_invocation_c *symbol) {
+	generic_function_call_t fcall_param = {
+		/* fcall_param.function_name               = */ symbol->function_name,
+		/* fcall_param.nonformal_operand_list      = */ symbol->nonformal_param_list,
+		/* fcall_param.formal_operand_list         = */ symbol->formal_param_list,
+		/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_function,
+		/* fcall_param.candidate_functions         = */ symbol->candidate_functions,
+		/* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
+		/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
+	};
+  
+	narrow_function_invocation(symbol, fcall_param);
+	return NULL;
+}
+
+/********************/
+/* B 3.2 Statements */
+/********************/
+
+
+/*********************************/
+/* B 3.2.1 Assignment Statements */
+/*********************************/
+
+void *narrow_candidate_datatypes_c::visit(assignment_statement_c *symbol) {
+	if (symbol->candidate_datatypes.size() != 1)
+		return NULL;
+	symbol->datatype = symbol->candidate_datatypes[0];
+	symbol->l_exp->datatype = symbol->datatype;
+	symbol->l_exp->accept(*this);
+	symbol->r_exp->datatype = symbol->datatype;
+	symbol->r_exp->accept(*this);
+	return NULL;
+}
+
+
+/*****************************************/
+/* B 3.2.2 Subprogram Control Statements */
+/*****************************************/
+
+void *narrow_candidate_datatypes_c::visit(fb_invocation_c *symbol) {
+	/* Note: We do not use the symbol->called_fb_declaration value (set in fill_candidate_datatypes_c)
+	 *       because we try to identify any other datatype errors in the expressions used in the 
+	 *       parameters to the FB call (e.g.  fb_var(var1 * 56 + func(var * 43)) )
+	 *       even it the call to the FB is invalid. 
+	 *       This makes sense because it may be errors in those expressions which are
+	 *       making this an invalid call, so it makes sense to point them out to the user!
+	 */
+	symbol_c *fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name);
+
+	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
+	if (NULL == fb_decl) ERROR;
+	if (NULL != symbol->nonformal_param_list)  narrow_nonformal_call(symbol, fb_decl);
+	if (NULL != symbol->   formal_param_list)     narrow_formal_call(symbol, fb_decl);
+
+	return NULL;
+}
+
+
+/********************************/
+/* B 3.2.3 Selection Statements */
+/********************************/
+
+void *narrow_candidate_datatypes_c::visit(if_statement_c *symbol) {
+	for(unsigned int i = 0; i < symbol->expression->candidate_datatypes.size(); i++) {
+		if (is_ANY_BOOL_compatible(symbol->expression->candidate_datatypes[i]))
+			symbol->expression->datatype = symbol->expression->candidate_datatypes[i];
+	}
+	symbol->expression->accept(*this);
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	if (NULL != symbol->elseif_statement_list)
+		symbol->elseif_statement_list->accept(*this);
+	if (NULL != symbol->else_statement_list)
+		symbol->else_statement_list->accept(*this);
+	return NULL;
+}
+
+
+void *narrow_candidate_datatypes_c::visit(elseif_statement_c *symbol) {
+	for (unsigned int i = 0; i < symbol->expression->candidate_datatypes.size(); i++) {
+		if (is_ANY_BOOL_compatible(symbol->expression->candidate_datatypes[i]))
+			symbol->expression->datatype = symbol->expression->candidate_datatypes[i];
+	}
+	symbol->expression->accept(*this);
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	return NULL;
+}
+
+/* CASE expression OF case_element_list ELSE statement_list END_CASE */
+// SYM_REF3(case_statement_c, expression, case_element_list, statement_list)
+void *narrow_candidate_datatypes_c::visit(case_statement_c *symbol) {
+	for (unsigned int i = 0; i < symbol->expression->candidate_datatypes.size(); i++) {
+		if ((is_ANY_INT_type(symbol->expression->candidate_datatypes[i]))
+				 || (search_base_type.type_is_enumerated(symbol->expression->candidate_datatypes[i])))
+			symbol->expression->datatype = symbol->expression->candidate_datatypes[i];
+	}
+	symbol->expression->accept(*this);
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	if (NULL != symbol->case_element_list) {
+		symbol->case_element_list->datatype = symbol->expression->datatype;
+		symbol->case_element_list->accept(*this);
+	}
+	return NULL;
+}
+
+/* helper symbol for case_statement */
+// SYM_LIST(case_element_list_c)
+void *narrow_candidate_datatypes_c::visit(case_element_list_c *symbol) {
+	for (int i = 0; i < symbol->n; i++) {
+		symbol->elements[i]->datatype = symbol->datatype;
+		symbol->elements[i]->accept(*this);
+	}
+	return NULL;
+}
+
+/*  case_list ':' statement_list */
+// SYM_REF2(case_element_c, case_list, statement_list)
+void *narrow_candidate_datatypes_c::visit(case_element_c *symbol) {
+	symbol->case_list->datatype = symbol->datatype;
+	symbol->case_list->accept(*this);
+	symbol->statement_list->accept(*this);
+	return NULL;
+}
+
+// SYM_LIST(case_list_c)
+void *narrow_candidate_datatypes_c::visit(case_list_c *symbol) {
+	for (int i = 0; i < symbol->n; i++) {
+		for (unsigned int k = 0; k < symbol->elements[i]->candidate_datatypes.size(); k++) {
+			if (is_type_equal(symbol->datatype, symbol->elements[i]->candidate_datatypes[k]))
+				symbol->elements[i]->datatype = symbol->elements[i]->candidate_datatypes[k];
+		}
+		/* NOTE: this may be an integer, a subrange_c, or a enumerated value! */
+		symbol->elements[i]->accept(*this);
+	}
+	return NULL;
+}
+
+
+/********************************/
+/* B 3.2.4 Iteration Statements */
+/********************************/
+void *narrow_candidate_datatypes_c::visit(for_statement_c *symbol) {
+	/* Control variable */
+	for(unsigned int i = 0; i < symbol->control_variable->candidate_datatypes.size(); i++) {
+		if (is_ANY_INT_type(symbol->control_variable->candidate_datatypes[i])) {
+			symbol->control_variable->datatype = symbol->control_variable->candidate_datatypes[i];
+		}
+	}
+	symbol->control_variable->accept(*this);
+	/* BEG expression */
+	for(unsigned int i = 0; i < symbol->beg_expression->candidate_datatypes.size(); i++) {
+		if (is_type_equal(symbol->control_variable->datatype,symbol->beg_expression->candidate_datatypes[i]) &&
+				is_ANY_INT_type(symbol->beg_expression->candidate_datatypes[i])) {
+			symbol->beg_expression->datatype = symbol->beg_expression->candidate_datatypes[i];
+		}
+	}
+	symbol->beg_expression->accept(*this);
+	/* END expression */
+	for(unsigned int i = 0; i < symbol->end_expression->candidate_datatypes.size(); i++) {
+		if (is_type_equal(symbol->control_variable->datatype,symbol->end_expression->candidate_datatypes[i]) &&
+				is_ANY_INT_type(symbol->end_expression->candidate_datatypes[i])) {
+			symbol->end_expression->datatype = symbol->end_expression->candidate_datatypes[i];
+		}
+	}
+	symbol->end_expression->accept(*this);
+	/* BY expression */
+	if (NULL != symbol->by_expression) {
+		for(unsigned int i = 0; i < symbol->by_expression->candidate_datatypes.size(); i++) {
+			if (is_type_equal(symbol->control_variable->datatype,symbol->by_expression->candidate_datatypes[i]) &&
+					is_ANY_INT_type(symbol->by_expression->candidate_datatypes[i])) {
+				symbol->by_expression->datatype = symbol->by_expression->candidate_datatypes[i];
+			}
+		}
+		symbol->by_expression->accept(*this);
+	}
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	return NULL;
+}
+
+void *narrow_candidate_datatypes_c::visit(while_statement_c *symbol) {
+	for (unsigned int i = 0; i < symbol->expression->candidate_datatypes.size(); i++) {
+		if(is_BOOL_type(symbol->expression->candidate_datatypes[i]))
+			symbol->expression->datatype = symbol->expression->candidate_datatypes[i];
+	}
+	symbol->expression->accept(*this);
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	return NULL;
+}
+
+void *narrow_candidate_datatypes_c::visit(repeat_statement_c *symbol) {
+	for (unsigned int i = 0; i < symbol->expression->candidate_datatypes.size(); i++) {
+		if(is_BOOL_type(symbol->expression->candidate_datatypes[i]))
+			symbol->expression->datatype = symbol->expression->candidate_datatypes[i];
+	}
+	symbol->expression->accept(*this);
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	return NULL;
+}
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/narrow_candidate_datatypes.hh	Sat Mar 31 15:36:08 2012 +0100
@@ -0,0 +1,242 @@
+/*
+ *  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)
+ *
+ */
+
+
+#include "../absyntax_utils/absyntax_utils.hh"
+#include "datatype_functions.hh"
+
+class narrow_candidate_datatypes_c: public iterator_visitor_c {
+
+  private:
+    search_varfb_instance_type_c *search_varfb_instance_type;
+    search_base_type_c search_base_type;
+    symbol_c *il_operand;
+    il_instruction_c *fake_prev_il_instruction;
+    std::vector <symbol_c *> *prev_il_instructions;
+    std::vector <symbol_c *> *prev_il_instructions_intersected_datatypes;
+
+    bool is_widening_compatible(const struct widen_entry widen_table[], symbol_c *left_type, symbol_c *right_type, symbol_c *result_type, bool *deprecated_status = NULL);
+
+    void  narrow_function_invocation(symbol_c *f_call, generic_function_call_t fcall_data);
+    void  narrow_nonformal_call(symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count = NULL);
+    void  narrow_formal_call(symbol_c *f_call, symbol_c *f_decl, int *ext_parm_count = NULL);
+    void *narrow_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name, symbol_c *&called_fb_declaration);
+
+    void *handle_il_instruction(symbol_c *symbol);
+    void *narrow_binary_operator  (const struct widen_entry widen_table[], symbol_c *symbol,                                     bool *deprecated_operation = NULL);
+    void *narrow_binary_expression(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr, bool *deprecated_operation = NULL);
+
+    void *narrow_conditional_flow_control_IL_instruction(symbol_c *symbol);
+
+
+  public:
+    narrow_candidate_datatypes_c(symbol_c *ignore);
+    virtual ~narrow_candidate_datatypes_c(void);
+
+    symbol_c *base_type(symbol_c *symbol);
+
+    /**********************/
+    /* B 1.3 - Data types */
+    /**********************/
+    /********************************/
+    /* B 1.3.3 - Derived data types */
+    /********************************/
+    void *visit(subrange_c *symbol);
+    void *visit(simple_spec_init_c *symbol);
+
+    /*********************/
+    /* B 1.4 - Variables */
+    /*********************/
+    /********************************************/
+    /* B 1.4.1 - Directly Represented Variables */
+    /********************************************/
+    /*************************************/
+    /* B 1.4.2 - Multi-element variables */
+    /*************************************/
+    void *visit(array_variable_c *symbol);
+    void *visit(subscript_list_c *symbol);
+
+    /**************************************/
+    /* B 1.5 - Program organization 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);
+
+    /********************************/
+    /* B 1.7 Configuration elements */
+    /********************************/
+    void *visit(configuration_declaration_c *symbol);
+    /****************************************/
+    /* 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_jump_operation_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);
+
+    /*******************/
+    /* 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);
+
+    /*********************************/
+    /* B 3.2.1 Assignment Statements */
+    /*********************************/
+    void *visit(assignment_statement_c *symbol);
+
+    /*****************************************/
+    /* B 3.2.2 Subprogram Control Statements */
+    /*****************************************/
+    void *visit(fb_invocation_c *symbol);
+    
+    /********************************/
+    /* B 3.2.3 Selection Statements */
+    /********************************/
+    void *visit(if_statement_c *symbol);
+    void *visit(elseif_statement_c *symbol);
+    void *visit(case_statement_c *symbol);
+    void *visit(case_element_list_c *symbol);
+    void *visit(case_element_c *symbol);
+    void *visit(case_list_c *symbol);
+
+    /********************************/
+    /* B 3.2.4 Iteration Statements */
+    /********************************/
+    void *visit(for_statement_c *symbol);
+    void *visit(while_statement_c *symbol);
+    void *visit(repeat_statement_c *symbol);
+
+}; // narrow_candidate_datatypes_c
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/print_datatypes_error.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -0,0 +1,1233 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2009-2011  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2011-2012 Manuele Conti (manuele.conti@sirius-es.it)
+ *  Copyright (C) 2011-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)
+ *
+ */
+
+
+/*
+ *  Fill candidate list of data types for all symbols
+ */
+
+#include "print_datatypes_error.hh"
+#include "datatype_functions.hh"
+
+#include <typeinfo>
+#include <list>
+#include <string>
+#include <string.h>
+#include <strings.h>
+
+
+
+
+
+
+#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");                                                                                                  \
+    il_error = true;                                                                                                        \
+    error_found = true;                                                                                                     \
+  }                                                                                                                         \
+}  
+
+
+#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;                                                                                                   \
+}  
+
+
+/* set to 1 to see debug info during execution */
+static int debug = 0;
+
+print_datatypes_error_c::print_datatypes_error_c(symbol_c *ignore) {
+	error_found = false;
+	warning_found = false;
+	current_display_error_level = error_level_default;
+}
+
+print_datatypes_error_c::~print_datatypes_error_c(void) {
+}
+
+int print_datatypes_error_c::get_error_found() {
+	return error_found;
+}
+
+
+
+
+
+/* Verify if the datatypes of all prev_il_instructions are valid and equal!  */
+static bool are_all_datatypes_of_prev_il_instructions_datatypes_equal(il_instruction_c *symbol) {
+	if (NULL == symbol) ERROR;
+	bool res;
+	
+	if (symbol->prev_il_instruction.size() > 0)
+		res = is_type_valid(symbol->prev_il_instruction[0]->datatype);
+
+	for (unsigned int i = 1; i < symbol->prev_il_instruction.size(); i++)
+		res &= is_type_equal(symbol->prev_il_instruction[i-1]->datatype, symbol->prev_il_instruction[i]->datatype);
+	
+	return res;
+}
+
+
+
+
+/* a helper function... */
+symbol_c *print_datatypes_error_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);
+}
+
+
+
+/*
+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 print_datatypes_error_c::handle_function_invocation(symbol_c *fcall, generic_function_call_t fcall_data) {
+	symbol_c *param_value, *param_name;
+	function_call_param_iterator_c fcp_iterator(fcall);
+	bool function_invocation_error = false;
+	const char *POU_str = NULL;
+
+	if (generic_function_call_t::POU_FB       == fcall_data.POU_type)  POU_str = "FB";
+	if (generic_function_call_t::POU_function == fcall_data.POU_type)  POU_str = "function";
+	if (NULL == POU_str) ERROR;
+
+	if ((NULL != fcall_data.formal_operand_list) && (NULL != fcall_data.nonformal_operand_list)) 
+		ERROR;
+
+	symbol_c *f_decl = fcall_data.called_function_declaration;
+	if ((NULL == f_decl) && (generic_function_call_t::POU_FB ==fcall_data.POU_type)) {
+		/* Due to the way the syntax analysis is buit (i.e. stage 2), this should never occur. */
+		/* I.e., a FB invocation using an undefined FB variable is not possible in the current implementation of stage 2. */
+		ERROR;
+	}
+	if (NULL == f_decl) {
+		/* we now try to find any function declaration with the same name, just so we can provide some relevant error messages */
+		function_symtable_t::iterator lower = function_symtable.lower_bound(fcall_data.function_name);
+		if (lower == function_symtable.end()) ERROR;
+		f_decl = function_symtable.get_value(lower);
+	}
+
+	if (NULL != fcall_data.formal_operand_list) {
+		fcall_data.formal_operand_list->accept(*this);
+		if (NULL != f_decl) {
+			function_param_iterator_c fp_iterator(f_decl);
+			while ((param_name = fcp_iterator.next_f()) != NULL) {
+				param_value = fcp_iterator.get_current_value();
+
+				/* Check if there are duplicate parameter values */
+				if(fcp_iterator.search_f(param_name) != param_value) {
+					function_invocation_error = true;
+					STAGE3_ERROR(0, param_name, param_name, "Duplicate parameter '%s' when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value);
+					continue; /* jump to next parameter */
+				}
+
+				/* Find the corresponding parameter in function declaration */
+				if (NULL == fp_iterator.search(param_name)) {
+					function_invocation_error = true;
+					STAGE3_ERROR(0, param_name, param_name, "Invalid parameter '%s' when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value);
+					continue; /* jump to next parameter */
+				} 
+
+				/* check whether direction (IN, OUT, IN_OUT) and assignment types (:= , =>) are compatible !!! */
+				/* 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();
+				/* Get the parameter direction: IN, OUT, IN_OUT */
+				function_param_iterator_c::param_direction_t param_dir = fp_iterator.param_direction();
+				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)) {
+						function_invocation_error = true;
+						STAGE3_ERROR(0, param_name, param_name, "Invalid assignment syntax ':=' used for parameter '%s', when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value);
+						continue; /* jump to next parameter */
+					}
+				} else if   (function_call_param_iterator_c::assign_out == call_param_dir) {
+					if ((function_param_iterator_c::direction_out   != param_dir)) {
+						function_invocation_error = true;
+						STAGE3_ERROR(0, param_name, param_name, "Invalid assignment syntax '=>' used for parameter '%s', when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value);
+						continue; /* jump to next parameter */
+					}
+				} else ERROR;
+
+				if (NULL == param_value->datatype) {
+					function_invocation_error = true;
+					STAGE3_ERROR(0, param_value, param_value, "Data type incompatibility between parameter '%s' and value being passed, when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value);
+					continue; /* jump to next parameter */
+				}
+			}
+		}
+	}
+	if (NULL != fcall_data.nonformal_operand_list) {
+		fcall_data.nonformal_operand_list->accept(*this);
+		if (f_decl)
+			for (int i = 1; (param_value = fcp_iterator.next_nf()) != NULL; i++) {
+		  		/* TODO: verify if it is lvalue when INOUT or OUTPUT parameters! */
+
+				/* This handle_function_invocation() will be called to handle IL function calls, where the first parameter comes from the previous IL instruction.
+				 * In this case, the previous IL instruction will be artifically (and temporarily) added to the begining ot the parameter list
+				 * so we (in this function) can handle this situation like all the other function calls.
+				 * However, 
+				 *     a) if NO previous IL function exists, then we get a fake previous IL function, with no location data (i.e. not found anywhere in the source code.
+				 *     b) the function call may actually have several prev IL instructions (if several JMP instructions jump directly to the il function call).
+				 * In order to handle these situations gracefully, we first check whether the first parameter is really an IL istruction!
+				 */
+				il_instruction_c *il_instruction_symbol = dynamic_cast<il_instruction_c *>(param_value);
+				if ((NULL != il_instruction_symbol) && (i == 1)) {
+					/* We are in a situation where an IL function call is passed the first parameter, which is actually the previous IL instruction */
+					/* However, this is really a fake previous il instruction (see visit(il_instruction_c *) )
+					 * We will iterate through all the real previous IL instructions, and analyse each of them one by one */
+					if (il_instruction_symbol->prev_il_instruction.size() == 0) {
+						function_invocation_error = true;
+						STAGE3_ERROR(0, fcall, fcall, "No available data to pass to first parameter of IL function %s. Missing a previous LD instruction?", ((identifier_c *)fcall_data.function_name)->value);
+					}
+#if 0
+					/* NOTE: We currently comment out this code...
+					 * This does not currently work, since the narrow operation is currently done on the intersection 
+					 * of all the previous IL instructions, so we currently either accept them all, or none at all.
+					 * In order to be able to produce these user freindly error messages, we will need to update the 
+					 * narrow algorithm. We leave this untill somebody aks for it...
+					 * So, for now, we simply comment out this code.
+					 */
+					for (unsigned int p = 0; p < il_instruction_symbol->prev_il_instruction.size(); p++) {
+						symbol_c *value = il_instruction_symbol->prev_il_instruction[p];  
+						if (!is_type_valid(value->datatype)) {
+							function_invocation_error = true;
+							STAGE3_ERROR(0, fcall, fcall, "Data type incompatibility for value passed to first parameter when invoking function '%s'", ((identifier_c *)fcall_data.function_name)->value);
+							STAGE3_ERROR(0, value, value, "This is the IL instruction producing the incompatible data type to first parameter of function '%s'", ((identifier_c *)fcall_data.function_name)->value);
+						}
+					}
+#else
+					if (!is_type_valid(il_instruction_symbol->datatype)) {
+						function_invocation_error = true;
+						STAGE3_ERROR(0, fcall, fcall, "Data type incompatibility between value in IL 'accumulator' and first parameter of function '%s'", ((identifier_c *)fcall_data.function_name)->value);
+					}
+#endif
+					if (function_invocation_error)
+						/* when handling a IL function call, and an error is found in the first parameter, then we bug out and do not print out any more error messages. */
+						return;
+				}
+				else if (!is_type_valid(param_value->datatype)) {
+					function_invocation_error = true;
+					STAGE3_ERROR(0, param_value, param_value, "Data type incompatibility for value passed in position %d when invoking %s '%s'", i, POU_str, ((identifier_c *)fcall_data.function_name)->value);
+				}
+			}
+	}
+
+	if (NULL == fcall_data.called_function_declaration) {
+		function_invocation_error = true;
+		STAGE3_ERROR(0, fcall, fcall, "Unable to resolve which overloaded %s '%s' is being invoked.", POU_str, ((identifier_c *)fcall_data.function_name)->value);
+	}
+
+	if (function_invocation_error) {
+		/* No compatible function exists */
+		STAGE3_ERROR(2, fcall, fcall, "Invalid parameters when invoking %s '%s'", POU_str, ((identifier_c *)fcall_data.function_name)->value);
+	} 
+
+	return;
+}
+
+
+
+void *print_datatypes_error_c::handle_implicit_il_fb_invocation(const char *param_name, symbol_c *il_operator, symbol_c *called_fb_declaration) {
+	if (NULL == il_operand) {
+		STAGE3_ERROR(0, il_operator, il_operator, "Missing operand for FB call operator '%s'.", param_name);
+		return NULL;
+	}
+	il_operand->accept(*this);
+	
+	if (NULL == called_fb_declaration) {
+		STAGE3_ERROR(0, il_operator, il_operand, "Invalid FB call: operand is not a FB instance.");
+		return NULL;
+	}
+
+	if (fake_prev_il_instruction->prev_il_instruction.empty()) {
+		STAGE3_ERROR(0, il_operator, il_operand, "FB invocation operator '%s' must be preceded by a 'LD' (or equivalent) operator.", param_name);	
+		return NULL;
+	}
+
+	/* Find the corresponding parameter in function declaration */
+	function_param_iterator_c fp_iterator(called_fb_declaration);
+	if (NULL == fp_iterator.search(param_name)) {
+		/* TODO: must also check whther it is an IN parameter!! */
+		/* NOTE: although all standard FBs have the implicit FB calls defined as input parameters
+		*        (i.e., for all standard FBs, CLK, PT, IN, CU, CD, S1, R1, etc... is always an input parameter)
+		*        if a non-standard (i.e. a FB not defined in the standard library) FB is being called, then
+		*        this (CLK, PT, IN, CU, ...) parameter may just have been defined as OUT or INOUT,
+		*        which will not work for an implicit FB call!
+		*/
+		STAGE3_ERROR(0, il_operator, il_operand, "FB called by '%s' operator does not have a parameter named '%s'", param_name, param_name);	
+		return NULL;
+	}
+	if (!are_all_datatypes_of_prev_il_instructions_datatypes_equal(fake_prev_il_instruction)) {
+		STAGE3_ERROR(0, il_operator, il_operand, "Data type incompatibility between parameter '%s' and value being passed.", param_name);
+		return NULL;
+	}
+	
+
+	/* NOTE: The error_level currently being used for errors in variables/constants etc... is rather high.
+	 *       However, in the case of an implicit FB call, if the datatype of the operand == NULL, this may be
+	 *       the __only__ indication of an error! So we test it here again, to make sure thtis error will really
+	 *       be printed out!
+	 */
+	if (NULL == il_operand->datatype) {
+		/* Note: the case of (NULL == fb_declaration) was already caught above! */
+// 		if (NULL != fb_declaration) {
+			STAGE3_ERROR(0, il_operator, il_operator, "Invalid FB call: Datatype incompatibility between the FB's '%s' parameter and value being passed, or paramater '%s' is not a 'VAR_INPUT' parameter.", param_name, param_name);
+			return NULL;
+// 		}
+	}
+
+	return NULL;
+}
+
+
+/*********************/
+/* B 1.2 - Constants */
+/*********************/
+/******************************/
+/* B 1.2.1 - Numeric Literals */
+/******************************/
+void *print_datatypes_error_c::visit(real_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for ANY_REAL data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "ANY_REAL data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(integer_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for ANY_INT data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(neg_real_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for ANY_REAL data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "ANY_REAL data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(neg_integer_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for ANY_INT data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(binary_integer_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for ANY_INT data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(octal_integer_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for ANY_INT data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(hex_integer_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for ANY_INT data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(integer_literal_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for %s data type.", elementary_type_c::to_string(symbol->type));
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(real_literal_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for %s data type.", elementary_type_c::to_string(symbol->type));
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "ANY_REAL data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(bit_string_literal_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for %s data type.", elementary_type_c::to_string(symbol->type));
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "ANY_BIT data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(boolean_literal_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Value is not valid for %s data type.", elementary_type_c::to_string(symbol->type));
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "ANY_BOOL data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(boolean_true_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Value is not valid for ANY_BOOL data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "ANY_BOOL data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(boolean_false_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Value is not valid for ANY_BOOL data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "ANY_BOOL data type not valid in this location.");
+	}
+	return NULL;
+}
+
+/*******************************/
+/* B.1.2.2   Character Strings */
+/*******************************/
+void *print_datatypes_error_c::visit(double_byte_character_string_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for WSTRING data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "WSTRING data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(single_byte_character_string_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for STRING data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "STRING data type not valid in this location.");
+	}
+	return NULL;
+}
+
+/***************************/
+/* B 1.2.3 - Time Literals */
+/***************************/
+/************************/
+/* B 1.2.3.1 - Duration */
+/************************/
+void *print_datatypes_error_c::visit(duration_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Invalid syntax for TIME data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "TIME data type not valid in this location.");
+	}
+	return NULL;
+}
+
+/************************************/
+/* B 1.2.3.2 - Time of day and Date */
+/************************************/
+void *print_datatypes_error_c::visit(time_of_day_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Invalid syntax for TOD data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "TOD data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(date_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Invalid syntax for DATE data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "DATE data type not valid in this location.");
+	}
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(date_and_time_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0) {
+		STAGE3_ERROR(0, symbol, symbol, "Invalid syntax for DT data type.");
+	} else if (NULL == symbol->datatype) {
+		STAGE3_ERROR(4, symbol, symbol, "DT data type not valid in this location.");
+	}
+	return NULL;
+}
+
+/**********************/
+/* B 1.3 - Data types */
+/**********************/
+/********************************/
+/* B 1.3.3 - Derived data types */
+/********************************/
+void *print_datatypes_error_c::visit(data_type_declaration_c *symbol) {
+	// TODO !!!
+	/* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(enumerated_value_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0)
+		STAGE3_ERROR(0, symbol, symbol, "Ambiguous enumerate value or Variable not declared in this scope.");
+	return NULL;
+}
+
+
+/*********************/
+/* B 1.4 - Variables */
+/*********************/
+void *print_datatypes_error_c::visit(symbolic_variable_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0)
+		STAGE3_ERROR(0, symbol, symbol, "Variable not declared in this scope.");
+	return NULL;
+}
+
+/********************************************/
+/* B 1.4.1 - Directly Represented Variables */
+/********************************************/
+void *print_datatypes_error_c::visit(direct_variable_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0)
+		STAGE3_ERROR(0, symbol, symbol, "Numerical value exceeds range for located variable data type.");
+	return NULL;
+}
+
+/*************************************/
+/* B 1.4.2 - Multi-element variables */
+/*************************************/
+/*  subscripted_variable '[' subscript_list ']' */
+// SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
+void *print_datatypes_error_c::visit(array_variable_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0)
+		STAGE3_ERROR(0, symbol, symbol, "Array variable not declared in this scope.");
+	
+	/* recursively call the subscript list to print any errors in the expressions used in the subscript...*/
+	symbol->subscript_list->accept(*this);
+	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 *print_datatypes_error_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 recursively determine the data types of each field_selector in fill_candidate_datatypes_c,
+ * so it does not make sense to recursively visit all the field_selectors to print out error messages. 
+ * Maybe in the future, if we find the need to print out more detailed error messages, we might do it that way. For now, we don't!
+ */
+void *print_datatypes_error_c::visit(structured_variable_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 0)
+		STAGE3_ERROR(0, symbol, symbol, "Undeclared structured/FB variable.");
+	return NULL;
+}
+
+/************************************/
+/* B 1.5 Program organization units */
+/************************************/
+/*********************/
+/* B 1.5.1 Functions */
+/*********************/
+void *print_datatypes_error_c::visit(function_declaration_c *symbol) {
+	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
+	/* We do not check for data type errors in variable declarations, Skip this for now... */
+// 	symbol->var_declarations_list->accept(*this);
+	if (debug) printf("Print error data types list in body of function %s\n", ((token_c *)(symbol->derived_function_name))->value);
+	il_parenthesis_level = 0;
+	il_error = false;
+	symbol->function_body->accept(*this);
+	delete search_varfb_instance_type;
+	search_varfb_instance_type = NULL;
+	return NULL;
+}
+
+/***************************/
+/* B 1.5.2 Function blocks */
+/***************************/
+void *print_datatypes_error_c::visit(function_block_declaration_c *symbol) {
+	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
+	/* We do not check for data type errors in variable declarations, Skip this for now... */
+// 	symbol->var_declarations->accept(*this);
+	if (debug) printf("Print error data types list in body of FB %s\n", ((token_c *)(symbol->fblock_name))->value);
+	il_parenthesis_level = 0;
+	il_error = false;
+	symbol->fblock_body->accept(*this);
+	delete search_varfb_instance_type;
+	search_varfb_instance_type = NULL;
+	return NULL;
+}
+
+/**********************/
+/* B 1.5.3 - Programs */
+/**********************/
+void *print_datatypes_error_c::visit(program_declaration_c *symbol) {
+	search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
+	/* We do not check for data type errors in variable declarations, Skip this for now... */
+// 	symbol->var_declarations->accept(*this);
+	if (debug) printf("Print error data types list in body of program %s\n", ((token_c *)(symbol->program_type_name))->value);
+	il_parenthesis_level = 0;
+	il_error = false;
+	symbol->function_block_body->accept(*this);
+	delete search_varfb_instance_type;
+	search_varfb_instance_type = NULL;
+	return NULL;
+}
+
+
+
+/********************************/
+/* B 1.7 Configuration elements */
+/********************************/
+void *print_datatypes_error_c::visit(configuration_declaration_c *symbol) {
+	// TODO !!!
+	/* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */
+	return NULL;
+}
+
+/****************************************/
+/* B.2 - Language IL (Instruction List) */
+/****************************************/
+/***********************************/
+/* B 2.1 Instructions and Operands */
+/***********************************/
+
+// void *visit(instruction_list_c *symbol);
+
+/* | label ':' [il_incomplete_instruction] eol_list */
+// SYM_REF2(il_instruction_c, label, il_instruction)
+void *print_datatypes_error_c::visit(il_instruction_c *symbol) {
+	if (NULL != symbol->il_instruction) {
+		il_instruction_c tmp_prev_il_instruction(NULL, NULL);
+#if 0
+		/* NOTE: The following is currently no longer needed. Since the following code is actually cool, 
+		 * we don't delete it, but simply comment it out. It might just come in handy later on...
+		 */
+		/* When handling a il function call, this fake_prev_il_instruction may be used as a standard function call parameter, so it is important that 
+		 * it contain some valid location info so error messages make sense.
+		 */
+		if (symbol->prev_il_instruction.size() > 0) {
+			/* since we don't want to copy all that data one variable at a time, we copy it all at once */
+			/* This has the advantage that, if we ever add some more data to the base symbol_c later on, we will not need to
+			 * change the following line to guarantee that the data is copied correctly!
+			 * However, it does have the drawback of copying more data than what we want!
+			 * In order to only copy the data in the base class symbol_c, we use the tmp_symbol pointer!
+			 * I (mario) have checked with a debugger, and it is working as intended!
+			 */
+			symbol_c *tmp_symbol1 = symbol->prev_il_instruction[0];
+			symbol_c *tmp_symbol2 = &tmp_prev_il_instruction;
+			*tmp_symbol2 = *tmp_symbol1;
+			/* we do not want to copy the datatype variable, so we reset it to NULL */
+			tmp_prev_il_instruction.datatype = NULL;
+			/* We don't need to worry about the candidate_datatype list (which we don't want to copy just yet), since that will 
+			 * be reset to the correct value when we call intersect_prev_candidate_datatype_lists() later on...
+			 */
+		}
+#endif
+		/* the print error algorithm will need access to the intersected candidate_datatype lists of all prev_il_instructions, as well as the 
+		 * list of the prev_il_instructions.
+		 * Instead of creating two 'global' (within the class) variables, we create a single il_instruction_c variable (fake_prev_il_instruction),
+		 * and shove that data into this single variable.
+		 */
+		tmp_prev_il_instruction.prev_il_instruction = symbol->prev_il_instruction;
+		intersect_prev_candidate_datatype_lists(&tmp_prev_il_instruction);
+		if (are_all_datatypes_of_prev_il_instructions_datatypes_equal(symbol))
+			if (symbol->prev_il_instruction.size() > 0)
+				tmp_prev_il_instruction.datatype = (symbol->prev_il_instruction[0])->datatype;
+		
+		/* Tell the il_instruction the datatype that it must generate - this was chosen by the next il_instruction (remember: we are iterating backwards!) */
+		fake_prev_il_instruction = &tmp_prev_il_instruction;
+		symbol->il_instruction->accept(*this);
+		fake_prev_il_instruction = NULL;
+	}
+
+	return NULL;
+}
+
+
+
+void *print_datatypes_error_c::visit(il_simple_operation_c *symbol) {
+	il_operand = symbol->il_operand;
+	if (NULL != symbol->il_operand) {
+		symbol->il_operand->accept(*this);
+	}
+	/* recursive call to see whether data types are compatible */
+	symbol->il_simple_operator->accept(*this);
+	il_operand = NULL;
+	return NULL;
+}
+
+/* | 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 *print_datatypes_error_c::visit(il_function_call_c *symbol) {
+	/* The first parameter of a non formal function call in IL will be the 'current value' (i.e. the prev_il_instruction)
+	 * In order to be able to handle this without coding special cases, we will simply prepend that symbol
+	 * to the il_operand_list, and remove it after calling handle_function_call().
+	 *
+	 * However, if no further paramters are given, then il_operand_list will be NULL, and we will
+	 * need to create a new object to hold the pointer to prev_il_instruction.
+	 * This change will also be undone later in print_datatypes_error_c.
+	 */
+	if (NULL == symbol->il_operand_list)  symbol->il_operand_list = new il_operand_list_c;
+	if (NULL == symbol->il_operand_list)  ERROR;
+
+	((list_c *)symbol->il_operand_list)->insert_element(fake_prev_il_instruction, 0);
+
+	generic_function_call_t fcall_param = {
+		/* fcall_param.function_name               = */ symbol->function_name,
+		/* fcall_param.nonformal_operand_list      = */ symbol->il_operand_list,
+		/* fcall_param.formal_operand_list         = */ NULL,
+		/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_function,
+		/* fcall_param.candidate_functions         = */ symbol->candidate_functions,
+		/* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
+		/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
+	};
+
+/* TODO: check what error message (if any) the compiler will give out if this function invocation
+ * is not preceded by a LD operator (or another equivalent operator or list of operators).
+ */
+	handle_function_invocation(symbol, fcall_param);
+	
+	/* We now undo those changes to the abstract syntax tree made above! */
+	((list_c *)symbol->il_operand_list)->remove_element(0);
+	if (((list_c *)symbol->il_operand_list)->n == 0) {
+		/* if the list becomes empty, then that means that it did not exist before we made these changes, so we delete it! */
+		delete 	symbol->il_operand_list;
+		symbol->il_operand_list = NULL;
+	}
+
+	return NULL;
+}
+
+
+/* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */
+// SYM_REF3(il_expression_c, il_expr_operator, il_operand, simple_instr_list);
+void *print_datatypes_error_c::visit(il_expression_c *symbol) {
+  /* first give the parenthesised IL list a chance to print errors */
+  il_instruction_c *save_fake_prev_il_instruction = fake_prev_il_instruction;
+  symbol->simple_instr_list->accept(*this);
+  fake_prev_il_instruction = save_fake_prev_il_instruction;
+
+  /* Now handle the operation (il_expr_operator) that will use the result coming from the parenthesised IL list (i.e. simple_instr_list) */
+  il_operand = symbol->simple_instr_list; /* This is not a bug! The parenthesised expression will be used as the operator! */
+  symbol->il_expr_operator->accept(*this);
+
+return NULL;
+}
+
+
+/*   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 *print_datatypes_error_c::visit(il_fb_call_c *symbol) {
+	int extensible_param_count;                      /* unused vairable! Needed for compilation only! */
+	std::vector <symbol_c *> candidate_functions;    /* unused vairable! Needed for compilation only! */
+	generic_function_call_t fcall_param = {
+		/* fcall_param.function_name               = */ symbol->fb_name,
+		/* fcall_param.nonformal_operand_list      = */ symbol->il_operand_list,
+		/* fcall_param.formal_operand_list         = */ symbol->il_param_list,
+		/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_FB,
+		/* fcall_param.candidate_functions         = */ candidate_functions,             /* will not be used, but must provide a reference to be able to compile */
+		/* fcall_param.called_function_declaration = */ symbol->called_fb_declaration,
+		/* fcall_param.extensible_param_count      = */ extensible_param_count           /* will not be used, but must provide a reference to be able to compile */
+	};
+  
+	handle_function_invocation(symbol, fcall_param);
+	/* check the semantics of the CALC, CALCN operators! */
+	symbol->il_call_operator->accept(*this);
+	return NULL;
+}
+
+/* | 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 *print_datatypes_error_c::visit(il_formal_funct_call_c *symbol) {
+	generic_function_call_t fcall_param = {
+		/* fcall_param.function_name               = */ symbol->function_name,
+		/* fcall_param.nonformal_operand_list      = */ NULL,
+		/* fcall_param.formal_operand_list         = */ symbol->il_param_list,
+		/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_function,
+		/* fcall_param.candidate_functions         = */ symbol->candidate_functions,
+		/* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
+		/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
+	};
+  
+	handle_function_invocation(symbol, fcall_param);
+	return NULL;
+}
+
+
+//     void *visit(il_operand_list_c *symbol);
+//     void *visit(simple_instr_list_c *symbol);
+
+// SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;)
+void *print_datatypes_error_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! */
+    
+  il_instruction_c tmp_prev_il_instruction(NULL, NULL);
+  /* the print error algorithm will need access to the intersected candidate_datatype lists of all prev_il_instructions, as well as the 
+   * list of the prev_il_instructions.
+   * Instead of creating two 'global' (within the class) variables, we create a single il_instruction_c variable (fake_prev_il_instruction),
+   * and shove that data into this single variable.
+   */
+  if (symbol->prev_il_instruction.size() > 0)
+    tmp_prev_il_instruction.candidate_datatypes = symbol->prev_il_instruction[0]->candidate_datatypes;
+  tmp_prev_il_instruction.prev_il_instruction = symbol->prev_il_instruction;
+  
+   /* copy the candidate_datatypes list */
+  fake_prev_il_instruction = &tmp_prev_il_instruction;
+  symbol->il_simple_instruction->accept(*this);
+  fake_prev_il_instruction = NULL;
+  return NULL;
+  
+  
+//   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;
+//   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 *print_datatypes_error_c::print_binary_operator_errors(const char *il_operator, symbol_c *symbol, bool deprecated_operation) {
+	if ((symbol->candidate_datatypes.size() == 0) && (il_operand->candidate_datatypes.size() > 0)) {
+		STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for '%s' operator.", il_operator);
+	} else if (NULL == symbol->datatype) {
+		STAGE3_WARNING(symbol, symbol, "Result of '%s' operation is never used.", il_operator);
+	} else if (deprecated_operation)
+		STAGE3_WARNING(symbol, symbol, "Deprecated operation for '%s' operator.", il_operator);
+	return NULL;
+}
+
+
+void *print_datatypes_error_c::visit(LD_operator_c *symbol) {
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(LDN_operator_c *symbol) {
+	if ((symbol->candidate_datatypes.size() == 0) 		&&
+		(il_operand->candidate_datatypes.size() > 0))
+		STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'LDN' operator.");
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(ST_operator_c *symbol) {
+	/* MANU:
+	 * if prev_instruction is NULL we can print a message error or warning error like:
+	 * we can't use a ST like first instruction.
+	 * What do you think?
+	 */
+	if ((symbol->candidate_datatypes.size() == 0) 		&&
+		(il_operand->candidate_datatypes.size() > 0))
+		STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'ST' operator.");
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(STN_operator_c *symbol) {
+	/* MANU:
+	 * if prev_instruction is NULL we can print a message error or warning error like:
+	 * we can't use a ST like first instruction.
+	 * What do you think?
+	 */
+	if ((symbol->candidate_datatypes.size() == 0) 		&&
+		(il_operand->candidate_datatypes.size() > 0))
+		STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'STN' operator.");
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(NOT_operator_c *symbol) {
+	/* 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!
+	 */
+	if (il_operand != NULL)
+		STAGE3_ERROR(0, symbol, symbol, "'NOT' operator may not have an operand.");
+	if (symbol->candidate_datatypes.size() == 0)
+		STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'NOT' operator.");
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(S_operator_c *symbol) {
+  /* TODO: what if this is a FB call ?? */
+	if ((symbol->candidate_datatypes.size() == 0) 		&&
+		(il_operand->candidate_datatypes.size() > 0))
+		STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'S' operator.");
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(R_operator_c *symbol) {
+  /* TODO: what if this is a FB call ?? */
+	if ((symbol->candidate_datatypes.size() == 0) 		&&
+		(il_operand->candidate_datatypes.size() > 0))
+		STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for 'R' operator.");
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit( S1_operator_c *symbol) {return handle_implicit_il_fb_invocation( "S1", symbol, symbol->called_fb_declaration);}
+void *print_datatypes_error_c::visit( R1_operator_c *symbol) {return handle_implicit_il_fb_invocation( "R1", symbol, symbol->called_fb_declaration);}
+void *print_datatypes_error_c::visit(CLK_operator_c *symbol) {return handle_implicit_il_fb_invocation("CLK", symbol, symbol->called_fb_declaration);}
+void *print_datatypes_error_c::visit( CU_operator_c *symbol) {return handle_implicit_il_fb_invocation( "CU", symbol, symbol->called_fb_declaration);}
+void *print_datatypes_error_c::visit( CD_operator_c *symbol) {return handle_implicit_il_fb_invocation( "CD", symbol, symbol->called_fb_declaration);}
+void *print_datatypes_error_c::visit( PV_operator_c *symbol) {return handle_implicit_il_fb_invocation( "PV", symbol, symbol->called_fb_declaration);}
+void *print_datatypes_error_c::visit( IN_operator_c *symbol) {return handle_implicit_il_fb_invocation( "IN", symbol, symbol->called_fb_declaration);}
+void *print_datatypes_error_c::visit( PT_operator_c *symbol) {return handle_implicit_il_fb_invocation( "PT", symbol, symbol->called_fb_declaration);}
+
+void *print_datatypes_error_c::visit( AND_operator_c *symbol) {return print_binary_operator_errors("AND" , symbol);}
+void *print_datatypes_error_c::visit(  OR_operator_c *symbol) {return print_binary_operator_errors( "OR" , symbol);}
+void *print_datatypes_error_c::visit( XOR_operator_c *symbol) {return print_binary_operator_errors("XOR" , symbol);}
+void *print_datatypes_error_c::visit(ANDN_operator_c *symbol) {return print_binary_operator_errors("ANDN", symbol);}
+void *print_datatypes_error_c::visit( ORN_operator_c *symbol) {return print_binary_operator_errors( "ORN", symbol);}
+void *print_datatypes_error_c::visit(XORN_operator_c *symbol) {return print_binary_operator_errors("XORN", symbol);}
+void *print_datatypes_error_c::visit( ADD_operator_c *symbol) {return print_binary_operator_errors("ADD" , symbol, symbol->deprecated_operation);}
+void *print_datatypes_error_c::visit( SUB_operator_c *symbol) {return print_binary_operator_errors("SUB" , symbol, symbol->deprecated_operation);}
+void *print_datatypes_error_c::visit( MUL_operator_c *symbol) {return print_binary_operator_errors("MUL" , symbol, symbol->deprecated_operation);}
+void *print_datatypes_error_c::visit( DIV_operator_c *symbol) {return print_binary_operator_errors("DIV" , symbol, symbol->deprecated_operation);}
+void *print_datatypes_error_c::visit( MOD_operator_c *symbol) {return print_binary_operator_errors("MOD" , symbol);}
+
+void *print_datatypes_error_c::visit(  GT_operator_c *symbol) {return print_binary_operator_errors( "GT" , symbol);}
+void *print_datatypes_error_c::visit(  GE_operator_c *symbol) {return print_binary_operator_errors( "GE" , symbol);}
+void *print_datatypes_error_c::visit(  EQ_operator_c *symbol) {return print_binary_operator_errors( "EQ" , symbol);}
+void *print_datatypes_error_c::visit(  LT_operator_c *symbol) {return print_binary_operator_errors( "LT" , symbol);}
+void *print_datatypes_error_c::visit(  LE_operator_c *symbol) {return print_binary_operator_errors( "LE" , symbol);}
+void *print_datatypes_error_c::visit(  NE_operator_c *symbol) {return print_binary_operator_errors( "NE" , symbol);}
+
+  
+
+
+void *print_datatypes_error_c::handle_conditional_flow_control_IL_instruction(symbol_c *symbol, const char *oper) {
+	if (NULL == symbol->datatype)
+		STAGE3_ERROR(0, symbol, symbol, "%s operator must be preceded by an IL instruction producing a BOOL value.", oper);
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(  CAL_operator_c *symbol) {return NULL;}
+void *print_datatypes_error_c::visit( CALC_operator_c *symbol) {return handle_conditional_flow_control_IL_instruction(symbol, "CALC" );}
+void *print_datatypes_error_c::visit(CALCN_operator_c *symbol) {return handle_conditional_flow_control_IL_instruction(symbol, "CALCN");}
+void *print_datatypes_error_c::visit(  RET_operator_c *symbol) {return NULL;}
+void *print_datatypes_error_c::visit( RETC_operator_c *symbol) {return handle_conditional_flow_control_IL_instruction(symbol, "RETC" );}
+void *print_datatypes_error_c::visit(RETCN_operator_c *symbol) {return handle_conditional_flow_control_IL_instruction(symbol, "RETCN");}
+void *print_datatypes_error_c::visit(  JMP_operator_c *symbol) {return NULL;}
+void *print_datatypes_error_c::visit( JMPC_operator_c *symbol) {return handle_conditional_flow_control_IL_instruction(symbol, "JMPC" );}
+void *print_datatypes_error_c::visit(JMPCN_operator_c *symbol) {return handle_conditional_flow_control_IL_instruction(symbol, "JMPCN");}
+
+
+
+/* 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 *print_datatypes_error_c::print_binary_expression_errors(const char *operation, symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr, bool deprecated_operation) {
+	l_expr->accept(*this);
+	r_expr->accept(*this);
+	if ((symbol->candidate_datatypes.size() == 0) 		&&
+		(l_expr->candidate_datatypes.size() > 0)	&&
+		(r_expr->candidate_datatypes.size() > 0))
+		STAGE3_ERROR(0, symbol, symbol, "Data type mismatch for '%s' expression.", operation);
+        if (deprecated_operation)
+                STAGE3_WARNING(symbol, symbol, "Deprecated operation for '%s' expression.", operation);
+	return NULL;
+}
+
+
+void *print_datatypes_error_c::visit(    or_expression_c *symbol) {return print_binary_expression_errors( "OR", symbol, symbol->l_exp, symbol->r_exp);}
+void *print_datatypes_error_c::visit(   xor_expression_c *symbol) {return print_binary_expression_errors("XOR", symbol, symbol->l_exp, symbol->r_exp);}
+void *print_datatypes_error_c::visit(   and_expression_c *symbol) {return print_binary_expression_errors("AND", symbol, symbol->l_exp, symbol->r_exp);}
+void *print_datatypes_error_c::visit(   equ_expression_c *symbol) {return print_binary_expression_errors( "=" , symbol, symbol->l_exp, symbol->r_exp);}
+void *print_datatypes_error_c::visit(notequ_expression_c *symbol) {return print_binary_expression_errors( "<>", symbol, symbol->l_exp, symbol->r_exp);}
+void *print_datatypes_error_c::visit(    lt_expression_c *symbol) {return print_binary_expression_errors( "<" , symbol, symbol->l_exp, symbol->r_exp);}
+void *print_datatypes_error_c::visit(    gt_expression_c *symbol) {return print_binary_expression_errors( ">" , symbol, symbol->l_exp, symbol->r_exp);}
+void *print_datatypes_error_c::visit(    le_expression_c *symbol) {return print_binary_expression_errors( "<=", symbol, symbol->l_exp, symbol->r_exp);}
+void *print_datatypes_error_c::visit(    ge_expression_c *symbol) {return print_binary_expression_errors( ">=", symbol, symbol->l_exp, symbol->r_exp);}
+void *print_datatypes_error_c::visit(   add_expression_c *symbol) {return print_binary_expression_errors( "+" , symbol, symbol->l_exp, symbol->r_exp, symbol->deprecated_operation);}
+void *print_datatypes_error_c::visit(   sub_expression_c *symbol) {return print_binary_expression_errors( "-" , symbol, symbol->l_exp, symbol->r_exp, symbol->deprecated_operation);}
+void *print_datatypes_error_c::visit(   mul_expression_c *symbol) {return print_binary_expression_errors( "*" , symbol, symbol->l_exp, symbol->r_exp, symbol->deprecated_operation);}
+void *print_datatypes_error_c::visit(   div_expression_c *symbol) {return print_binary_expression_errors( "/" , symbol, symbol->l_exp, symbol->r_exp, symbol->deprecated_operation);}
+void *print_datatypes_error_c::visit(   mod_expression_c *symbol) {return print_binary_expression_errors("MOD", symbol, symbol->l_exp, symbol->r_exp);}
+void *print_datatypes_error_c::visit( power_expression_c *symbol) {return print_binary_expression_errors( "**", symbol, symbol->l_exp, symbol->r_exp);}
+
+
+void *print_datatypes_error_c::visit(neg_expression_c *symbol) {
+	symbol->exp->accept(*this);
+	if ((symbol->candidate_datatypes.size() == 0)      &&
+		(symbol->exp->candidate_datatypes.size() > 0))
+		STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'NEG' expression.");
+	return NULL;
+}
+
+
+void *print_datatypes_error_c::visit(not_expression_c *symbol) {
+	symbol->exp->accept(*this);
+	if ((symbol->candidate_datatypes.size() == 0)      &&
+		(symbol->exp->candidate_datatypes.size() > 0))
+		STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'NOT' expression.");
+	return NULL;
+}
+
+/* NOTE: The parameter 'called_function_declaration', 'extensible_param_count' and 'candidate_functions' are used to pass data between the stage 3 and stage 4. */
+/*    formal_param_list -> may be NULL ! */
+/* nonformal_param_list -> may be NULL ! */
+// 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;)
+void *print_datatypes_error_c::visit(function_invocation_c *symbol) {
+	generic_function_call_t fcall_param = {
+		/* fcall_param.function_name               = */ symbol->function_name,
+		/* fcall_param.nonformal_operand_list      = */ symbol->nonformal_param_list,
+		/* fcall_param.formal_operand_list         = */ symbol->formal_param_list,
+		/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_function,
+		/* fcall_param.candidate_functions         = */ symbol->candidate_functions,
+		/* fcall_param.called_function_declaration = */ symbol->called_function_declaration,
+		/* fcall_param.extensible_param_count      = */ symbol->extensible_param_count
+	};
+
+	handle_function_invocation(symbol, fcall_param);
+	return NULL;
+}
+
+
+
+/********************/
+/* B 3.2 Statements */
+/********************/
+
+/*********************************/
+/* B 3.2.1 Assignment Statements */
+/*********************************/
+void *print_datatypes_error_c::visit(assignment_statement_c *symbol) {
+	symbol->l_exp->accept(*this);
+	symbol->r_exp->accept(*this);
+	if ((NULL == symbol->l_exp->datatype) &&
+	    (NULL == symbol->r_exp->datatype) &&
+		(symbol->l_exp->candidate_datatypes.size() > 0)	&&
+		(symbol->r_exp->candidate_datatypes.size() > 0))
+		STAGE3_ERROR(0, symbol, symbol, "Incompatible data types for ':=' operation.");
+	return NULL;
+}
+
+
+/*****************************************/
+/* B 3.2.2 Subprogram Control Statements */
+/*****************************************/
+/* fb_name '(' [param_assignment_list] ')' */
+/*    formal_param_list -> may be NULL ! */
+/* nonformal_param_list -> may be NULL ! */
+/* 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;)
+void *print_datatypes_error_c::visit(fb_invocation_c *symbol) {
+	int extensible_param_count;                      /* unused vairable! Needed for compilation only! */
+	std::vector <symbol_c *> candidate_functions;    /* unused vairable! Needed for compilation only! */
+	generic_function_call_t fcall_param = {
+		/* fcall_param.function_name               = */ symbol->fb_name,
+		/* fcall_param.nonformal_operand_list      = */ symbol->nonformal_param_list,
+		/* fcall_param.formal_operand_list         = */ symbol->formal_param_list,
+		/* enum {POU_FB, POU_function} POU_type    = */ generic_function_call_t::POU_FB,
+		/* fcall_param.candidate_functions         = */ candidate_functions,             /* will not be used, but must provide a reference to be able to compile */
+		/* fcall_param.called_function_declaration = */ symbol->called_fb_declaration,
+		/* fcall_param.extensible_param_count      = */ extensible_param_count           /* will not be used, but must provide a reference to be able to compile */
+	};
+	
+	handle_function_invocation(symbol, fcall_param);
+	return NULL;
+}
+
+
+/********************************/
+/* B 3.2.3 Selection Statements */
+/********************************/
+
+void *print_datatypes_error_c::visit(if_statement_c *symbol) {
+	symbol->expression->accept(*this);
+	if ((NULL == symbol->expression->datatype) &&
+		(symbol->expression->candidate_datatypes.size() > 0)) {
+		STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'IF' condition.");
+	}
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	if (NULL != symbol->elseif_statement_list)
+		symbol->elseif_statement_list->accept(*this);
+	if (NULL != symbol->else_statement_list)
+		symbol->else_statement_list->accept(*this);
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(elseif_statement_c *symbol) {
+	symbol->expression->accept(*this);
+	if ((NULL == symbol->expression->datatype) &&
+		(symbol->expression->candidate_datatypes.size() > 0)) {
+		STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'ELSIF' condition.");
+	}
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	return NULL;
+}
+
+
+void *print_datatypes_error_c::visit(case_statement_c *symbol) {
+	symbol->expression->accept(*this);
+	if ((NULL == symbol->expression->datatype) &&
+		(symbol->expression->candidate_datatypes.size() > 0)) {
+		STAGE3_ERROR(0, symbol, symbol, "'CASE' quantity not an integer or enumerated.");
+	}
+	symbol->case_element_list->accept(*this);
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	return NULL;
+}
+
+/********************************/
+/* B 3.2.4 Iteration Statements */
+/********************************/
+
+void *print_datatypes_error_c::visit(for_statement_c *symbol) {
+	symbol->control_variable->accept(*this);
+	symbol->beg_expression->accept(*this);
+	symbol->end_expression->accept(*this);
+	/* Control variable */
+	if ((NULL == symbol->control_variable->datatype) &&
+		(symbol->control_variable->candidate_datatypes.size() > 0)) {
+		STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'FOR' control variable.");
+	}
+	/* BEG expression */
+	if ((NULL == symbol->beg_expression->datatype) &&
+		(symbol->beg_expression->candidate_datatypes.size() > 0)) {
+		STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'FOR' begin expression.");
+	}
+	/* END expression */
+	if ((NULL == symbol->end_expression->datatype) &&
+		(symbol->end_expression->candidate_datatypes.size() > 0)) {
+		STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'FOR' end expression.");
+	}
+	/* BY expression */
+	if ((NULL != symbol->by_expression) &&
+		(NULL == symbol->by_expression->datatype) &&
+		(symbol->end_expression->candidate_datatypes.size() > 0)) {
+		STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'FOR' by expression.");
+	}
+	/* DO statement */
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(while_statement_c *symbol) {
+	symbol->expression->accept(*this);
+	if (symbol->candidate_datatypes.size() != 1) {
+		STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'WHILE' condition.");
+		return NULL;
+	}
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	return NULL;
+}
+
+void *print_datatypes_error_c::visit(repeat_statement_c *symbol) {
+	if (symbol->candidate_datatypes.size() != 1) {
+		STAGE3_ERROR(0, symbol, symbol, "Invalid data type for 'REPEAT' condition.");
+		return NULL;
+	}
+	if (NULL != symbol->statement_list)
+		symbol->statement_list->accept(*this);
+	symbol->expression->accept(*this);
+	return NULL;
+}
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/print_datatypes_error.hh	Sat Mar 31 15:36:08 2012 +0100
@@ -0,0 +1,323 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2009-2011  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2011-2012  Manuele Conti (manuele.conti@sirius-es.it)
+ *  Copyright (C) 2011-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)
+ *
+ */
+
+
+#include "../absyntax_utils/absyntax_utils.hh"
+#include "datatype_functions.hh"
+
+
+class print_datatypes_error_c: public iterator_visitor_c {
+
+  private:
+    /* The level of detail that the user wants us to display error messages. */
+//     #define error_level_default (1)
+    #define error_level_default (1)
+    #define error_level_nagging (4)
+    unsigned int current_display_error_level;
+    
+    search_varfb_instance_type_c *search_varfb_instance_type;
+    search_base_type_c search_base_type;
+    /* When calling a function block, we must first find it's type,
+     * by searching through the declarations of the variables currently
+     * in scope.
+     * This class does just that...
+     * A new object instance is instantiated whenever we start checking semantics
+     * for a function block type declaration, or a program declaration.
+     * This object instance will then later be called while the
+     * function block's or the program's body is being handled.
+     *
+     * Note that functions cannot contain calls to function blocks,
+     * so we do not create an object instance when handling
+     * a function declaration.
+     */
+
+    /* In IL code, once we find a type mismatch error, it is best to
+     * ignore any further errors until the end of the logical operation,
+     * i.e. until the next LD.
+     * However, we cannot clear the il_error flag on all LD operations,
+     * as these may also be used within parenthesis. LD operations
+     * within parenthesis may not clear the error flag.
+     * We therefore need a counter to know how deep inside a parenthesis
+     * structure we are.
+     */
+    int  il_parenthesis_level;
+    bool il_error;
+    bool error_found;
+    bool warning_found;
+
+    /* the current data type of the data stored in the IL stack, i.e. the default variable */
+    il_instruction_c *fake_prev_il_instruction;
+    /* the narrow algorithm will need access to the intersected candidate_datatype lists of all prev_il_instructions, as well as the 
+     * list of the prev_il_instructions.
+     * Instead of creating two 'global' (within the class) variables, we create a single il_instruction_c variable (fake_prev_il_instruction),
+     * and shove that data into this single variable.
+     */
+    symbol_c *il_operand_type;
+    symbol_c *il_operand;
+
+    /* some helper functions... */
+    symbol_c *base_type(symbol_c *symbol);
+    void handle_function_invocation(symbol_c *fcall, generic_function_call_t fcall_data);
+    void *handle_implicit_il_fb_invocation(const char *param_name, symbol_c *il_operator, symbol_c *called_fb_declaration);  
+    void *handle_conditional_flow_control_IL_instruction(symbol_c *symbol, const char *oper);
+
+    void *print_binary_operator_errors  (const char *il_operator, symbol_c *symbol,                                     bool deprecated_operation = false);
+    void *print_binary_expression_errors(const char *operation  , symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr, bool deprecated_operation = false);
+
+    
+  public:
+    print_datatypes_error_c(symbol_c *ignore);
+    virtual ~print_datatypes_error_c(void);
+    int get_error_found();
+
+
+    /*********************/
+    /* 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.1.2.2   Character Strings */
+    /*******************************/
+    void *visit(double_byte_character_string_c *symbol);
+    void *visit(single_byte_character_string_c *symbol);
+
+    /***************************/
+    /* B 1.2.3 - Time Literals */
+    /***************************/
+    /************************/
+    /* B 1.2.3.1 - Duration */
+    /************************/
+    void *visit(duration_c *symbol);
+
+    /************************************/
+    /* B 1.2.3.2 - Time of day and Date */
+    /************************************/
+    void *visit(time_of_day_c *symbol);
+    void *visit(date_c *symbol);
+    void *visit(date_and_time_c *symbol);
+
+    /**********************/
+    /* B 1.3 - Data types */
+    /**********************/
+    /********************************/
+    /* B 1.3.3 - Derived data types */
+    /********************************/
+    void *visit(data_type_declaration_c *symbol);
+    void *visit(enumerated_value_c *symbol);
+
+    /*********************/
+    /* B 1.4 - Variables */
+    /*********************/
+    void *visit(symbolic_variable_c *symbol);
+
+    /********************************************/
+    /* B 1.4.1 - Directly Represented Variables */
+    /********************************************/
+    void *visit(direct_variable_c *symbol);
+
+    /*************************************/
+    /* 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 */
+    /**************************************/
+    /***********************/
+    /* 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);
+
+    /********************************/
+    /* B 1.7 Configuration elements */
+    /********************************/
+    void *visit(configuration_declaration_c *symbol);
+
+    /****************************************/
+    /* 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);
+
+    /*******************/
+    /* 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);
+
+    /*********************************/
+    /* B 3.2.1 Assignment Statements */
+    /*********************************/
+    void *visit(assignment_statement_c *symbol);
+
+    /*****************************************/
+    /* B 3.2.2 Subprogram Control Statements */
+    /*****************************************/
+    void *visit(fb_invocation_c *symbol);
+
+    /********************************/
+    /* B 3.2.3 Selection Statements */
+    /********************************/
+    void *visit(if_statement_c *symbol);
+    //     void *visit(elseif_statement_list_c *symbol);
+    void *visit(elseif_statement_c *symbol);
+    void *visit(case_statement_c *symbol);
+    //     void *visit(case_element_list_c *symbol);
+    //     void *visit(case_element_c *symbol);
+    // void *visit(case_list_c *symbol);
+
+    /********************************/
+    /* B 3.2.4 Iteration Statements */
+    /********************************/
+    void *visit(for_statement_c *symbol);
+    void *visit(while_statement_c *symbol);
+    void *visit(repeat_statement_c *symbol);
+
+}; // print_datatypes_error_c
+
+
+
+
+
+
+
--- a/stage3/stage3.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/stage3/stage3.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -1,8 +1,10 @@
 /*
  *  matiec - a compiler for the programming languages defined in IEC 61131-3
  *
- *  Copyright (C) 2009-2011  Mario de Sousa (msousa@fe.up.pt)
+ *  Copyright (C) 2009-2012  Mario de Sousa (msousa@fe.up.pt)
  *  Copyright (C) 2007-2011  Laurent Bessard and Edouard Tisserant
+ *  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
@@ -32,17 +34,36 @@
 
 #include "stage3.hh"
 
-int type_safety(symbol_c *tree_root){
-	visit_expression_type_c visit_expression_type(tree_root);
+#include "flow_control_analysis.hh"
+#include "fill_candidate_datatypes.hh"
+#include "narrow_candidate_datatypes.hh"
+#include "print_datatypes_error.hh"
 
-	(*tree_root).accept(visit_expression_type);
 
-	if (visit_expression_type.get_error_found())
-	  return -1;
-	
+static int flow_control_analysis(symbol_c *tree_root){
+  flow_control_analysis_c flow_control_analysis(tree_root);
+  tree_root->accept(flow_control_analysis);
+  return 0;
+}
+
+/* Type safety analysis assumes that flow control analysis has already been completed,
+ * so be sure to call flow_control_analysis() before calling this function
+ */
+static int type_safety(symbol_c *tree_root){
+	fill_candidate_datatypes_c fill_candidate_datatypes(tree_root);
+	tree_root->accept(fill_candidate_datatypes);
+	narrow_candidate_datatypes_c narrow_candidate_datatypes(tree_root);
+	tree_root->accept(narrow_candidate_datatypes);
+	print_datatypes_error_c print_datatypes_error(tree_root);
+	tree_root->accept(print_datatypes_error);
+	if (print_datatypes_error.get_error_found())
+		return -1;
 	return 0;
 }
 
+
+
 int stage3(symbol_c *tree_root){
+	flow_control_analysis(tree_root);
 	return type_safety(tree_root);
 }
--- a/stage3/stage3.hh	Tue Feb 21 22:31:38 2012 +0100
+++ b/stage3/stage3.hh	Sat Mar 31 15:36:08 2012 +0100
@@ -31,20 +31,8 @@
  */
 
 
-// #include <stdio.h>  /* required for NULL */
-#include <string>
-#include <iostream>
-#include <sstream>
-#include <typeinfo>
-#include <list>
-#include <strings.h>
-
 #include "../util/symtable.hh"
-#include "../util/dsymtable.hh"
-#include "../absyntax/visitor.hh"
-
-#include "visit_expression_type.hh"
 
 
 int stage3(symbol_c *tree_root);
-int type_safety(symbol_c *tree_root);
+
--- a/stage3/visit_expression_type.cc	Tue Feb 21 22:31:38 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2376 +0,0 @@
-/*
- *  matiec - a compiler for the programming languages defined in IEC 61131-3
- *
- *  Copyright (C) 2009-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)
- *
- */
-
-
-/* Verify whether the semantic rules of data type compatibility are being followed.
- *
- * For example:
- */
-
-#include "visit_expression_type.hh"
-#include <typeinfo>
-#include <list>
-#include <string>
-#include <string.h>
-#include <strings.h>
-
-
-#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(symbol1, symbol2, ...) {                                          \
-    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");                                                             \
-    il_error = true;                                                                   \
-    error_found = true;                                                                \
-  }
-
-
-/* set to 1 to see debug info during execution */
-static int debug = 0;
-
-
-void *visit_expression_type_c::visit(program_declaration_c *symbol) {
-  search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
-  symbol->var_declarations->accept(*this);
-  if (debug) printf("checking semantics in body of program %s\n", ((token_c *)(symbol->program_type_name))->value);
-  il_parenthesis_level = 0;
-  il_error = false;
-  il_default_variable_type = NULL;
-  symbol->function_block_body->accept(*this);
-  il_default_variable_type = NULL;
-  delete search_varfb_instance_type;
-  search_varfb_instance_type = NULL;
-  return NULL;
-}
-
-void *visit_expression_type_c::visit(function_declaration_c *symbol) {
-  search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
-  symbol->var_declarations_list->accept(*this);
-  if (debug) printf("checking semantics in body of function %s\n", ((token_c *)(symbol->derived_function_name))->value);
-  il_parenthesis_level = 0;
-  il_error = false;
-  il_default_variable_type = NULL;
-  symbol->function_body->accept(*this);
-  il_default_variable_type = NULL;
-  delete search_varfb_instance_type;
-  search_varfb_instance_type = NULL;
-  return NULL;
-}
-
-void *visit_expression_type_c::visit(function_block_declaration_c *symbol) {
-  search_varfb_instance_type = new search_varfb_instance_type_c(symbol);
-  symbol->var_declarations->accept(*this);
-  if (debug) printf("checking semantics in body of FB %s\n", ((token_c *)(symbol->fblock_name))->value);
-  il_parenthesis_level = 0;
-  il_error = false;
-  il_default_variable_type = NULL;
-  symbol->fblock_body->accept(*this);
-  il_default_variable_type = NULL;
-  delete search_varfb_instance_type;
-  search_varfb_instance_type = NULL;
-  return NULL;
-}
-
-
-
-
-
-
-
-
-
-visit_expression_type_c::visit_expression_type_c(symbol_c *ignore) {
-  error_found = false;
-}
-
-visit_expression_type_c::~visit_expression_type_c(void) {
-}
-
-bool visit_expression_type_c::get_error_found(void) {
-  return error_found;
-}
-
-
-
-/* NOTE on data type handling and literals...
- * ==========================================
- *
- * Literals that are explicitly type cast 
- *   e.g.:   BYTE#42
- *           INT#65
- *           TIME#45h23m
- *               etc...
- *  are NOT considered literals in the following code.
- *  Since they are type cast, and their data type is fixed and well known,
- *  they are treated as a variable of that data type (except when determining lvalues)
- *  In other words, when calling search_constant_type_c on these constants, it returns
- *  a xxxxx_type_name_c, and not one of the xxxx_literal_c ! 
- *
- *  When the following code handles a literal, it is really a literal of unknown data type.
- *    e.g.   42, may be considered an int, a byte, a word, etc... 
- *
- * NOTE: type_symbol == NULL is valid!
- *       This will occur, for example, when and undefined/undeclared symbolic_variable is used in the program.
- *       This will not be of any type, so we always return false.
- */
-
-/* A helper function... */
-bool visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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;}
-// TODO literal_string ???
-  return false;
-}
-
-/* A helper function... */
-bool visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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;}
-  if (is_literal_integer_type(type_symbol))          {return true;}
-  return false;
-}
-
-/* A helper function... */
-bool visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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;}
-  if (is_literal_real_type(type_symbol))              {return true;}
-  return false;
-}
-
-/* A helper function... */
-bool visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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;}
-  if (is_nonneg_literal_integer_type(type_symbol))   {return true;}
-  if (is_literal_bool_type(type_symbol))             {return true;}
-  return false;
-}
-
-/* A helper function... */
-bool visit_expression_type_c::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 visit_expression_type_c::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 visit_expression_type_c::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;}
-  if (is_literal_bool_type(type_symbol))              {return true;}
-  return false;
-}
-
-
-#define is_type(type_name_symbol, type_name_class)  ((type_name_symbol == NULL) ? false : (typeid(*type_name_symbol) == typeid(type_name_class)))
-
-
-#define sizeoftype(symbol) get_sizeof_datatype_c::getsize(symbol)
-
-
-/* A helper function... */
-bool visit_expression_type_c::is_literal_integer_type(symbol_c *type_symbol) {
-  if (type_symbol == NULL) {return false;}
-  if (typeid(*type_symbol) == typeid(neg_integer_c))        {return true;}
-  return is_nonneg_literal_integer_type(type_symbol);
-}
-
-
-/* A helper function... */
-bool visit_expression_type_c::is_nonneg_literal_integer_type(symbol_c *type_symbol) {
-  if (type_symbol == NULL) {return false;}
-  if (typeid(*type_symbol) == typeid(integer_c))        {return true;}
-  if (typeid(*type_symbol) == typeid(binary_integer_c)) {return true;}
-  if (typeid(*type_symbol) == typeid(octal_integer_c))  {return true;}
-  if (typeid(*type_symbol) == typeid(hex_integer_c))    {return true;}
-  return false;
-}
-
-
-/* A helper function... */
-bool visit_expression_type_c::is_literal_real_type(symbol_c *type_symbol) {
-  if (type_symbol == NULL) {return false;}
-  if (typeid(*type_symbol) == typeid(real_c))     {return true;}
-  if (typeid(*type_symbol) == typeid(neg_real_c)) {return true;}
-  return false;
-}
-
-
-/* A helper function... */
-bool visit_expression_type_c::is_literal_bool_type(symbol_c *type_symbol) {
-  bool_type_name_c bool_t;
-
-  if (type_symbol == NULL) {return false;}
-  if (typeid(*type_symbol) == typeid(boolean_true_c))    {return true;}
-  if (typeid(*type_symbol) == typeid(boolean_false_c))   {return true;}
-  if (is_nonneg_literal_integer_type(type_symbol))
-    if (sizeoftype(&bool_t) >= sizeoftype(type_symbol))  {return true;}
-  return false;
-}
-
-bool visit_expression_type_c::is_ANY_ELEMENTARY_OR_ENUMERATED_compatible(symbol_c *type_symbol) {
-  if (type_symbol == NULL) {return false;}
-  if (search_base_type.type_is_enumerated(type_symbol)) {return true;}
-  return is_ANY_ELEMENTARY_compatible(type_symbol);
-}
-
-
-/* Determine the common data type between two data types.
- * If no common data type found, return NULL.
- *
- * If data types are identical, return the first (actually any would do...).
- * If any of the data types is a literal, we confirm that 
- *   the literal uses less bits than the fixed size data type.
- *   e.g. BYTE and 1024 returns NULL
- *        BYTE and 255  returns BYTE
- *
- * If two literals, then return the literal that requires more bits...
- */
-
-symbol_c *visit_expression_type_c::common_type__(symbol_c *first_type, symbol_c *second_type) {
-  if (first_type == NULL && second_type == NULL) {return NULL;}
-  if (first_type == NULL)  {return second_type;}
-  if (second_type == NULL) {return first_type;}
-
-  if (is_literal_integer_type(first_type) && is_literal_integer_type(second_type))
-    {return ((sizeoftype(first_type) > sizeoftype(second_type))? first_type:second_type);}
-
-  if (is_literal_real_type(first_type) && is_literal_real_type(second_type))
-    {return ((sizeoftype(first_type) > sizeoftype(second_type))? first_type:second_type);}
-
-  if (is_literal_bool_type(first_type) && is_literal_bool_type(second_type))
-    {return first_type;}
-
-  /* The following check can only be made after the is_literal_XXXX checks */
-  /* When two literals of the same type, with identical typeid's are checked,
-   * we must return the one that occupies more bits... This is done above.
-   */
-  if (typeid(*first_type) == typeid(*second_type)) {return first_type;}
-
-  /* NOTE Although a BOOL is also an ANY_BIT, we must check it explicitly since some
-   *       literal bool values are not literal integers...
-   */ 
-  if (is_BOOL_type(first_type)        && is_literal_bool_type(second_type))    {return first_type;}
-  if (is_BOOL_type(second_type)       && is_literal_bool_type(first_type))     {return second_type;}
-
-  if (is_SAFEBOOL_type(first_type)    && is_literal_bool_type(second_type))    {return first_type;}
-  if (is_SAFEBOOL_type(second_type)   && is_literal_bool_type(first_type))     {return second_type;}
-
-  if (is_SAFEBOOL_type(first_type)    && is_BOOL_type(second_type))            {return second_type;}
-  if (is_SAFEBOOL_type(second_type)   && is_BOOL_type(first_type))             {return first_type;}
-
-  if (is_ANY_BIT_type(first_type)     && is_nonneg_literal_integer_type(second_type))
-    {return ((sizeoftype(first_type)  >= sizeoftype(second_type))? first_type :NULL);}
-  if (is_ANY_BIT_type(second_type)    && is_nonneg_literal_integer_type(first_type))
-    {return ((sizeoftype(second_type) >= sizeoftype(first_type)) ? second_type:NULL);}
-
-  if (is_ANY_SAFEBIT_type(first_type)     && is_nonneg_literal_integer_type(second_type))
-    {return ((sizeoftype(first_type)  >= sizeoftype(second_type))? first_type :NULL);}
-  if (is_ANY_SAFEBIT_type(second_type)    && is_nonneg_literal_integer_type(first_type))
-    {return ((sizeoftype(second_type) >= sizeoftype(first_type)) ? second_type:NULL);}
-
-  if  (is_ANY_SAFEBIT_type(first_type)    && is_ANY_BIT_type(second_type))
-    {return ((sizeoftype(first_type) == sizeoftype(second_type))? second_type:NULL);}
-  if  (is_ANY_SAFEBIT_type(second_type)   && is_ANY_BIT_type(first_type))
-    {return ((sizeoftype(first_type) == sizeoftype(second_type))? first_type :NULL);}
-
-  if (is_ANY_INT_type(first_type)     && is_literal_integer_type(second_type))
-    {return ((sizeoftype(first_type)  >= sizeoftype(second_type))? first_type :NULL);}
-  if (is_ANY_INT_type(second_type)    && is_literal_integer_type(first_type))
-    {return ((sizeoftype(second_type) >= sizeoftype(first_type)) ? second_type:NULL);}
-
-  if (is_ANY_SAFEINT_type(first_type)     && is_literal_integer_type(second_type))
-    {return ((sizeoftype(first_type)  >= sizeoftype(second_type))? first_type :NULL);}
-  if (is_ANY_SAFEINT_type(second_type)    && is_literal_integer_type(first_type))
-    {return ((sizeoftype(second_type) >= sizeoftype(first_type)) ? second_type:NULL);}
-
-  if  (is_ANY_SAFEINT_type(first_type)    && is_ANY_INT_type(second_type))
-    {return ((sizeoftype(first_type) == sizeoftype(second_type))? second_type:NULL);}
-  if  (is_ANY_SAFEINT_type(second_type)   && is_ANY_INT_type(first_type))
-    {return ((sizeoftype(first_type) == sizeoftype(second_type))? first_type :NULL);}
-
-  if (is_ANY_REAL_type(first_type)    && is_literal_real_type(second_type))
-    {return ((sizeoftype(first_type)  >= sizeoftype(second_type))? first_type :NULL);}
-  if (is_ANY_REAL_type(second_type)   && is_literal_real_type(first_type))
-    {return ((sizeoftype(second_type) >= sizeoftype(first_type)) ? second_type:NULL);}
-
-  if (is_ANY_SAFEREAL_type(first_type)    && is_literal_real_type(second_type))
-    {return ((sizeoftype(first_type)  >= sizeoftype(second_type))? first_type :NULL);}
-  if (is_ANY_SAFEREAL_type(second_type)   && is_literal_real_type(first_type))
-    {return ((sizeoftype(second_type) >= sizeoftype(first_type)) ? second_type:NULL);}
-
-  if  (is_ANY_SAFEREAL_type(first_type)    && is_ANY_REAL_type(second_type))
-    {return ((sizeoftype(first_type) == sizeoftype(second_type))? second_type:NULL);}
-  if  (is_ANY_SAFEREAL_type(second_type)   && is_ANY_REAL_type(first_type))
-    {return ((sizeoftype(first_type) == sizeoftype(second_type))? first_type :NULL);}
-
-  /* the Time and Date types... */
-  if (is_type(first_type,  safetime_type_name_c) && is_type(second_type, time_type_name_c))  {return second_type;}
-  if (is_type(second_type, safetime_type_name_c) && is_type( first_type, time_type_name_c))  {return  first_type;}
-
-  if (is_type(first_type,  safedate_type_name_c) && is_type(second_type, date_type_name_c))  {return second_type;}
-  if (is_type(second_type, safedate_type_name_c) && is_type( first_type, date_type_name_c))  {return  first_type;}
-
-  if (is_type(first_type,  safedt_type_name_c)   && is_type(second_type, dt_type_name_c))    {return second_type;}
-  if (is_type(second_type, safedt_type_name_c)   && is_type( first_type, dt_type_name_c))    {return  first_type;}
-
-  if (is_type(first_type,  safetod_type_name_c)  && is_type(second_type, tod_type_name_c))   {return second_type;}
-  if (is_type(second_type, safetod_type_name_c)  && is_type( first_type, tod_type_name_c))   {return  first_type;}
-
-  /* no common type */
-  return NULL;
-}
-
-/* Determine the common data type between two data types.
- * Unlike the common_type__() function, we stop the compiler with an ERROR
- *  if no common data type is found.
- */
-symbol_c *visit_expression_type_c::common_type(symbol_c *first_type, symbol_c *second_type) {
-/*  
-  symbol_c *res = common_type__(first_type, second_type);
-  if (NULL == res) ERROR;
-  return res;
-*/
-  return common_type__(first_type, second_type);
-}
-
-symbol_c *visit_expression_type_c::common_literal(symbol_c *first_type, symbol_c *second_type) {
-  printf("common_literal: %d == %d, %d == %d, %d == %d\n",
-		 (int)is_ANY_INT_compatible(first_type),
-		 (int)is_ANY_INT_compatible(second_type),
-		 (int)is_ANY_REAL_compatible(first_type),
-		 (int)is_ANY_REAL_compatible(second_type),
-		 (int)is_ANY_BIT_compatible(first_type),
-		 (int)is_ANY_BIT_compatible(second_type));
-  if ((is_ANY_INT_compatible(first_type) && is_ANY_INT_compatible(second_type)) ||
-	  (is_ANY_BIT_compatible(first_type) && is_ANY_BIT_compatible(second_type)))
-	 return &search_constant_type_c::integer;
-  else if (is_ANY_REAL_compatible(first_type) && is_ANY_REAL_compatible(second_type))
-	 return &search_constant_type_c::real;
-  return NULL;
-}
-
-symbol_c *visit_expression_type_c::overloaded_return_type(symbol_c *type) {
-  if (is_ANY_INT_compatible(type))
-	return &search_constant_type_c::ulint_type_name;
-  else if (is_ANY_REAL_compatible(type))
-	return &search_constant_type_c::lreal_type_name;
-  else if (is_ANY_BIT_compatible(type))
-  	return &search_constant_type_c::lword_type_name;
-  return NULL;
-}
-
-/* Return TRUE if the second (value) data type may be assigned to a variable of the first (variable) data type
- * such as: 
- *     var_type     value_type
- *    BOOL           BYTE#7     -> returns false
- *    INT            INT#7      -> returns true
- *    INT            7          -> returns true
- *    REAL           7.89       -> returns true
- *    REAL           7          -> returns true
- *    INT            7.89       -> returns false
- *    SAFEBOOL       BOOL#1     -> returns false   !!!
- *   etc...
- *
- * NOTE: It is assumed that the var_type is the data type of an lvalue
- */
-bool visit_expression_type_c::is_valid_assignment(symbol_c *var_type, symbol_c *value_type) {
-  if (var_type == NULL)   {/* STAGE3_ERROR(value_type, value_type, "Var_type   == NULL"); */ return false;}
-  if (value_type == NULL) {/* STAGE3_ERROR(var_type,   var_type,   "Value_type == NULL"); */ return false;}
-
-  symbol_c *common_type = common_type__(var_type, value_type);
-  if (NULL == common_type)
-    return false;
-  return (typeid(*var_type) == typeid(*common_type));
-}
-
-
-/* Return TRUE if there is a common data type, otherwise return FALSE
- * i.e., return TRUE if both data types may be used simultaneously in an expression
- * such as:
- *    BOOL#0     AND BYTE#7  -> returns false
- *    0          AND BYTE#7  -> returns true
- *    INT#10     AND INT#7   -> returns true
- *    INT#10     AND 7       -> returns true
- *    REAL#34.3  AND 7.89    -> returns true
- *    REAL#34.3  AND 7       -> returns true
- *    INT#10     AND 7.89    -> returns false
- *    SAFEBOOL#0 AND BOOL#1  -> returns true   !!!
- *   etc...
- */
-bool visit_expression_type_c::is_compatible_type(symbol_c *first_type, symbol_c *second_type) {
-  if (first_type == NULL || second_type == NULL) {return false;}
-  return (NULL != common_type__(first_type, second_type));
-}
-
-
-
-
-/* A helper function... */
-/*
-symbol_c *visit_expression_type_c::compute_boolean_expression(symbol_c *left_type, symbol_c *right_type,
-                                                              is_data_type_t is_data_type) {
-*/
-symbol_c *visit_expression_type_c::compute_expression(symbol_c *left_type,      symbol_c *right_type,     is_data_type_t is_data_type,
-						      symbol_c *left_expr, symbol_c *right_expr) {
-  bool error = false;
-
-  if (!(this->*is_data_type)(left_type)) {
-    if (debug) printf("visit_expression_type_c::compute_expression(): invalid left_type\n");
-    if (left_expr != NULL)
-      STAGE3_ERROR(left_expr, left_expr, "Invalid data type of operand, or of data resulting from previous IL instructions.");
-    error = true;
-  }
-  if (!(this->*is_data_type)(right_type)) {
-    if (debug) printf("visit_expression_type_c::compute_expression(): invalid right_type\n");
-    if (right_expr != NULL)
-      STAGE3_ERROR(right_expr, right_expr, "Invalid data type of operand.");
-    error = true;
-  }
-  if (!is_compatible_type(left_type, right_type)) {
-    if (debug) printf("visit_expression_type_c::compute_expression(): left_type & right_type are incompatible\n");
-    if ((left_expr != NULL) && (right_expr != NULL))
-      STAGE3_ERROR(left_expr, right_expr, "Type mismatch between operands.");
-    error = true;
-  }
-
-  if (error)
-    return NULL;
-  else
-    return common_type(left_type, right_type);
-}
-
-
-
-
-/* A helper function... */
-/* check the semantics of a FB or Function non-formal call */
-/* e.g. foo(1, 2, 3, 4);  */
-/* If error_count pointer is != NULL, we do not really print out the errors,
- * but rather only count how many errors were found.
- * This is used to support overloaded functions, where we have to check each possible
- * function, one at a time, untill we find a function call without any errors.
- */
-void visit_expression_type_c::check_nonformal_call(symbol_c *f_call, symbol_c *f_decl, bool use_il_defvar, int *error_count) {
-  symbol_c *call_param_value, *call_param_type, *param_type;
-  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;
-  
-  /* reset error counter */
-  if (error_count != NULL) *error_count = 0;
-  /* if use_il_defvar, then the first parameter for the call comes from the il_default_variable */
-  if (use_il_defvar) {
-    /* The first parameter of the function corresponds to the il_default_variable_type of the function call */
-    do {
-      param_name = fp_iterator.next();
-      if(param_name == NULL) break;
-      /*  The EN and ENO parameters are default parameters.
-       *  In the non-formal invocation of a function there can be no assignment of
-       * values to these parameters. Therefore, we ignore the parameters declared
-       * in the function.
-       */
-    } while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0));
-    /* If the function does not have any parameters (param_name == NULL)
-     * then we cannot compare its type with the il_default_variable_type.
-     *
-     * However, I (Mario) think this is invalid syntax, as it seems to me all functions must
-     * have at least one parameter.
-     * However, we will make this semantic verification consider it possible, as later
-     * versions of the standard may change that syntax.
-     * So, instead of generating a syntax error message, we simply check whether the call
-     * is passing any more parameters besides the default variable (the il default variable may be ignored
-     * in this case, and not consider it as being a parameter being passed to the function).
-     * If it does, then we have found a semantic error, otherwise the function call is 
-     * correct, and we simply return.
-     */
-    if(param_name == NULL) {
-      if (fcp_iterator.next_nf() != NULL)
-        STAGE3_ERROR(f_call, f_call, "Too many parameters in function/FB call.");
-      return;
-    } else { 
-      /* param_name != NULL */
-      param_type = fp_iterator.param_type();
-      if(!is_valid_assignment(param_type, il_default_variable_type)) {
-        if (error_count != NULL) (*error_count)++;
-        else STAGE3_ERROR(f_call, f_call, "In function/FB call, first parameter has invalid data type.");
-      }
-    }
-    
-    /* the fisrt parameter (il_def_variable) is correct */
-    if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) {
-      extensible_parameter_highest_index = fp_iterator.extensible_param_index();
-    }
-  } // if (use_il_defvar)
-  
-  
-
-  /* Iterating through the non-formal parameters of the function call */
-  while((call_param_value = fcp_iterator.next_nf()) != NULL) {
-    /* Obtaining the type of the value being passed in the function call */
-    call_param_type = base_type((symbol_c*)call_param_value->accept(*this));
-    if (call_param_type == NULL) {
-      if (error_count != NULL) (*error_count)++;
-      /* the following error will usually occur when ST code uses an identifier, that could refer to an enumerated constant,
-       * but was not actually used as a constant in any definitions of an enumerated data type
-       */
-      else STAGE3_ERROR(call_param_value, call_param_value, "Could not determine data type of value being passed in function/FB call.");
-      continue;
-    }  
-    
-    /* 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) {
-        if (error_count != NULL) (*error_count)++;
-        /* Note: We don't want to print out the follwoing error message multiple times, so we return instead of continuing with 'break' */
-        else STAGE3_ERROR(f_call, f_call, "Too many parameters in function/FB call."); return;
-      }
-    } while ((strcmp(param_name->value, "EN") == 0) || (strcmp(param_name->value, "ENO") == 0));
-
-    /* Get the parameter type */
-    param_type = base_type(fp_iterator.param_type());
-    /* If the declared parameter and the parameter from the function call do not have the same type */
-    if(!is_valid_assignment(param_type, call_param_type)) {
-      if (error_count != NULL) (*error_count)++;
-      else STAGE3_ERROR(call_param_value, call_param_value, "Type mismatch in function/FB call parameter.");
-    }
-
-    if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) {
-      extensible_parameter_highest_index = fp_iterator.extensible_param_index();
-    }
-  }
-  
-  /* The function call may not have any errors! */
-  /* In the case of a call to an extensible function, we store the highest index 
-   * of the extensible parameters this particular call uses, in the symbol_c object
-   * of the function call itself!
-   * In calls to non-extensible functions, this value will be set to -1.
-   * This information is later used in stage4 to correctly generate the
-   * output code.
-   */
-  int extensible_param_count = -1;
-  if (extensible_parameter_highest_index >=0) /* if call to extensible function */
-    extensible_param_count = 1 + extensible_parameter_highest_index - fp_iterator.first_extensible_param_index();
-  il_function_call_c     *il_function_call = dynamic_cast<il_function_call_c *>(f_call);
-  function_invocation_c  *function_invocation  = dynamic_cast<function_invocation_c  *>(f_call);
-  if      (il_function_call     != NULL) il_function_call   ->extensible_param_count = extensible_param_count;
-  else if (function_invocation  != NULL) function_invocation->extensible_param_count = extensible_param_count;
-  //   else ERROR;  /* this function is also called by Function Blocks, so this is not an error! */
-}
-
-
-/* check semantics of FB call in the IL language using input operators */
-/* e.g. CU, CLK, IN, PT, SR, ...                                       */
-void visit_expression_type_c::check_il_fbcall(symbol_c *il_operator, const char *il_operator_str) {
-  symbol_c *call_param_type = il_default_variable_type;
-  symbol_c *fb_decl = il_operand_type;
-    /* The following should never occur. The function block must be defined, 
-     * and the FB type being called MUST be in the symtable... 
-     * This was all already checked at stage 2!
-     */
-  if (NULL == fb_decl) ERROR;
-  if (call_param_type == NULL) ERROR;
-
-  /* We also create an identifier_c object, so we can later use it to find the equivalent FB parameter */
-  /* Note however that this symbol does not have the correct location (file name and line numbers) 
-   * so any error messages must use the il_operator symbol to generate the error location
-   */
-  identifier_c call_param_name(il_operator_str);
-
-  /* Obtaining the type of the value being passed in the function call */
-  call_param_type = base_type(call_param_type);
-  if (call_param_type == NULL) STAGE3_ERROR(il_operator, il_operator, "Could not determine data type of value being passed in FB call.");
-
-  /* Find the corresponding parameter of the function being called */
-  function_param_iterator_c fp_iterator(fb_decl);
-  if(fp_iterator.search(&call_param_name) == NULL) {
-    STAGE3_ERROR(il_operand, il_operand, "Called FB does not have an input parameter named %s.", il_operator_str);
-  } else {
-    /* Get the parameter type */
-    symbol_c *param_type = base_type(fp_iterator.param_type());
-    /* If the declared parameter and the parameter from the function call have the same type */
-    if(!is_valid_assignment(param_type, call_param_type)) STAGE3_ERROR(il_operator, il_operator, "Type mismatch in FB call parameter.");
-  }
-}
-
-
-/* A helper function... */
-/* check the semantics of a FB or Function formal call */
-/* e.g. foo(IN1 := 1, OUT1 =>x, EN := true);  */
-/* If error_count pointer is != NULL, we do not really print out the errors,
- * but rather only count how many errors were found.
- * This is used to support overloaded functions, where we have to check each possible
- * function, one at a time, untill we find a function call without any errors.
- */
-void visit_expression_type_c::check_formal_call(symbol_c *f_call, symbol_c *f_decl, int *error_count) {
-  symbol_c *call_param_value, *call_param_type, *call_param_name, *param_type;
-  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;
-
-  /* reset error counter */
-  if (error_count != NULL) *error_count = 0;
-
-  /* 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;
-
-    /* Checking if there are duplicated parameter values */
-    verify_duplicate_param = fcp_iterator.search_f(call_param_name);
-    if(verify_duplicate_param != call_param_value){
-      if (error_count != NULL) (*error_count)++;
-      else STAGE3_ERROR(call_param_name, verify_duplicate_param, "Duplicated parameter values.");
-    }   
-
-    /* Obtaining the type of the value being passed in the function call */
-    call_param_type = (symbol_c*)call_param_value->accept(*this);
-    if (call_param_type == NULL) {
-      if (error_count != NULL) (*error_count)++;
-      else STAGE3_ERROR(call_param_name, call_param_value, "Could not determine data type of value being passed in function/FB call.");
-      /* The data value being passed is possibly any enumerated type value.
-       * We do not yet handle semantic verification of enumerated types.
-       */
-      ERROR;
-    }
-    call_param_type = base_type(call_param_type);
-    if (call_param_type == NULL) STAGE3_ERROR(call_param_name, call_param_value, "Could not determine data type of value being passed in function/FB call.");
-
-    /* Find the corresponding parameter of the function being called */
-    param_name = fp_iterator.search(call_param_name);
-    if(param_name == NULL) {
-      if (error_count != NULL) (*error_count)++;
-      else STAGE3_ERROR(call_param_name, call_param_name, "Invalid parameter in function/FB call.");
-    } else {
-      /* Get the parameter type */
-      param_type = base_type(fp_iterator.param_type());
-      /* If the declared parameter and the parameter from the function call have the same type */
-      if(!is_valid_assignment(param_type, call_param_type)) {
-        if (error_count != NULL) (*error_count)++;
-        else STAGE3_ERROR(call_param_name, call_param_value, "Type mismatch function/FB call parameter.");
-      }
-      if (extensible_parameter_highest_index < fp_iterator.extensible_param_index()) {
-        extensible_parameter_highest_index = fp_iterator.extensible_param_index();
-        extensible_parameter_name = param_name;
-      }
-    }
-  }
-  
-  /* In the case of a call to an extensible function, we store the highest index 
-   * of the extensible parameters this particular call uses, in the symbol_c object
-   * of the function call itself!
-   * In calls to non-extensible functions, this value will be set to -1.
-   * This information is later used in stage4 to correctly generate the
-   * output code.
-   */
-  int extensible_param_count = -1;
-  if (extensible_parameter_highest_index >=0) /* if call to extensible function */
-    extensible_param_count = 1 + extensible_parameter_highest_index - fp_iterator.first_extensible_param_index();
-  il_formal_funct_call_c *il_formal_funct_call = dynamic_cast<il_formal_funct_call_c *>(f_call);
-  function_invocation_c  *function_invocation  = dynamic_cast<function_invocation_c  *>(f_call);
-  if      (il_formal_funct_call != NULL) il_formal_funct_call->extensible_param_count = extensible_param_count;
-  else if (function_invocation  != NULL) function_invocation->extensible_param_count  = extensible_param_count;
-//   else ERROR;  /* this function is also called by Function Blocks, so this is not an error! */
-
-  /* We have iterated through all the formal parameters of the function call,
-   * and everything seems fine. 
-   * If the function being called in an extensible function, we now check
-   * whether the extensible paramters in the formal invocation do not skip
-   * any indexes...
-   *
-   * f(in1:=0, in2:=0, in4:=0) --> ERROR!!
-   */
-  if (extensible_parameter_highest_index >=0) { /* if call to extensible function */
-    for (int i=fp_iterator.first_extensible_param_index(); i < extensible_parameter_highest_index; i++) {
-      char tmp[256];
-      if (snprintf(tmp, 256, "%s%d", extensible_parameter_name->value, i) >= 256) ERROR;
-      if (fcp_iterator.search_f(tmp) == NULL) {
-        /* error in invocation of extensible function */
-        if (error_count != NULL) (*error_count)++;
-        else STAGE3_ERROR(f_call, f_call, "Missing extensible parameters in call to extensible function.");
-      }  
-    }    
-  }  
-}
-
-
-
-
-/* a helper function... */
-symbol_c *visit_expression_type_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);
-}
-
-
-/* a helper function... */
-void *visit_expression_type_c::verify_null(symbol_c *symbol){
-  if(il_default_variable_type == NULL){
-    STAGE3_ERROR(symbol, symbol, "Missing LD instruction (or equivalent) before this instruction.");
-  }
-  if(il_operand_type == NULL){
-    STAGE3_ERROR(symbol, symbol, "This instruction requires an operand.");
-  }
-  return NULL;
-}
-
-
-/********************************/
-/* B 1.3.3 - Derived data types */
-/********************************/
-void *visit_expression_type_c::visit(data_type_declaration_c *symbol) {
-  // TODO !!!
-  /* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */
-  return NULL;
-}
-
-
-/*********************/
-/* B 1.4 - Variables */
-/*********************/
-
-void *visit_expression_type_c::visit(symbolic_variable_c *symbol) {
-  return search_varfb_instance_type->get_basetype_decl(symbol);
-}
-
-/********************************************/
-/* B 1.4.1 - Directly Represented Variables */
-/********************************************/
-void *visit_expression_type_c::visit(direct_variable_c *symbol) {
-  switch (symbol->value[2]) {
-    case 'X': // bit - 1 bit
-      return (void *)&bool_type_name;
-    case 'B': // byte - 8 bits
-      return (void *)&byte_type_name;
-    case 'W': // word - 16 bits
-      return (void *)&word_type_name;
-    case 'D': // double word - 32 bits
-      return (void *)&dword_type_name;
-    case 'L': // long word - 64 bits
-      return (void *)&lword_type_name;
-    default:  // if none of the above, then the empty string was used <=> boolean 
-      return (void *)&bool_type_name;
-   }
-}
-
-/*************************************/
-/* B 1.4.2 - Multi-element variables */
-/*************************************/
-void *visit_expression_type_c::visit(array_variable_c *symbol) {
-  return search_varfb_instance_type->get_basetype_decl(symbol);
-}
-
-void *visit_expression_type_c::visit(structured_variable_c *symbol) {
-  return search_varfb_instance_type->get_basetype_decl(symbol);
-}
-
-
-
-/********************************/
-/* B 1.7 Configuration elements */
-/********************************/
-void *visit_expression_type_c::visit(configuration_declaration_c *symbol) {
-  // TODO !!!
-  /* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */
-  return NULL;
-}
-
-
-/****************************************/
-/* B.2 - Language IL (Instruction List) */
-/****************************************/
-/***********************************/
-/* B 2.1 Instructions and Operands */
-/***********************************/
-/*| instruction_list il_instruction */
-/* The visitor of the base class search_visitor_c will handle calling each instruction in the list.
- * We do not need to do anything here...
- */
-// void *visit_expression_type_c::visit(instruction_list_c *symbol)
-
-/* | label ':' [il_incomplete_instruction] eol_list */
-//SYM_REF2(il_instruction_c, label, il_instruction)
-// void *visit_expression_type_c::visit(il_instruction_c *symbol);
-
-
-/* | il_simple_operator [il_operand] */
-// SYM_REF2(il_simple_operation_c, il_simple_operator, il_operand)
-void *visit_expression_type_c::visit(il_simple_operation_c *symbol) {
-  if (il_error)
-    return NULL;
-
-  /* determine the data type of the operand */
-  il_operand = symbol->il_operand;
-  if (symbol->il_operand != NULL){
-    il_operand_type = base_type((symbol_c *)symbol->il_operand->accept(*this));
-  } else {
-    il_operand_type = NULL;
-  }
-  /* recursive call to see whether data types are compatible */
-  symbol->il_simple_operator->accept(*this);
-
-  il_operand_type = NULL;
-  il_operand = NULL;
-  return NULL;
-}
-
-// | function_name [il_operand_list] */
-//SYM_REF2(il_function_call_c, function_name, il_operand_list)
-void *visit_expression_type_c::visit(il_function_call_c *symbol) {
-  if (il_error)
-    return NULL;
-
-  symbol_c *return_data_type = NULL;
-  symbol_c* fdecl_return_type;
-  symbol->called_function_declaration = NULL;
-
-  /* First find the declaration of the function being called! */
-  function_symtable_t::iterator lower = function_symtable.lower_bound(symbol->function_name);
-  function_symtable_t::iterator upper = function_symtable.upper_bound(symbol->function_name);
-  if (lower == function_symtable.end()) ERROR;
-
-  int error_count = 0; 
-  int *error_count_ptr = NULL;
-
-  function_symtable_t::iterator second = lower;
-  second++;
-  if (second != upper) 
-    /* This is a call to an overloaded function... */  
-    error_count_ptr = &error_count;
-
-  for(; lower != upper; lower++) {
-    function_declaration_c *f_decl = function_symtable.get_value(lower);
-    
-    check_nonformal_call(symbol, f_decl, true, error_count_ptr);
-    
-    if (0 == error_count) {
-      /* Either: 
-       * (i) we have a call to a non-overloaded function (error_cnt_ptr is NULL!, so error_count won't change!)  
-       * (ii) we have a call to an overloaded function, with no errors!
-       */
-
-      fdecl_return_type = base_type(f_decl->type_name);
-
-      if (symbol->called_function_declaration == NULL) {
-      	/* Store the pointer to the declaration of the function being called.
-      	 * This data will be used by stage 4 to call the correct function.
-      	 * Mostly needed to disambiguate overloaded functions...
-      	 * See comments in absyntax.def for more details
-         */
-        symbol->called_function_declaration = f_decl;
-  		symbol->overloaded_return_type = NULL;
-
-  		/* determine the base data type returned by the function being called... */
-  	    return_data_type = fdecl_return_type;
-  	  }
-  	  else if (typeid(*return_data_type) != typeid(*fdecl_return_type)){
-  		if (symbol->overloaded_return_type == NULL)
-  		  symbol->overloaded_return_type = overloaded_return_type(return_data_type);
-  		return_data_type = common_literal(return_data_type, fdecl_return_type);
-  	  }
-      
-      if (NULL == return_data_type) ERROR;
-    }
-  }
-
-  if (NULL == return_data_type) {
-    /* No compatible function was found for this function call */
-    STAGE3_ERROR(symbol, symbol, "Call to an overloaded function with invalid parameter type.");
-  }
-  else {
-    /* set the new data type of the default variable for the following verifications... */
-    il_default_variable_type = return_data_type;
-  }
-
-  return NULL;
-}
-
-
-/* | il_expr_operator '(' [il_operand] eol_list [simple_instr_list] ')' */
-// SYM_REF3(il_expression_c, il_expr_operator, il_operand, simple_instr_list);
-void *visit_expression_type_c::visit(il_expression_c *symbol) {
-  if (il_error)
-    return NULL;
-
-  symbol_c *il_default_variable_type_back = il_default_variable_type;
-
-  il_parenthesis_level++;
-
-  if(symbol->il_operand != NULL) {
-     il_default_variable_type = base_type((symbol_c *)symbol->il_operand->accept(*this));
-  } else {
-     il_default_variable_type = NULL;
-  }
-
-  if(symbol->simple_instr_list != NULL) {
-    symbol->simple_instr_list->accept(*this);
-  }
-
-  il_parenthesis_level--;
-  if (il_parenthesis_level < 0) ERROR;
-
-  il_operand = symbol->simple_instr_list;
-  il_operand_type = il_default_variable_type;
-  il_default_variable_type = il_default_variable_type_back;
-
-  /* Now check the if the data type semantics of operation are correct,
-   * but only if no previous error has been found...
-   */
-  if (!il_error)
-    symbol->il_expr_operator->accept(*this);
-
-  il_operand_type = NULL;
-  il_operand = NULL;
-  return NULL;
-}
-
-
-#if 0
-/*  il_jump_operator label */
-SYM_REF2(il_jump_operation_c, il_jump_operator, label)
-void *visit_expression_type_c::visit(il_jump_operation_c *symbol);
-#endif
-
-
-/*   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 ')'
- */
-/* SYM_REF4(il_fb_call_c, il_call_operator, fb_name, il_operand_list, il_param_list) */
-void *visit_expression_type_c::visit(il_fb_call_c *symbol) {
-  if (il_error)
-    return NULL;
-
-  /* first check whether the il_default_variable is of the correct type
-   * for the CAL / CALC / CALCN operator being used...
-   */
-  symbol->il_call_operator->accept(*this);
-
-  /* Now check the FB call itself... */
-
-  /* First we find the declaration of the FB type of the FB instance being called... */
-  /* e.g.  Function_block foo_fb_type
-   *         ...
-   *       End_Function_Block
-   *
-   *       Program test
-   *         var fb1 : foo_fb_type; end_var
-   *         fb1(...)
-   *       End_Program
-   *
-   *    search_varfb_instance_type->get_basetype_decl( identifier_c("fb1") )
-   *    in the scope of Program 'test'
-   *    will return the fb declaration of foo_fb_type !!
-   */
-#if 0
-  symbol_c *fb_decl_symbol = search_varfb_instance_type->get_basetype_decl(symbol->fb_name);
-    /* The following should never occur. The function block must be defined, 
-     * and the FB type being called MUST be in the symtable... 
-     * This was all already checked at stage 2!
-     */
-  if (NULL == fb_decl_symbol) ERROR;
-
-  function_block_declaration_c *fb_decl = dynamic_cast<function_block_declaration_c *>(fb_decl_symbol);
-    /* should never occur. ... */
-  if (NULL == fb_decl) ERROR;
-#endif
-  symbol_c *fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name);
-    /* The following should never occur. The function block must be defined, 
-     * and the FB type being called MUST be in the symtable... 
-     * This was all already checked at stage 2!
-     */
-  if (NULL == fb_decl) ERROR;
-
-  /* now check the semantics of the fb call... */
-  /* If the syntax parser is working correctly, exactly one of the 
-   * following two symbols will be NULL, while the other is != NULL.
-   */
-  if (NULL != symbol->il_operand_list)  check_nonformal_call(symbol, fb_decl);
-  if (NULL != symbol->il_param_list)    check_formal_call   (symbol, fb_decl);
-
-  return NULL;
-}
-
-
-
-/* | function_name '(' eol_list [il_param_list] ')' */
-/* SYM_REF2(il_formal_funct_call_c, function_name, il_param_list) */
-void *visit_expression_type_c::visit(il_formal_funct_call_c *symbol) {
-  if (il_error)
-    return NULL;
-
-  symbol_c *return_data_type = NULL;
-  symbol_c* fdecl_return_type;
-  symbol->called_function_declaration = NULL;
-
-  function_symtable_t::iterator lower = function_symtable.lower_bound(symbol->function_name);
-  function_symtable_t::iterator upper = function_symtable.upper_bound(symbol->function_name);
-  
-  if (lower == function_symtable.end()) {
-    function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name);
-    if (current_function_type == function_none) ERROR;
-    return NULL;
-  }
-
-  int error_count = 0; 
-  int *error_count_ptr = NULL;
-
-  function_symtable_t::iterator second = lower;
-  second++;
-  if (second != upper) 
-    /* This is a call to an overloaded function... */  
-    error_count_ptr = &error_count;
-
-  for(; lower != upper; lower++) {
-    function_declaration_c *f_decl = function_symtable.get_value(lower);
-  
-    /* check semantics of data passed in the function call... */
-    check_formal_call(symbol, f_decl, error_count_ptr);
-
-    if (0 == error_count) {
-      /* Either: 
-       * (i) we have a call to a non-overloaded function (error_cnt_ptr is NULL!, so error_count won't change!)  
-       * (ii) we have a call to an overloaded function, with no errors!
-       */
-
-      fdecl_return_type = base_type(f_decl->type_name);
-
-      if (symbol->called_function_declaration == NULL) {
-    	/* Store the pointer to the declaration of the function being called.
-    	 * This data will be used by stage 4 to call the correct function.
-    	 * Mostly needed to disambiguate overloaded functions...
-    	 * See comments in absyntax.def for more details
-         */
-        symbol->called_function_declaration = f_decl;
-		symbol->overloaded_return_type = NULL;
-
-		/* determine the base data type returned by the function being called... */
-		return_data_type = fdecl_return_type;
-	  }
-	  else if (typeid(*return_data_type) != typeid(*fdecl_return_type)){
-		if (symbol->overloaded_return_type == NULL)
-		  symbol->overloaded_return_type = overloaded_return_type(return_data_type);
-		return_data_type = common_literal(return_data_type, fdecl_return_type);
-	  }
-
-      /* the following should never occur. If it does, then we have a bug in the syntax parser (stage 2)... */
-      if (NULL == return_data_type) ERROR;
-
-    }
-  }
-  
-  if (NULL == return_data_type) {
-	/* No compatible function was found for this function call */
-	STAGE3_ERROR(symbol, symbol, "Call to an overloaded function with invalid parameter type.");
-  }
-  else {
-    /* the data type of the data returned by the function, and stored in the il default variable... */
-    il_default_variable_type = return_data_type;
-  }
-
-  return NULL;
-}
-
-
-#if 0
-/* | il_operand_list ',' il_operand */
-SYM_LIST(il_operand_list_c)
-void *visit_expression_type_c::visit(il_operand_list_c *symbol);
-
-/* | simple_instr_list il_simple_instruction */
-SYM_LIST(simple_instr_list_c)
-void *visit_expression_type_c::visit(simple_instr_list_c *symbol);
-
-/* | il_initial_param_list il_param_instruction */
-SYM_LIST(il_param_list_c)
-void *visit_expression_type_c::visit(il_param_list_c *symbol);
-
-/*  il_assign_operator il_operand
- * | il_assign_operator '(' eol_list simple_instr_list ')'
- */
-SYM_REF3(il_param_assignment_c, il_assign_operator, il_operand, simple_instr_list)
-void *visit_expression_type_c::visit(il_param_assignment_c *symbol);
-/*  il_assign_out_operator variable */
-SYM_REF2(il_param_out_assignment_c, il_assign_out_operator, variable)
-void *visit_expression_type_c::visit(il_param_out_assignment_c *symbol);
-
-#endif
-
-
-/*******************/
-/* B 2.2 Operators */
-/*******************/
-
-//SYM_REF0(LD_operator_c)
-void *visit_expression_type_c::visit(LD_operator_c *symbol) {
-  if (0 == il_parenthesis_level)
-    il_error = false;
-
-  if(il_operand_type == NULL)
-      STAGE3_ERROR(symbol, symbol, "LD operator requires an operand.");
-  il_default_variable_type = il_operand_type;
-  return NULL;
-}
-
-// SYM_REF0(LDN_operator_c)
-void *visit_expression_type_c::visit(LDN_operator_c *symbol) {
-  if(il_operand_type == NULL)
-      STAGE3_ERROR(symbol, symbol, "LDN operator requires an operand.");
-  if(!is_ANY_BIT_compatible(il_operand_type))
-      STAGE3_ERROR(symbol, il_operand, "invalid data type of LDN operand, should be of type ANY_BIT.");
-  il_default_variable_type = il_operand_type;
-  return NULL;
-}
-
-// SYM_REF0(ST_operator_c)
-void *visit_expression_type_c::visit(ST_operator_c *symbol) {
-  verify_null(symbol);
-
-  if(!is_valid_assignment(il_operand_type, il_default_variable_type))
-    STAGE3_ERROR(symbol, symbol, "Type mismatch in ST operation.");
-  /* TODO: check whether il_operand_type is an LVALUE !! */
-  /* data type of il_default_variable_type is unchanged... */
-  // il_default_variable_type = il_default_variable_type;
-  return NULL;
-}
-
-// SYM_REF0(STN_operator_c)
- void *visit_expression_type_c::visit(STN_operator_c *symbol) {
-  verify_null(symbol);
-  if(!is_valid_assignment(il_operand_type, il_default_variable_type))
-    STAGE3_ERROR(symbol, symbol, "Type mismatch in ST operation.");
-  /* TODO: check whether il_operand_type is an LVALUE !! */
-  if(!is_ANY_BIT_compatible(il_default_variable_type))
-      STAGE3_ERROR(symbol, symbol, "invalid data type of il_default_variable for STN operand, should be of type ANY_BIT.");
-  if(!is_ANY_BIT_compatible(il_operand_type))
-      STAGE3_ERROR(symbol, il_operand, "invalid data type of STN operand, should be of type ANY_BIT.");
-  /* data type of il_default_variable_type is unchanged... */
-  // il_default_variable_type = il_default_variable_type;
-  return NULL;
-}
-
-//SYM_REF0(NOT_operator_c)
-void *visit_expression_type_c::visit(NOT_operator_c *symbol) {
-  if(il_operand_type != NULL){
-    STAGE3_ERROR(symbol, il_operand, "NOT operator may not have an operand.");
-    return NULL;
-  }
-  if(il_default_variable_type == NULL) {
-    STAGE3_ERROR(symbol, symbol, "Il default variable should not be NULL.");
-    return NULL;
-  }
-  if(!is_ANY_BIT_compatible(il_default_variable_type)) {
-    STAGE3_ERROR(symbol, symbol, "Il default variable should be of type ANY_BIT.");
-    return NULL;
-  }
-  /* data type of il_default_variable_type is unchanged... */
-  // il_default_variable_type = il_default_variable_type;
-  return NULL;
-}
-
-// SYM_REF0(S_operator_c)
-void *visit_expression_type_c::visit(S_operator_c *symbol) {
-  verify_null(symbol);
-  if (!is_BOOL_type(il_default_variable_type)) {STAGE3_ERROR(symbol, symbol, "IL default variable should be BOOL type.");}
-  if (!is_BOOL_type(il_operand_type)) {STAGE3_ERROR(symbol, il_operand, "operator S requires operand of type BOOL.");}
-  /* TODO: check whether il_operand_type is an LVALUE !! */
-  /* data type of il_default_variable_type is unchanged... */
-  // il_default_variable_type = il_default_variable_type;
-  return NULL;
-}
-
-// SYM_REF0(R_operator_c)
-void *visit_expression_type_c::visit(R_operator_c *symbol) {
-  verify_null(symbol);
-  if (!is_BOOL_type(il_default_variable_type)) {STAGE3_ERROR(symbol, symbol, "IL default variable should be BOOL type.");}
-  if (!is_BOOL_type(il_operand_type)) {STAGE3_ERROR(symbol, il_operand, "operator R requires operand of type BOOL.");}
-  /* TODO: check whether il_operand_type is an LVALUE !! */
-  /* data type of il_default_variable_type is unchanged... */
-  // il_default_variable_type = il_default_variable_type;
-  return NULL;
-}
-
-
-// SYM_REF0(S1_operator_c)
-void *visit_expression_type_c::visit(S1_operator_c *symbol){
-  check_il_fbcall(symbol, "S1");
-  return NULL;
-}
-
-// SYM_REF0(R1_operator_c)
-void *visit_expression_type_c::visit(R1_operator_c *symbol) {
-  check_il_fbcall(symbol, "R1");
-  return NULL;
-}
-
-// SYM_REF0(CLK_operator_c)
-void *visit_expression_type_c::visit(CLK_operator_c *symbol) {
-  check_il_fbcall(symbol, "CLK");
-  return NULL;
-}
-
-// SYM_REF0(CU_operator_c)
-void *visit_expression_type_c::visit(CU_operator_c *symbol) {
-  check_il_fbcall(symbol, "CU");
-  return NULL;
-}
-
-// SYM_REF0(CD_operator_c)
-void *visit_expression_type_c::visit(CD_operator_c *symbol) {
-  check_il_fbcall(symbol, "CD");
-  return NULL;
-}
-
-// SYM_REF0(PV_operator_c)
-void *visit_expression_type_c::visit(PV_operator_c *symbol) {
-  check_il_fbcall(symbol, "PV");
-  return NULL;
-}
-
-// SYM_REF0(IN_operator_c)
-void *visit_expression_type_c::visit(IN_operator_c *symbol) {
-  check_il_fbcall(symbol, "IN");
-  return NULL;
-}
-
-// SYM_REF0(PT_operator_c)
-void *visit_expression_type_c::visit(PT_operator_c *symbol) {
-  check_il_fbcall(symbol, "PT");
-  return NULL;
-}
-
-//SYM_REF0(AND_operator_c)
-void *visit_expression_type_c::visit(AND_operator_c *symbol) {
-  verify_null(symbol);
-  il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_compatible,
-                                                symbol                  , il_operand);
-  return NULL;
-}
-
-//SYM_REF0(OR_operator_c)
-void *visit_expression_type_c::visit(OR_operator_c *symbol) {
-  verify_null(symbol);
-  il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_compatible,
-                                                symbol                  , il_operand);
-  return NULL;
-}
-
-//SYM_REF0(XOR_operator_c)
-void *visit_expression_type_c::visit(XOR_operator_c *symbol) {
-  verify_null(symbol);
-  il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_compatible,
-                                                symbol                  , il_operand);
-  return NULL;
-}
-
-// SYM_REF0(ANDN_operator_c)
-void *visit_expression_type_c::visit(ANDN_operator_c *symbol) {
-  verify_null(symbol);
-  il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_compatible,
-                                                symbol                  , il_operand);
-  return NULL;
-}
-
-// SYM_REF0(ORN_operator_c)
-void *visit_expression_type_c::visit(ORN_operator_c *symbol) {
-  verify_null(symbol);
-  il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_compatible,
-                                                symbol                  , il_operand);
-  return NULL;
-}
-
-// SYM_REF0(XORN_operator_c)
-void *visit_expression_type_c::visit(XORN_operator_c *symbol) {
-  verify_null(symbol);
-  il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_BIT_compatible,
-                                                symbol                  , il_operand);
-  return NULL;
-}
-
-// SYM_REF0(ADD_operator_c)
-void *visit_expression_type_c::visit(ADD_operator_c *symbol) {
-  verify_null(symbol);
-  symbol_c *left_type  = il_default_variable_type;
-  symbol_c *right_type = il_operand_type;
-
-/* The following is not required, it is already handled by compute_expression() ... */
-/*
-  if      (is_type(left_type, time_type_name_c) && is_type(right_type, time_type_name_c))
-    il_default_variable_type = &time_type_name;
-*/
-
-  if      (is_type(left_type, tod_type_name_c)      && is_type(right_type, time_type_name_c))
-    il_default_variable_type = &tod_type_name;
-  else if (is_type(left_type, safetod_type_name_c)  && is_type(right_type, time_type_name_c))
-    il_default_variable_type = &tod_type_name;
-  else if (is_type(left_type, tod_type_name_c)      && is_type(right_type, safetime_type_name_c))
-    il_default_variable_type = &tod_type_name;
-  else if (is_type(left_type, safetod_type_name_c)  && is_type(right_type, safetime_type_name_c))
-    il_default_variable_type = &safetod_type_name;
-
-  else if (is_type(left_type, dt_type_name_c)       && is_type(right_type, time_type_name_c))
-    il_default_variable_type = &dt_type_name;
-  else if (is_type(left_type, safedt_type_name_c)   && is_type(right_type, time_type_name_c))
-    il_default_variable_type = &dt_type_name;
-  else if (is_type(left_type, dt_type_name_c)       && is_type(right_type, safetime_type_name_c))
-    il_default_variable_type = &dt_type_name;
-  else if (is_type(left_type, safedt_type_name_c)   && is_type(right_type, safetime_type_name_c))
-    il_default_variable_type = &safedt_type_name;
-
-  else il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_MAGNITUDE_compatible,
-                                                     symbol                  , il_operand);
-  return NULL;
-}
-
-// SYM_REF0(SUB_operator_c)
-void *visit_expression_type_c::visit(SUB_operator_c *symbol) {
-  verify_null(symbol);
-  symbol_c *left_type = il_default_variable_type;
-  symbol_c *right_type = il_operand_type;;
-
-/* The following is not required, it is already handled by compute_expression() ... */
-/*
-  if      (typeid(*left_type) == typeid(time_type_name_c) && typeid(*right_type) == typeid(time_type_name_c))
-    il_default_variable_type = &time_type_name;
-*/
-
-  if      (is_type(left_type, tod_type_name_c)       && is_type(right_type, time_type_name_c))
-    il_default_variable_type = &tod_type_name;
-  else if (is_type(left_type, safetod_type_name_c)   && is_type(right_type, time_type_name_c))
-    il_default_variable_type = &tod_type_name;
-  else if (is_type(left_type, tod_type_name_c)       && is_type(right_type, safetime_type_name_c))
-    il_default_variable_type = &tod_type_name;
-  else if (is_type(left_type, safetod_type_name_c)   && is_type(right_type, safetime_type_name_c))
-    il_default_variable_type = &safetod_type_name;
-
-  else if (is_type(left_type, dt_type_name_c)       && is_type(right_type, time_type_name_c))
-    il_default_variable_type = &dt_type_name;
-  else if (is_type(left_type, safedt_type_name_c)   && is_type(right_type, time_type_name_c))
-    il_default_variable_type = &dt_type_name;
-  else if (is_type(left_type, dt_type_name_c)       && is_type(right_type, safetime_type_name_c))
-    il_default_variable_type = &dt_type_name;
-  else if (is_type(left_type, safedt_type_name_c)   && is_type(right_type, safetime_type_name_c))
-    il_default_variable_type = &safedt_type_name;
-
-  else if (is_type(left_type, date_type_name_c)     && is_type(right_type, date_type_name_c))
-    il_default_variable_type = &time_type_name;
-  else if (is_type(left_type, safedate_type_name_c) && is_type(right_type, date_type_name_c))
-    il_default_variable_type = &time_type_name;
-  else if (is_type(left_type, date_type_name_c)     && is_type(right_type, safedate_type_name_c))
-    il_default_variable_type = &time_type_name;
-  else if (is_type(left_type, safedate_type_name_c) && is_type(right_type, safedate_type_name_c))
-    il_default_variable_type = &safetime_type_name;
-
-  else if (is_type(left_type, tod_type_name_c)      && is_type(right_type, tod_type_name_c))
-    il_default_variable_type = &time_type_name;
-  else if (is_type(left_type, safetod_type_name_c)  && is_type(right_type, tod_type_name_c))
-    il_default_variable_type = &time_type_name;
-  else if (is_type(left_type, tod_type_name_c)      && is_type(right_type, safetod_type_name_c))
-    il_default_variable_type = &time_type_name;
-  else if (is_type(left_type, safetod_type_name_c)  && is_type(right_type, safetod_type_name_c))
-    il_default_variable_type = &safetime_type_name;
-
-  else if (is_type(left_type, dt_type_name_c)       && is_type(right_type, dt_type_name_c))
-    il_default_variable_type = &time_type_name;
-  else if (is_type(left_type, safedt_type_name_c)   && is_type(right_type, dt_type_name_c))
-    il_default_variable_type = &time_type_name;
-  else if (is_type(left_type, dt_type_name_c)       && is_type(right_type, safedt_type_name_c))
-    il_default_variable_type = &time_type_name;
-  else if (is_type(left_type, safedt_type_name_c)   && is_type(right_type, safedt_type_name_c))
-    il_default_variable_type = &safetime_type_name;
-
-  else il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_MAGNITUDE_compatible,
-                                                     symbol                  , il_operand);
-  return NULL;
-}
-
-// SYM_REF0(MUL_operator_c)
-void *visit_expression_type_c::visit(MUL_operator_c *symbol) {
-  verify_null(symbol);
-  symbol_c *left_type = il_default_variable_type;
-  symbol_c *right_type = il_operand_type;
-
-  if      (is_type(left_type, time_type_name_c)     && is_ANY_NUM_compatible(right_type))
-    il_default_variable_type = &time_type_name;
-  else if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_type(right_type))
-    il_default_variable_type = &time_type_name;
-  else if (is_type(left_type, safetime_type_name_c) && is_ANY_SAFENUM_type(right_type))
-    il_default_variable_type = &safetime_type_name;
-  /* Since we have already checked for ANY_NUM_type and ANY_SAFENUM_type in the previous lines,
-   * this next line is really only to check for integers/reals of undefined type on 'right_type'... 
-   */
-  else if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_compatible(right_type))
-    il_default_variable_type = &safetime_type_name;
-
-  else il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_NUM_compatible,
-                                                     symbol                  , il_operand);
-  return NULL;
-}
-
-// SYM_REF0(DIV_operator_c)
-void *visit_expression_type_c::visit(DIV_operator_c *symbol) {
-  verify_null(symbol);
-  symbol_c *left_type = il_default_variable_type;
-  symbol_c *right_type = il_operand_type;
-
-  if      (is_type(left_type, time_type_name_c)     && is_ANY_NUM_compatible(right_type))
-    il_default_variable_type = &time_type_name;
-  else if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_type(right_type))
-    il_default_variable_type = &time_type_name;
-  else if (is_type(left_type, safetime_type_name_c) && is_ANY_SAFENUM_type(right_type))
-    il_default_variable_type = &safetime_type_name;
-  /* Since we have already checked for ANY_NUM_type and ANY_SAFENUM_type in the previous lines,
-   * this next line is really only to check for integers/reals of undefined type on 'right_type'... 
-   */
-  else if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_compatible(right_type))
-    il_default_variable_type = &safetime_type_name;
-
-  else il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_NUM_compatible,
-                                                     symbol                  , il_operand);
-  return NULL;
-}
-
-// SYM_REF0(MOD_operator_c)
-void *visit_expression_type_c::visit(MOD_operator_c *symbol) {
-  verify_null(symbol);
-  il_default_variable_type = compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_INT_compatible,
-                                                symbol                  , il_operand);
-  return NULL;
-}
-
-// SYM_REF0(GT_operator_c)
-void *visit_expression_type_c::visit(GT_operator_c *symbol) {
-  verify_null(symbol);
-  compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible,
-                     symbol                  , il_operand);
-  il_default_variable_type = &search_expression_type_c::bool_type_name;
-  return NULL;
-}
-
-//SYM_REF0(GE_operator_c)
-void *visit_expression_type_c::visit(GE_operator_c *symbol) {
-  verify_null(symbol);
-  compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible,
-                     symbol                  , il_operand);
-  il_default_variable_type = &search_expression_type_c::bool_type_name;
-  return NULL;
-}
-
-//SYM_REF0(EQ_operator_c)
-void *visit_expression_type_c::visit(EQ_operator_c *symbol) {
-  verify_null(symbol);
-  compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible,
-                     symbol                  , il_operand);
-  il_default_variable_type = &search_expression_type_c::bool_type_name;
-  return NULL;
-}
-
-//SYM_REF0(LT_operator_c)
-void *visit_expression_type_c::visit(LT_operator_c *symbol) {
-  verify_null(symbol);
-  compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible,
-                     symbol                  , il_operand);
-  il_default_variable_type = &search_expression_type_c::bool_type_name;
-  return NULL;
-}
-
-//SYM_REF0(LE_operator_c)
-void *visit_expression_type_c::visit(LE_operator_c *symbol) {
-  verify_null(symbol);
-  compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible,
-                     symbol                  , il_operand);
-  il_default_variable_type = &search_expression_type_c::bool_type_name;
-  return NULL;
-}
-
-//SYM_REF0(NE_operator_c)
-void *visit_expression_type_c::visit(NE_operator_c *symbol) {
-  verify_null(symbol);
-  compute_expression(il_default_variable_type, il_operand_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible,
-                     symbol                  , il_operand);
-  il_default_variable_type = &search_expression_type_c::bool_type_name;
-  return NULL;
-}
-
-// SYM_REF0(CAL_operator_c)
-void *visit_expression_type_c::visit(CAL_operator_c *symbol) {
-  return NULL;
-}
-
-// SYM_REF0(CALC_operator_c)
-void *visit_expression_type_c::visit(CALC_operator_c *symbol) {
-  if(il_default_variable_type == NULL)
-    STAGE3_ERROR(symbol, symbol, "CALC: il default variable should not be NULL.");
-  if (!is_BOOL_type(il_default_variable_type))
-    STAGE3_ERROR(symbol, symbol, "CALC operator requires il_default_variable to be of type BOOL.");
-  return NULL;
-}
-
-// SYM_REF0(CALCN_operator_c)
-void *visit_expression_type_c::visit(CALCN_operator_c *symbol) {
-  if(il_default_variable_type == NULL)
-    STAGE3_ERROR(symbol, symbol, "CALCN: il_default_variable should not be NULL.");
-  if (!is_BOOL_type(il_default_variable_type))
-    STAGE3_ERROR(symbol, symbol, "CALCN operator requires il_default_variable to be of type BOOL.");
-  return NULL;
-}
-
-// SYM_REF0(RET_operator_c)
-void *visit_expression_type_c::visit(RET_operator_c *symbol) {
-  return NULL;
-}
-
-// SYM_REF0(RETC_operator_c)
-void *visit_expression_type_c::visit(RETC_operator_c *symbol) {
-  if(il_default_variable_type == NULL)
-    STAGE3_ERROR(symbol, symbol, "RETC: il default variable should not be NULL.");
-  if (!is_BOOL_type(il_default_variable_type))
-    STAGE3_ERROR(symbol, symbol, "RETC operator requires il_default_variable to be of type BOOL.");
-  return NULL;
-}
-
-// SYM_REF0(RETCN_operator_c)
-void *visit_expression_type_c::visit(RETCN_operator_c *symbol) {
-  if(il_default_variable_type == NULL)
-    STAGE3_ERROR(symbol, symbol, "RETCN: il_default_variable should not be NULL.");
-  if (!is_BOOL_type(il_default_variable_type))
-    STAGE3_ERROR(symbol, symbol, "RETCN operator requires il_default_variable to be of type BOOL.");
-  return NULL;
-}
-
-// SYM_REF0(JMP_operator_c)
-void *visit_expression_type_c::visit(JMP_operator_c *symbol){
-  return NULL;
-}
-
-// SYM_REF0(JMPC_operator_c)
-void *visit_expression_type_c::visit(JMPC_operator_c *symbol) {
-  if(il_default_variable_type == NULL)
-    STAGE3_ERROR(symbol, symbol, "JMPC: il default variable should not be NULL.");
-  if (!is_BOOL_type(il_default_variable_type))
-    STAGE3_ERROR(symbol, symbol, "JMPC operator requires il_default_variable to be of type BOOL.");
-  return NULL;
-}
-
-// SYM_REF0(JMPCN_operator_c)
-void *visit_expression_type_c::visit(JMPCN_operator_c *symbol) {
-  if(il_default_variable_type == NULL)
-    STAGE3_ERROR(symbol, symbol, "JMPCN: il_default_variable should not be NULL.");
-  if (!is_BOOL_type(il_default_variable_type))
-    STAGE3_ERROR(symbol, symbol, "JMPCN operator requires il_default_variable to be of type BOOL.");
-  return NULL;
-}
-
-/* Symbol class handled together with function call checks */
-/*  any_identifier ASSIGN */
-// SYM_REF1(il_assign_operator_c, variable_name)
-// void *visit_expression_type_c::visit(il_assign_operator_c *symbol, variable_name);
-
-/* Symbol class handled together with function call checks */
-/*| [NOT] any_identifier SENDTO */
-// SYM_REF2(il_assign_out_operator_c, option, variable_name)
-// void *visit_expression_type_c::visit(il_assign_operator_c *symbol, option, variable_name);
-
-
-
-
-
-/***************************************/
-/* B.3 - Language ST (Structured Text) */
-/***************************************/
-/***********************/
-/* B 3.1 - Expressions */
-/***********************/
-
-void *visit_expression_type_c::visit(or_expression_c *symbol) {
-  symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-  return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_BIT_compatible, symbol->l_exp, symbol->r_exp);
-}
-
-
-void *visit_expression_type_c::visit(xor_expression_c *symbol) {
-  symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-  return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_BIT_compatible, symbol->l_exp, symbol->r_exp);
-}
-
-
-void *visit_expression_type_c::visit(and_expression_c *symbol) {
-  symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-  return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_BIT_compatible, symbol->l_exp, symbol->r_exp);
-}
-
-
-void *visit_expression_type_c::visit(equ_expression_c *symbol) {
-  symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-  compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_OR_ENUMERATED_compatible, symbol->l_exp, symbol->r_exp);
-  return &search_expression_type_c::bool_type_name;
-}
-
-
-void *visit_expression_type_c::visit(notequ_expression_c *symbol)  {
-  symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-  compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_OR_ENUMERATED_compatible, symbol->l_exp, symbol->r_exp);
-  return &search_expression_type_c::bool_type_name;
-}
-
-
-void *visit_expression_type_c::visit(lt_expression_c *symbol) {
-  symbol_c *left_type  = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-  compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible, symbol->l_exp, symbol->r_exp);
-  return &search_expression_type_c::bool_type_name;
-}
-
-
-void *visit_expression_type_c::visit(gt_expression_c *symbol) {
-  symbol_c *left_type  = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-  compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible, symbol->l_exp, symbol->r_exp);
-  return &search_expression_type_c::bool_type_name;
-}
-
-
-void *visit_expression_type_c::visit(le_expression_c *symbol) {
-  symbol_c *left_type  = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-  compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible, symbol->l_exp, symbol->r_exp);
-  return &search_expression_type_c::bool_type_name;
-}
-
-
-void *visit_expression_type_c::visit(ge_expression_c *symbol) {
-  symbol_c *left_type  = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-  compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_ELEMENTARY_compatible, symbol->l_exp, symbol->r_exp);
-  return &search_expression_type_c::bool_type_name;
-}
-
-
-void *visit_expression_type_c::visit(add_expression_c *symbol) {
-  symbol_c *left_type  = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-
-/* The following is already checked in compute_expression */
-/*
-  if (is_type(left_type, time_type_name_c) && is_type(right_type, time_type_name_c)) 
-    return (void *)&time_type_name;
-*/
-
-  if (is_type(left_type, tod_type_name_c)      && is_type(right_type, time_type_name_c)) 
-    return (void *)&tod_type_name;
-  if (is_type(left_type, safetod_type_name_c)  && is_type(right_type, time_type_name_c)) 
-    return (void *)&tod_type_name;
-  if (is_type(left_type, tod_type_name_c)      && is_type(right_type, safetime_type_name_c)) 
-    return (void *)&tod_type_name;
-  if (is_type(left_type, safetod_type_name_c)  && is_type(right_type, safetime_type_name_c)) 
-    return (void *)&safetod_type_name;
-
-  if (is_type(left_type, dt_type_name_c)       && is_type(right_type, time_type_name_c)) 
-    return (void *)&dt_type_name;
-  if (is_type(left_type, safedt_type_name_c)   && is_type(right_type, time_type_name_c)) 
-    return (void *)&dt_type_name;
-  if (is_type(left_type, dt_type_name_c)       && is_type(right_type, safetime_type_name_c)) 
-    return (void *)&dt_type_name;
-  if (is_type(left_type, safedt_type_name_c)   && is_type(right_type, safetime_type_name_c)) 
-    return (void *)&safedt_type_name;
-
-  return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_MAGNITUDE_compatible, symbol->l_exp, symbol->r_exp);
-}
-
-
-void *visit_expression_type_c::visit(sub_expression_c *symbol) {
-  symbol_c *left_type  = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-
-/* The following is already checked in compute_expression */
-/*
-  if (is_type(left_type, time_type_name_c) && is_type(right_type, time_type_name_c))
-    return (void *)&time_type_name;
-*/
-
-  if (is_type(left_type, tod_type_name_c)     && is_type(right_type, time_type_name_c))
-    return (void *)&tod_type_name;
-  if (is_type(left_type, safetod_type_name_c) && is_type(right_type, time_type_name_c))
-    return (void *)&tod_type_name;
-  if (is_type(left_type, tod_type_name_c)     && is_type(right_type, safetime_type_name_c))
-    return (void *)&tod_type_name;
-  if (is_type(left_type, safetod_type_name_c) && is_type(right_type, safetime_type_name_c))
-    return (void *)&safetod_type_name;
-
-  if (is_type(left_type, dt_type_name_c)     && is_type(right_type, time_type_name_c))
-    return (void *)&dt_type_name;
-  if (is_type(left_type, safedt_type_name_c) && is_type(right_type, time_type_name_c))
-    return (void *)&dt_type_name;
-  if (is_type(left_type, dt_type_name_c)     && is_type(right_type, safetime_type_name_c))
-    return (void *)&dt_type_name;
-  if (is_type(left_type, safedt_type_name_c) && is_type(right_type, safetime_type_name_c))
-    return (void *)&safedt_type_name;
-
-  if (is_type(left_type, tod_type_name_c)     && is_type(right_type, tod_type_name_c))
-    return (void *)&time_type_name;
-  if (is_type(left_type, safetod_type_name_c) && is_type(right_type, tod_type_name_c))
-    return (void *)&time_type_name;
-  if (is_type(left_type, tod_type_name_c)     && is_type(right_type, safetod_type_name_c))
-    return (void *)&time_type_name;
-  if (is_type(left_type, safetod_type_name_c) && is_type(right_type, safetod_type_name_c))
-    return (void *)&safetime_type_name;
-
-  if (is_type(left_type, date_type_name_c)     && is_type(right_type, date_type_name_c))
-    return (void *)&time_type_name;
-  if (is_type(left_type, safedate_type_name_c) && is_type(right_type, date_type_name_c))
-    return (void *)&time_type_name;
-  if (is_type(left_type, date_type_name_c)     && is_type(right_type, safedate_type_name_c))
-    return (void *)&time_type_name;
-  if (is_type(left_type, safedate_type_name_c) && is_type(right_type, safedate_type_name_c))
-    return (void *)&safetime_type_name;
-
-  if (is_type(left_type, dt_type_name_c)     && is_type(right_type, dt_type_name_c))
-    return (void *)&time_type_name;
-  if (is_type(left_type, safedt_type_name_c) && is_type(right_type, dt_type_name_c))
-    return (void *)&time_type_name;
-  if (is_type(left_type, dt_type_name_c)     && is_type(right_type, safedt_type_name_c))
-    return (void *)&time_type_name;
-  if (is_type(left_type, safedt_type_name_c) && is_type(right_type, safedt_type_name_c))
-    return (void *)&safetime_type_name;
-
-  return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_MAGNITUDE_compatible, symbol->l_exp, symbol->r_exp);
-}
-
-
-void *visit_expression_type_c::visit(mul_expression_c *symbol) {
-  symbol_c *left_type  = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-
-  if (is_type(left_type, time_type_name_c)     && is_ANY_NUM_compatible(right_type)) 
-    return (void *)&time_type_name;
-  if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_type(right_type)) 
-    return (void *)&time_type_name;
-  if (is_type(left_type, safetime_type_name_c) && is_ANY_SAFENUM_type(right_type)) 
-    return (void *)&safetime_type_name;
-  /* Since we have already checked for ANY_NUM_type and ANY_SAFENUM_type in the previous lines,
-   * this next line is really only to check for integers/reals of undefined type on 'right_type'... 
-   */
-  if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_compatible(right_type)) 
-    return (void *)&safetime_type_name;
-
-  return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_NUM_compatible, symbol->l_exp, symbol->r_exp);
-}
-
-
-void *visit_expression_type_c::visit(div_expression_c *symbol) {
-  symbol_c *left_type  = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-
-  if (is_type(left_type, time_type_name_c)     && is_ANY_NUM_compatible(right_type)) 
-    return (void *)&time_type_name;
-  if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_type(right_type)) 
-    return (void *)&time_type_name;
-  if (is_type(left_type, safetime_type_name_c) && is_ANY_SAFENUM_type(right_type)) 
-    return (void *)&safetime_type_name;
-  /* Since we have already checked for ANY_NUM_type and ANY_SAFENUM_type in the previous lines,
-   * this next line is really only to check for integers/reals of undefined type on 'right_type'... 
-   */
-  if (is_type(left_type, safetime_type_name_c) && is_ANY_NUM_compatible(right_type)) 
-    return (void *)&safetime_type_name;
-
-  return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_NUM_compatible, symbol->l_exp, symbol->r_exp);
-}
-
-
-void *visit_expression_type_c::visit(mod_expression_c *symbol) {
-  symbol_c *left_type  = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-  return compute_expression(left_type, right_type, &visit_expression_type_c::is_ANY_INT_compatible, symbol->l_exp, symbol->r_exp);
-}
-
-
-void *visit_expression_type_c::visit(power_expression_c *symbol) {
-  symbol_c *left_type  = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-  if (!is_ANY_REAL_compatible(left_type))
-    STAGE3_ERROR(symbol->l_exp, symbol->l_exp, "first operand of ** operator has invalid data type, should be of type ANY_REAL.");
-  if (!is_ANY_NUM_compatible(right_type))
-    STAGE3_ERROR(symbol->r_exp, symbol->r_exp, "second operand of ** operator has invalid data type, should be of type ANY_NUM.");
-
-  return (void *)left_type;
-}
-
-
-void *visit_expression_type_c::visit(neg_expression_c *symbol) {
-  symbol_c *exp_type = base_type((symbol_c *)symbol->exp->accept(*this));
-  if (!is_ANY_MAGNITUDE_compatible(exp_type))
-    STAGE3_ERROR(symbol, symbol, "operand of negate expression '-' has invalid data type, should be of type ANY_MAGNITUDE.");
-
-  return exp_type;
-}
-
-
-void *visit_expression_type_c::visit(not_expression_c *symbol) {
-  symbol_c *type = base_type((symbol_c *)symbol->exp->accept(*this));
-  return compute_expression(type, type, &visit_expression_type_c::is_ANY_BIT_compatible, NULL, symbol->exp);
-}
-
-
-void *visit_expression_type_c::visit(function_invocation_c *symbol) {
-  function_symtable_t::iterator lower = function_symtable.lower_bound(symbol->function_name);
-  function_symtable_t::iterator upper = function_symtable.upper_bound(symbol->function_name);
-  if (lower == function_symtable.end()) ERROR;
-
-  symbol_c* return_data_type;
-  symbol_c* fdecl_return_type;
-  symbol->called_function_declaration = NULL;
-
-  function_symtable_t::iterator second = lower;
-  second++;
-  if (second == upper) {
-    /* call to a function that is not overloaded. */	  
-    /* now check the semantics of the function call... */
-    /* If the syntax parser is working correctly, exactly one of the 
-     * following two symbols will be NULL, while the other is != NULL.
-     */
-    function_declaration_c *f_decl = function_symtable.get_value(lower);
-    if (symbol->   formal_param_list != NULL) check_formal_call   (symbol, f_decl);
-    if (symbol->nonformal_param_list != NULL) check_nonformal_call(symbol, f_decl);
-    /* Store the pointer to the declaration of the function being called.
-     * This data will be used by stage 4 to call the correct function.
-     * Mostly needed to disambiguate overloaded functions...
-     * See comments in absyntax.def for more details
-     */
-    symbol->called_function_declaration = f_decl;
-    symbol->overloaded_return_type = NULL;
-    return base_type(f_decl->type_name);
-  }  
-
-  /* This is a call to an overloaded function... */
-  if (debug) printf("visit_expression_type_c::visit(function_invocation_c *symbol): FOUND CALL TO OVERLOADED FUNCTION!!\n");
-  for(; lower != upper; lower++) {
-    if (debug) printf("visit_expression_type_c::visit(function_invocation_c *symbol): FOUND CALL TO OVERLOADED FUNCTION!! iterating...\n");
-    int error_count = 0; 
-    function_declaration_c *f_decl = function_symtable.get_value(lower);
-    if (symbol->   formal_param_list != NULL) check_formal_call   (symbol, f_decl, &error_count);
-    if (symbol->nonformal_param_list != NULL) check_nonformal_call(symbol, f_decl, false, &error_count);
-    if (0 == error_count) {
-
-      fdecl_return_type = base_type(f_decl->type_name);
-
-      if (symbol->called_function_declaration == NULL) {
-        /* Store the pointer to the declaration of the function being called.
-         * This data will be used by stage 4 to call the correct function.
-         * Mostly needed to disambiguate overloaded functions...
-         * See comments in absyntax.def for more details
-         */
-        symbol->called_function_declaration = f_decl;
-        symbol->overloaded_return_type = NULL;
-
-        /* determine the base data type returned by the function being called... */
-        return_data_type = fdecl_return_type;
-      }
-      else if (typeid(*return_data_type) != typeid(*fdecl_return_type)){
-      	if (symbol->overloaded_return_type == NULL)
-      	  symbol->overloaded_return_type = overloaded_return_type(return_data_type);
-      	return_data_type = common_literal(return_data_type, fdecl_return_type);
-      }
-
-      if (NULL == return_data_type) ERROR;
-    }
-  }
-
-  if (return_data_type != NULL)
-	return return_data_type;
-
-  /* No compatible function was found for this function call */
-  STAGE3_ERROR(symbol, symbol, "Call to an overloaded function with invalid parameter type.");
-  return NULL;
-}
-
-/********************/
-/* B 3.2 Statements */
-/********************/
-// SYM_LIST(statement_list_c)
-/* The visitor of the base class search_visitor_c will handle calling each instruction in the list.
- * We do not need to do anything here...
- */
-// void *visit_expression_type_c::visit(statement_list_c *symbol)
-
-
-/*********************************/
-/* B 3.2.1 Assignment Statements */
-/*********************************/
-
-void *visit_expression_type_c::visit(assignment_statement_c *symbol) {
-  symbol_c *left_type = base_type((symbol_c *)symbol->l_exp->accept(*this));
-  symbol_c *right_type = base_type((symbol_c *)symbol->r_exp->accept(*this));
-
-  if (debug) {
-    printf("visit_expression_type_c::visit(assignment_statement_c) called. Checking --->");  
-    symbolic_variable_c *hi = dynamic_cast<symbolic_variable_c *>(symbol->l_exp);  
-    if (hi != NULL) {
-      identifier_c *hi1 = dynamic_cast<identifier_c *>(hi->var_name);  
-      if (hi1 != NULL) printf("%s", hi1->value);
-    }
-    printf(" := ");
-    hex_integer_c *hi2 = dynamic_cast<hex_integer_c *>(symbol->r_exp);  
-    if (hi2 != NULL) printf("%s", hi2->value);
-    printf("\n");
-  } // if (debug)
-
-  if        (NULL == left_type) {
-    STAGE3_ERROR(symbol->l_exp, symbol->l_exp, "Could not determine data type of expression (undefined variable, constant, or structure element?).\n");
-  } else if (NULL == right_type) {
-    STAGE3_ERROR(symbol->r_exp, symbol->r_exp, "Could not determine data type of expression (undefined variable, constant, or structure element?).\n");
-  } else if (!is_valid_assignment(left_type, right_type))
-    STAGE3_ERROR(symbol, symbol, "data type mismatch in assignment statement!\n");
-
-  return NULL;
-}
-
-
-
-/*****************************************/
-/* B 3.2.2 Subprogram Control Statements */
-/*****************************************/
-
-/*  RETURN */
-// SYM_REF0(return_statement_c)
-
-
-/* fb_name '(' [param_assignment_list] ')' */
-/* param_assignment_list -> may be NULL ! */
-// SYM_REF3(fb_invocation_c, fb_name, formal_param_list, nonformal_param_list)
-void *visit_expression_type_c::visit(fb_invocation_c *symbol) {
-  symbol_c *fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name);
-    /* The following should never occur. The function block must be defined, 
-     * and the FB type being called MUST be in the symtable... 
-     * This was all already checked at stage 2!
-     */
-  if (NULL == fb_decl) ERROR;
-
-  /* now check the semantics of the fb call... */
-  /* If the syntax parser is working correctly, exactly one of the 
-   * following two symbols will be NULL, while the other is != NULL.
-   */
-  if (symbol->   formal_param_list != NULL) check_formal_call   (symbol, fb_decl);
-  if (symbol->nonformal_param_list != NULL) check_nonformal_call(symbol, fb_decl);
-
-  return NULL;
-}
-
-
-#if 0
-/* helper symbol for fb_invocation */
-/* param_assignment_list ',' param_assignment */
-SYM_LIST(param_assignment_list_c)
-
-/*  variable_name ASSIGN expression */
-SYM_REF2(input_variable_param_assignment_c, variable_name, expression)
-
-/* [NOT] variable_name '=>' variable */
-SYM_REF3(output_variable_param_assignment_c, not_param, variable_name, variable)
-
-/* helper CLASS for output_variable_param_assignment */
-SYM_REF0(not_paramassign_c)
-#endif
-
-/********************************/
-/* B 3.2.3 Selection Statements */
-/********************************/
-
-/* IF expression THEN statement_list elseif_statement_list ELSE statement_list END_IF */
-// SYM_REF4(if_statement_c, expression, statement_list, elseif_statement_list, else_statement_list)
-void *visit_expression_type_c::visit(if_statement_c *symbol) {
-  symbol_c *expr_type = base_type((symbol_c*)symbol->expression->accept(*this));
-  if (!is_BOOL_type(expr_type)) STAGE3_ERROR(symbol->expression,symbol->expression,"IF conditional expression is not of boolean type.");
-  if (NULL != symbol->statement_list)
-    symbol->statement_list->accept(*this); 
-  if (NULL != symbol->elseif_statement_list)  
-    symbol->elseif_statement_list->accept(*this);
-  if (NULL != symbol->else_statement_list)  
-    symbol->else_statement_list->accept(*this);  
-  return NULL;
-}
-
-/* helper symbol for if_statement */
-// SYM_LIST(elseif_statement_list_c)
-// void *visit_expression_type_c::visit(elseif_statement_list_c *symbol) { }
-
-/* helper symbol for elseif_statement_list */
-/* ELSIF expression THEN statement_list    */
-// SYM_REF2(elseif_statement_c, expression, statement_list)
-void *visit_expression_type_c::visit(elseif_statement_c *symbol) {
-  symbol_c *elseif_expr_type = base_type((symbol_c*)symbol->expression->accept(*this));
-  if(!is_BOOL_type(elseif_expr_type)) STAGE3_ERROR(symbol->expression,symbol->expression,"ELSIF conditional expression is not of boolean type.");
-  if (NULL != symbol->statement_list)
-    symbol->statement_list->accept(*this); 
-  return NULL;
-}
-
-
-/* CASE expression OF case_element_list ELSE statement_list END_CASE */
-// SYM_REF3(case_statement_c, expression, case_element_list, statement_list)
-void *visit_expression_type_c::visit(case_statement_c *symbol) {
-  case_expression_type = base_type((symbol_c*)symbol->expression->accept(*this));
-  if (NULL != case_expression_type) {
-    if (NULL != symbol->case_element_list)
-      symbol->case_element_list->accept(*this);
-  }
-  if (NULL != symbol->statement_list)
-    symbol->statement_list->accept(*this);
-  return NULL;
-}
-
-#if 0
-/* helper symbol for case_statement */
-// SYM_LIST(case_element_list_c)
-// void *visit_expression_type_c::visit(case_element_list_c *symbol);
-
-/*  case_list ':' statement_list */
-// SYM_REF2(case_element_c, case_list, statement_list)
-void *visit_expression_type_c::visit(case_element_c *symbol);  
-#endif
-
-// SYM_LIST(case_list_c)
-void *visit_expression_type_c::visit(case_list_c *symbol) {
-  symbol_c *element_type;
-  for(int i = 0; i < symbol->n; i++) {
-    element_type = (symbol_c *)symbol->elements[i]->accept(*this);
-    if (NULL == element_type) {
-      STAGE3_ERROR(symbol->elements[i], symbol->elements[i], "Case list element has undefined data type.");
-    } else {
-      element_type = base_type(element_type);
-      if (NULL != element_type){
-        /* The CASE value is only used for comparison (and not assingment), so we only check for compatibility! */ 
-        if (!is_compatible_type(case_expression_type, element_type))
-          STAGE3_ERROR(symbol->elements[i], symbol->elements[i], "Invalid data type of case list element.");
-      }
-    }
-  }
-  return NULL;
-}
-
-/********************************/
-/* B 3.2.4 Iteration Statements */
-/********************************/
-
-/*  FOR control_variable ASSIGN expression TO expression [BY expression] DO statement_list END_FOR */
-// SYM_REF5(for_statement_c, control_variable, beg_expression, end_expression, by_expression, statement_list)
-void *visit_expression_type_c::visit(for_statement_c *symbol) {
-  symbol_c *var_type = (symbol_c*)symbol->control_variable->accept(*this);
-  if (NULL == var_type) ERROR;
-  var_type = base_type(var_type);
-  if (NULL == var_type) ERROR;
-  // ASSIGN
-  symbol_c *beg_expr_type = base_type((symbol_c*)symbol->beg_expression->accept(*this));
-  if (NULL != beg_expr_type) {
-    /* The BEG value is assigned to the variable, so we check for assignment validity! */ 
-    if(!is_valid_assignment(var_type, beg_expr_type)) 
-      STAGE3_ERROR(symbol->beg_expression, symbol->beg_expression, "Data type mismatch between control variable and initial value.");
-  }
-  // TO
-  symbol_c *end_expr_type = base_type((symbol_c*)symbol->end_expression->accept(*this));
-  if (NULL != end_expr_type) { 
-    /* The TO value is only used for comparison, so we only check for compatibility! */ 
-    if(!is_compatible_type(var_type, end_expr_type)) 
-      STAGE3_ERROR(symbol->end_expression, symbol->end_expression, "Data type mismatch between control variable and final value.");
-  }
-  // BY
-  if(symbol->by_expression != NULL) {
-    symbol_c *by_expr_type = base_type((symbol_c*)symbol->by_expression->accept(*this));
-    if (NULL != end_expr_type) {   
-      /* The BY value is used in an expression (add, sub, ...), so we only check for compatibility! */ 
-      if(!is_compatible_type(var_type, by_expr_type)) 
-        STAGE3_ERROR(symbol->by_expression, symbol->by_expression, "Data type mismatch between control variable and BY value.");
-    }
-  }
-  // DO
-  if (NULL != symbol->statement_list)
-    symbol->statement_list->accept(*this); 
-  return NULL;
-}
-
-
-/*  WHILE expression DO statement_list END_WHILE */
-// SYM_REF2(while_statement_c, expression, statement_list)
-void *visit_expression_type_c::visit(while_statement_c *symbol) {
-  symbol_c *expr_type = base_type((symbol_c*)symbol->expression->accept(*this));
-  if (NULL != expr_type) {
-    if(!is_BOOL_type(expr_type)) 
-      STAGE3_ERROR(symbol->expression,symbol->expression,"WHILE conditional expression is not of boolean type.");
-  }
- 
-  if (NULL != symbol->statement_list)
-    symbol->statement_list->accept(*this); 
-  return NULL;
-}
-
-/*  REPEAT statement_list UNTIL expression END_REPEAT */
-// SYM_REF2(repeat_statement_c, statement_list, expression)
-void *visit_expression_type_c::visit(repeat_statement_c *symbol) {
-  if (NULL != symbol->statement_list)
-    symbol->statement_list->accept(*this); 
- 
-  symbol_c *expr_type = base_type((symbol_c*)symbol->expression->accept(*this));
-  if (NULL != expr_type) {
-    if(!is_BOOL_type(expr_type)) 
-      STAGE3_ERROR(symbol->expression,symbol->expression,"REPEAT conditional expression is not of boolean type.");
-  }
-  return NULL;
-}
-
-/*  EXIT */
-// SYM_REF0(exit_statement_c)
-
-
-
--- a/stage3/visit_expression_type.hh	Tue Feb 21 22:31:38 2012 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,393 +0,0 @@
-/*
- *  matiec - a compiler for the programming languages defined in IEC 61131-3
- *
- *  Copyright (C) 2009-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)
- *
- */
-
-/* Verify whether the semantic rules of data type compatibility are being followed.
- *
- * For example:
- */
-
-#include "../absyntax_utils/absyntax_utils.hh"
-
-class visit_expression_type_c: public search_constant_type_c {
-
-  private:
-    search_varfb_instance_type_c *search_varfb_instance_type;
-    search_base_type_c search_base_type;
-
-    /* When calling a function block, we must first find it's type,
-     * by searching through the declarations of the variables currently
-     * in scope.
-     * This class does just that...
-     * A new bject instance is instantiated whenever we start checking semantics
-     * for a function block type declaration, or a program declaration.
-     * This object instance will then later be called while the
-     * function block's or the program's body is being handled.
-     *
-     * Note that functions cannot contain calls to function blocks,
-     * so we do not create an object instance when handling
-     * a function declaration.
-     */
-//     search_var_instance_decl_c *search_var_instance_decl;
-    
-     /* This variable was created to pass information from
-      * visit_expression_type_c::visit(case_statement_c *symbol) function to
-      * visit_expression_type_c::visit(case_list_c *symbol) function.
-      */
-      symbol_c *case_expression_type;
-  
-    /* In IL code, once we find a type mismatch error, it is best to
-     * ignore any further errors until the end of the logicl operation,
-     * i.e. until the next LD.
-     * However, we cannot clear the il_error flag on all LD operations,
-     * as these may also be used within parenthesis. LD operations
-     * within parenthesis may not clear the error flag.
-     * We therefore need a counter to know how deep inside a parenthesis 
-     * structure we are.
-     */
-    int  il_parenthesis_level;
-    bool il_error;
-    bool error_found;
-
-    /* the current data type of the data stored in the IL stack, i.e. the default variable */
-    symbol_c *il_default_variable_type;
-    /* the current IL operand being analysed - its symbol and its data type */
-    symbol_c *il_operand_type;
-    symbol_c *il_operand;
-
-
-  public:
-    visit_expression_type_c(symbol_c *ignore);
-    virtual ~visit_expression_type_c(void);
-
-    bool get_error_found(void);
-
-    typedef struct {
-      symbol_c *value;
-      symbol_c *type;
-    } value_and_type_t; 
-
-    /* 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_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_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_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_nonneg_literal_integer_type (symbol_c *type_symbol);
-    bool is_literal_integer_type        (symbol_c *type_symbol);
-    bool is_literal_real_type           (symbol_c *type_symbol);
-    bool is_literal_bool_type           (symbol_c *type_symbol);
-
-    bool is_ANY_ELEMENTARY_OR_ENUMERATED_compatible (symbol_c *type_symbol);
-
-    /* Determine the common data type between two data types.
-     * If no common data type found, return NULL.
-     *
-     * If data types are identical, return the first (any would do...).
-     * If any of the datat types is a literal, we confirm that 
-     *   the literal uses less bits than the fixed size data type.
-     *   e.g. BYTE and 1024 returns NULL
-     *        BYTE and 255  returns BYTE
-     *
-     * If two literals, then return the literal that requires more bits...
-     */
-    symbol_c *common_type__(symbol_c *first_type, symbol_c *second_type);
-    /* Determine the common data type between two data types.
-     * Unlike the common_type__() function, we stop the compiler with an ERROR
-     *  if no common data type is found.
-     */
-    symbol_c *common_type(symbol_c *first_type, symbol_c *second_type);
-
-    symbol_c *common_literal(symbol_c *first_type, symbol_c *second_type);
-    symbol_c *overloaded_return_type(symbol_c *type);
-
-/* Return TRUE if the second (value) data type may be assigned to a variable of the first (variable) data type
- * such as: 
- *     var_type     value_type
- *    BOOL           BYTE#7     -> returns false
- *    INT            INT#7      -> returns true
- *    INT            7          -> returns true
- *    REAL           7.89       -> returns true
- *    REAL           7          -> returns true
- *    INT            7.89       -> returns false
- *    SAFEBOOL       BOOL#1     -> returns false   !!!
- *   etc...
- *
- * NOTE: It is assumed that the var_type is the data type of an lvalue
- */
-    bool is_valid_assignment(symbol_c *var_type, symbol_c *value_type);
-
-/* Return TRUE if there is a common data type, otherwise return FALSE
- * i.e., return TRUE if both data types may be used simultaneously in an expression
- * such as:
- *    BOOL#0     AND BYTE#7  -> returns false
- *    0          AND BYTE#7  -> returns true
- *    INT#10     AND INT#7   -> returns true
- *    INT#10     AND 7       -> returns true
- *    REAL#34.3  AND 7.89    -> returns true
- *    REAL#34.3  AND 7       -> returns true
- *    INT#10     AND 7.89    -> returns false
- *    SAFEBOOL#0 AND BOOL#1  -> returns true   !!!
- *   etc...
- */
-    bool is_compatible_type(symbol_c *first_type, symbol_c *second_type);
-
-    /* check semantics of FB call in the IL language using input operators */
-    /* e.g. CU, CLK, IN, PT, SR, ...                                       */
-    void check_il_fbcall(symbol_c *symbol, const char *input_operator);
-    /* check the semantics of a FB or Function non-formal call */
-    /* e.g. foo(1, 2, 3, 4);  */
-    /* If error_count pointer is NULL, print out error messages.
-     * If error_count pointer is != NULL, do not print out error messages, but tally up
-     * how many errors were found.
-     */
-    void check_nonformal_call(symbol_c *f_call, symbol_c *f_decl, bool use_il_defvar = false, int *error_count = NULL);
-    /* check the semantics of a FB or Function formal call */
-    /* e.g. foo(IN1 := 1, OUT1 =>x, EN := true);  */
-    /* If error_count pointer is NULL, print out error messages.
-     * If error_count pointer is != NULL, do not print out error messages, but tally up
-     * how many errors were found.
-     */
-    void check_formal_call(symbol_c *f_call, symbol_c *f_decl, int *error_count = NULL);
-
-
-    void *compute_standard_function_default(function_invocation_c *st_symbol, il_formal_funct_call_c *il_symbol);
-    void *compute_standard_function_il(il_function_call_c *symbol, symbol_c *param_data_type);
-
-
-    /* A helper function... */
-    typedef bool (visit_expression_type_c::*is_data_type_t)(symbol_c *type_symbol);  /* a pointer to a function! */
-//    symbol_c *compute_boolean_expression(symbol_c *left_exp, symbol_c *right_exp, is_data_type_t is_data_type);
-//    symbol_c *compute_numeric_expression(symbol_c *left_exp, symbol_c *right_exp, is_data_type_t is_data_type);
-//    symbol_c *compute_expression(symbol_c *left_exp, symbol_c *right_exp, is_data_type_t is_data_type);
-    symbol_c *compute_expression(symbol_c *left_type, symbol_c *right_type, is_data_type_t is_data_type,
-                                 symbol_c *left_expr, symbol_c *right_expr);
-
-
-    /* a helper function... */
-    symbol_c *base_type(symbol_c *symbol);
-
-    /* a helper function... */
-    void *verify_null(symbol_c *symbol);
-    
-    /********************************/
-    /* B 1.3.3 - Derived data types */
-    /********************************/
-    void *visit(data_type_declaration_c *symbol);
-
-    /*********************/
-    /* B 1.4 - Variables */
-    /*********************/
-    void *visit(symbolic_variable_c *symbol);
-
-    /********************************************/
-    /* B 1.4.1 - Directly Represented Variables */
-    /********************************************/
-    void *visit(direct_variable_c *symbol);
-
-    /*************************************/
-    /* B 1.4.2 - Multi-element variables */
-    /*************************************/
- 
-    void *visit(array_variable_c *symbol);
-    void *visit(structured_variable_c *symbol);
-
-    /********************************/
-    /* B 1.7 Configuration elements */
-    /********************************/
-    void *visit(configuration_declaration_c *symbol);
-
-/****************************************/
-    /* B.2 - Language IL (Instruction List) */
-    /****************************************/
-    /***********************************/
-    /* B 2.1 Instructions and Operands */
-    /***********************************/
-    // void *visit(instruction_list_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_jump_operation_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_param_list_c *symbol);
-    void *visit(il_param_assignment_c *symbol);
-    void *visit(il_param_out_assignment_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);
-
-    /*********************************/
-    /* B 3.2.1 Assignment Statements */
-    /*********************************/
-    void *visit(assignment_statement_c *symbol);
-
-    /*****************************************/
-    /* B 3.2.2 Subprogram Control Statements */
-    /*****************************************/
-    void *visit(fb_invocation_c *symbol);
-
-    /********************************/
-    /* B 3.2.3 Selection Statements */
-    /********************************/
- 
-    void *visit(if_statement_c *symbol);    
-//     void *visit(elseif_statement_list_c *symbol);
-    void *visit(elseif_statement_c *symbol);
-    void *visit(case_statement_c *symbol);
-//     void *visit(case_element_list_c *symbol);
-//     void *visit(case_element_c *symbol);   
-   void *visit(case_list_c *symbol);
-    
-    /********************************/
-    /* B 3.2.4 Iteration Statements */
-    /********************************/
-    
-    void *visit(for_statement_c *symbol);
-    void *visit(while_statement_c *symbol);
-    void *visit(repeat_statement_c *symbol);
-    
-
-//TODO: delete this functions. Why are they needed?
-void *visit(program_declaration_c *symbol);
-void *visit(function_declaration_c *symbol);
-void *visit(function_block_declaration_c *symbol);
-
-}; // visit_expression_type_c
-
--- a/stage4/generate_c/generate_c.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/stage4/generate_c/generate_c.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -182,7 +182,6 @@
 class print_function_parameter_data_types_c: public generate_c_base_c {
   private:
     symbol_c *current_type;
-    symbol_c *return_type;
     bool_type_name_c tmp_bool;
 
     void print_list(symbol_c *var_list, symbol_c *data_type) { 
@@ -198,11 +197,9 @@
     }
     
   public:
-    print_function_parameter_data_types_c(stage4out_c *s4o_ptr, symbol_c* return_type):
-      generate_c_base_c(s4o_ptr) {
-    	current_type = NULL;
-    	this->return_type = return_type;
-      }
+    print_function_parameter_data_types_c(stage4out_c *s4o_ptr): 
+      generate_c_base_c(s4o_ptr)
+      {current_type = NULL;}
 
     /**************************************/
     /* B.1.5 - Program organization units */
@@ -213,11 +210,7 @@
     /*   FUNCTION derived_function_name ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */
     /* | FUNCTION derived_function_name ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */
     void *visit(function_declaration_c *symbol) {
-      /* return type */
-      if (this->return_type == NULL)
-    	symbol->type_name->accept(*this);
-      else
-    	this->return_type->accept(*this);
+      symbol->type_name->accept(*this); /* return type */
       symbol->var_declarations_list->accept(*this);
       return NULL;
     }
@@ -2231,10 +2224,10 @@
           if (var_decl == NULL)
             ERROR;
           else
-            vartype = search_config_instance->get_vartype();
+            vartype = search_config_instance->get_vartype(current_var_reference);
         }
         else
-          vartype = search_resource_instance->get_vartype();
+          vartype = search_resource_instance->get_vartype(current_var_reference);
         
         s4o.print(s4o.indent_spaces + "{extern ");
         var_decl->accept(*this);
@@ -2266,10 +2259,10 @@
           if (var_decl == NULL)
             ERROR;
           else
-            vartype = search_config_instance->get_vartype();
+            vartype = search_config_instance->get_vartype(current_var_reference);
         }
         else
-          vartype = search_resource_instance->get_vartype();
+          vartype = search_resource_instance->get_vartype(current_var_reference);
         
         s4o.print(s4o.indent_spaces + "{extern ");
         var_decl->accept(*this);
--- a/stage4/generate_c/generate_c_il.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/stage4/generate_c/generate_c_il.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -968,7 +968,7 @@
     if (fdecl_mutiplicity == 2) {
       /* function being called is overloaded! */
       s4o.print("__");
-      print_function_parameter_data_types_c overloaded_func_suf(&s4o, symbol->overloaded_return_type);
+      print_function_parameter_data_types_c overloaded_func_suf(&s4o);
       f_decl->accept(overloaded_func_suf);
     }
     s4o.print_integer(fcall_number);
@@ -979,7 +979,7 @@
           if (fdecl_mutiplicity == 2) {
             /* function being called is overloaded! */
             s4o.print("__");
-            print_function_parameter_data_types_c overloaded_func_suf(&s4o, symbol->overloaded_return_type);
+            print_function_parameter_data_types_c overloaded_func_suf(&s4o);
             f_decl->accept(overloaded_func_suf);
           }
     }	  
@@ -1376,7 +1376,7 @@
     if (fdecl_mutiplicity == 2) {
       /* function being called is overloaded! */
       s4o.print("__");
-      print_function_parameter_data_types_c overloaded_func_suf(&s4o, symbol->overloaded_return_type);
+      print_function_parameter_data_types_c overloaded_func_suf(&s4o);
       f_decl->accept(overloaded_func_suf);
     }
     s4o.print_integer(fcall_number);
@@ -1387,7 +1387,7 @@
       if (fdecl_mutiplicity == 2) {
         /* function being called is overloaded! */
         s4o.print("__");
-        print_function_parameter_data_types_c overloaded_func_suf(&s4o, symbol->overloaded_return_type);
+        print_function_parameter_data_types_c overloaded_func_suf(&s4o);
         f_decl->accept(overloaded_func_suf);
       }
     }  
@@ -1562,6 +1562,12 @@
   return NULL;
 }
 
+// SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;)
+void *visit(il_simple_instruction_c *symbol)	{
+  return symbol->il_simple_instruction->accept(*this);
+}
+
+
 /* | il_initial_param_list il_param_instruction */
 // SYM_LIST(il_param_list_c)
 void *visit(il_param_list_c *symbol) {ERROR; return NULL;} // should never get called!
@@ -1640,6 +1646,12 @@
 }
 
 void *visit(NOT_operator_c *symbol)	{
+  /* 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!
+   *       The error is caught in stage 3!
+   */  
   if ((NULL != this->current_operand) || (NULL != this->current_operand_type)) ERROR;
   XXX_operator(&(this->default_variable_name),
                search_expression_type->is_bool_type(this->default_variable_name.current_type)?" = !":" = ~",
--- a/stage4/generate_c/generate_c_inlinefcall.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/stage4/generate_c/generate_c_inlinefcall.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -169,7 +169,7 @@
       if (f_decl != NULL) {
         /* function being called is overloaded! */
         s4o.print("__");
-        print_function_parameter_data_types_c overloaded_func_suf(&s4o, function_type_prefix);
+        print_function_parameter_data_types_c overloaded_func_suf(&s4o);
         f_decl->accept(overloaded_func_suf);
       }	
       if (function_type_suffix) {
@@ -222,7 +222,7 @@
       if (f_decl != NULL) {
     	/* function being called is overloaded! */
     	s4o.print("__");
-        print_function_parameter_data_types_c overloaded_func_suf(&s4o, function_type_prefix);
+        print_function_parameter_data_types_c overloaded_func_suf(&s4o);
         f_decl->accept(overloaded_func_suf);
       }
 
@@ -492,10 +492,7 @@
       
       /* determine the base data type returned by the function being called... */
       search_base_type_c search_base_type;
-      if (symbol->overloaded_return_type == NULL)
-        function_type_prefix = (symbol_c *)f_decl->type_name->accept(search_base_type);
-      else
-    	function_type_prefix = symbol->overloaded_return_type;
+      function_type_prefix = (symbol_c *)f_decl->type_name->accept(search_base_type);
       
       function_name = symbol->function_name;      
       
@@ -678,10 +675,7 @@
 
       /* determine the base data type returned by the function being called... */
       search_base_type_c search_base_type;
-      if (symbol->overloaded_return_type == NULL)
-		function_type_prefix = (symbol_c *)f_decl->type_name->accept(search_base_type);
-      else
-		function_type_prefix = symbol->overloaded_return_type;
+      function_type_prefix = (symbol_c *)f_decl->type_name->accept(search_base_type);
       if (NULL == function_type_prefix) ERROR;
       
       function_name = symbol->function_name;
@@ -832,6 +826,11 @@
 	  this->default_variable_back_name.current_type = this->default_variable_name.current_type;
 	  return NULL;
     }
+    
+    // SYM_REF1(il_simple_instruction_c, il_simple_instruction, symbol_c *prev_il_instruction;)
+    void *visit(il_simple_instruction_c *symbol)	{
+      return symbol->il_simple_instruction->accept(*this);
+    }
 
     void *visit(LD_operator_c *symbol)	{
       /* the data type resulting from this operation... */
@@ -1050,10 +1049,7 @@
 
       /* determine the base data type returned by the function being called... */
       search_base_type_c search_base_type;
-      if (symbol->overloaded_return_type == NULL)
-        function_type_prefix = (symbol_c *)f_decl->type_name->accept(search_base_type);
-      else
-        function_type_prefix = symbol->overloaded_return_type;
+      function_type_prefix = (symbol_c *)f_decl->type_name->accept(search_base_type);
       if (NULL == function_type_prefix) ERROR;
 
       /* loop through each function parameter, find the value we should pass
--- a/stage4/generate_c/generate_c_sfc.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/stage4/generate_c/generate_c_sfc.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -844,7 +844,7 @@
         for(pt = variable_list.begin(); pt != variable_list.end(); pt++) {
           symbol_c *var_decl = search_var_instance_decl->get_decl(pt->symbol);
           if (var_decl != NULL) {
-            unsigned int vartype = search_var_instance_decl->get_vartype();
+            unsigned int vartype = search_var_instance_decl->get_vartype(pt->symbol);
 
             s4o.print(s4o.indent_spaces);
             if (vartype == search_var_instance_decl_c::external_vt)
--- a/stage4/generate_c/generate_c_st.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/stage4/generate_c/generate_c_st.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -347,7 +347,7 @@
     case complextype_suffix_vg:
       symbol->subscripted_variable->accept(*this);
 
-      current_array_type = search_varfb_instance_type->get_type_id(symbol->subscripted_variable);
+      current_array_type = search_varfb_instance_type->get_basetype_decl(symbol->subscripted_variable);
       if (current_array_type == NULL) ERROR;
 
       s4o.print(".table");
@@ -361,7 +361,7 @@
       if (this->is_variable_prefix_null()) {
     	symbol->subscripted_variable->accept(*this);
 
-    	current_array_type = search_varfb_instance_type->get_type_id(symbol->subscripted_variable);
+    	current_array_type = search_varfb_instance_type->get_basetype_decl(symbol->subscripted_variable);
     	if (current_array_type == NULL) ERROR;
 
     	s4o.print(".table");
@@ -782,7 +782,7 @@
     if (fdecl_mutiplicity == 2) {
       /* function being called is overloaded! */
       s4o.print("__");
-      print_function_parameter_data_types_c overloaded_func_suf(&s4o, symbol->overloaded_return_type);
+      print_function_parameter_data_types_c overloaded_func_suf(&s4o);
       f_decl->accept(overloaded_func_suf);
     }
     s4o.print_integer(fcall_number);
@@ -792,7 +792,7 @@
     if (fdecl_mutiplicity == 2) {
       /* function being called is overloaded! */
       s4o.print("__");
-      print_function_parameter_data_types_c overloaded_func_suf(&s4o, symbol->overloaded_return_type);
+      print_function_parameter_data_types_c overloaded_func_suf(&s4o);
       f_decl->accept(overloaded_func_suf);
     }
   }
--- a/stage4/generate_iec/generate_iec.cc	Tue Feb 21 22:31:38 2012 +0100
+++ b/stage4/generate_iec/generate_iec.cc	Sat Mar 31 15:36:08 2012 +0100
@@ -58,6 +58,10 @@
 
 
 
+#define ERROR error_exit(__FILE__,__LINE__)
+/* function defined in main.cc */
+extern void error_exit(const char *file_name, int line_no);
+
 
 
 
@@ -153,6 +157,13 @@
 #endif
 
 
+/* 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)
+void *visit(invalid_type_name_c *symbol) {
+  ERROR;
+  return NULL;
+}
 
 
 /******************/
@@ -1670,6 +1681,17 @@
   return print_list(symbol,  s4o.indent_spaces, "\n" + s4o.indent_spaces, "\n");
 }
 
+
+/* il_simple_instruction:
+ *   il_simple_operation eol_list
+ * | il_expression eol_list
+ * | il_formal_funct_call eol_list
+ */
+void *visit(il_simple_instruction_c *symbol)	{
+  return symbol->il_simple_instruction->accept(*this);
+}
+
+
 /* | il_initial_param_list il_param_instruction */
 void *visit(il_param_list_c *symbol) {
 // return print_list(symbol);