Merge
authorEdouard Tisserant
Wed, 19 Feb 2014 22:27:11 +0100
changeset 870 9c6c588fd708
parent 822 a7d9e0b8636b (current diff)
parent 869 d88f47549408 (diff)
child 871 878e9bf4c6ec
Merge
stage1_2/iec_bison.yy
stage1_2/iec_flex.ll
stage1_2/stage1_2.cc
stage1_2/stage1_2_priv.hh
--- a/absyntax/absyntax.def	Wed Feb 19 22:25:10 2014 +0100
+++ b/absyntax/absyntax.def	Wed Feb 19 22:27:11 2014 +0100
@@ -862,6 +862,10 @@
 /* enumvalue_symtable is filled in by enum_declaration_check_c, during stage3 semantic verification, with a list of all enumerated constants declared inside this POU */
 SYM_REF5(configuration_declaration_c, configuration_name, global_var_declarations, resource_declarations, access_declarations, instance_specific_initializations, enumvalue_symtable_t enumvalue_symtable;)
 
+/* intermediate helper symbol for configuration_declaration  */
+/*  { global_var_declarations_list }   */
+SYM_LIST(global_var_declarations_list_c)
+
 /* helper symbol for configuration_declaration */
 SYM_LIST(resource_declaration_list_c)
 
--- a/absyntax_utils/array_dimension_iterator.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/absyntax_utils/array_dimension_iterator.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -82,12 +82,19 @@
  */
 array_dimension_iterator_c::array_dimension_iterator_c(symbol_c *symbol) {
   /* do some consistency check... */
-  array_specification_c* array_spec = dynamic_cast<array_specification_c*>(symbol);
-
-  if (NULL == array_spec) ERROR;
+  /* NOTE: We comment out the consistency check so the compiler does not bork when it encounters buggy source code.
+   *        e.g. Code that handles a non array variable as an array!
+   *               VAR  v1, v2: int; END_VAR
+   *               v1 := v2[33, 45];
+   *       The above error will be caught by the datatype checking algorithms!
+   */
+  array_spec_init_c    * array_spec_init = dynamic_cast<array_spec_init_c    *>(symbol); 
+  if (NULL != array_spec_init)    symbol = array_spec_init->array_specification;
+  array_specification_c* array_spec      = dynamic_cast<array_specification_c*>(symbol);
+  // if (NULL == array_spec) ERROR;
 
   /* OK. Now initialize this object... */
-  this->array_specification = symbol;
+  this->array_specification = array_spec; // Set to array_spec and not symbol => will be NULL if not an array_specification_c* !!
   reset();
 }
 
@@ -101,9 +108,9 @@
  * Returns the subrange symbol!
  */
 subrange_c *array_dimension_iterator_c::next(void) {
+  if (NULL == array_specification) return NULL; /* The source code probably has a bug which will be caught somewhere else! */
   void *res = array_specification->accept(*this);
-  if (res == NULL) 
-    return NULL;
+  if (NULL == res)                 return NULL;
 
   return current_array_dimension;
 }
--- a/absyntax_utils/decompose_var_instance_name.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/absyntax_utils/decompose_var_instance_name.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -52,24 +52,31 @@
   next_variable_name = NULL;
   current_recursive_variable_name = NULL;
   previously_returned_variable_name = NULL;
+  current_array_subscript_list = NULL;
 }
 
-symbol_c *decompose_var_instance_name_c::next_part(bool increment) {
+/* Get the next element in the strcutured variable */
+symbol_c *decompose_var_instance_name_c::get_next() {
   /* We must always start from the top!
    * See note in the structured_variable_c visitor
    * to understand why...
    */
+  current_array_subscript_list = NULL;
   symbol_c *res = (symbol_c *)variable_name->accept(*this);
-  if (increment)
-    next_variable_name = current_recursive_variable_name;
+  next_variable_name = current_recursive_variable_name;
 
   if (previously_returned_variable_name == res)
-	  return NULL;
-  if (increment)
-    previously_returned_variable_name = res;
+    return NULL;
+  
+  previously_returned_variable_name = res;
   return res;
 }
 
+/* If the current element in the structured variable is an array, return its subscript_list, 
+ * otherwise return NULL
+ */
+list_c *decompose_var_instance_name_c::get_current_arraysubs_list(void) {return current_array_subscript_list;}
+
 /*************************/
 /* B.1 - Common elements */
 /*************************/
@@ -95,8 +102,14 @@
 /*  subscripted_variable '[' subscript_list ']' */
 // SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
 void *decompose_var_instance_name_c::visit(array_variable_c *symbol) {
-  /* NOTE: the subscripted_variable may itself be a structure!,
-   * so we must recursevily visit!
+  if (NULL == symbol->subscript_list) ERROR; // array may not have an empty subscript list!
+  current_array_subscript_list = dynamic_cast<list_c *>(symbol->subscript_list);
+  if (NULL == current_array_subscript_list) ERROR; // if it does not point to a subscript_list_c, then the abstract syntax tree has been changed, and this code needs to be fixed accordingly!
+  
+  /* NOTE: the subscripted_variable may itself be a structure or an array!, so we must recursevily visit! */
+  /* the next line will call either:
+   *   - visit(structured_variable_c *) or visit(array_variable_c *), if the array variable is itself an element of another array os structure
+   *   - visit(symbolic_variable_c *) if it is a simple array variable
    */
   return symbol->subscripted_variable->accept(*this);
 }
@@ -131,8 +144,13 @@
     return (void *)symbol->field_selector->accept(*this);
   }
 
+  current_array_subscript_list = NULL;
   current_recursive_variable_name = symbol;
-  return symbol->record_variable->accept(*this);
+  /* the next line will call either:
+   *   - visit(structured_variable_c *) or visit(array_variable_c *), if the record variable has more elements to visit
+   *   - visit(symbolic_variable_c *) if it is the last element in the record variable
+   */
+  return symbol->record_variable->accept(*this); 
 }
 
 /********************************/
--- a/absyntax_utils/decompose_var_instance_name.hh	Wed Feb 19 22:25:10 2014 +0100
+++ b/absyntax_utils/decompose_var_instance_name.hh	Wed Feb 19 22:27:11 2014 +0100
@@ -74,11 +74,14 @@
     symbol_c *next_variable_name;
     symbol_c *current_recursive_variable_name;
     symbol_c *previously_returned_variable_name;
+    list_c   *current_array_subscript_list;
 
   public:
     decompose_var_instance_name_c(symbol_c *variable_instance_name);
-
-    symbol_c *next_part(bool increment = true);
+    /* Get the next element in the strcutured variable */
+    symbol_c *get_next(void);
+    /* If the current element in the structured variable is an array, return its subscript_list, otherwise return NULL */
+    list_c *get_current_arraysubs_list(void);
 
   private:
   /*************************/
--- a/absyntax_utils/function_call_param_iterator.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/absyntax_utils/function_call_param_iterator.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -464,12 +464,13 @@
 void *function_call_param_iterator_c::visit(il_param_assignment_c *symbol) {
   TRACE("il_param_assignment_c");
 
-  // TODO : We do not yet handle a instruction list passed as parameter !!!
-  // since we do not yet support it, it is best to simply stop than to fail silently...
-  if (NULL != symbol->simple_instr_list) ERROR;
+  symbol_c *expression = NULL;
+  if (!((NULL != symbol->simple_instr_list) ^ (NULL != symbol->il_operand))) ERROR;
+  if    (NULL != symbol->simple_instr_list) expression = symbol->simple_instr_list;
+  if    (NULL != symbol->il_operand       ) expression = symbol->il_operand;
 
   current_assign_direction = assign_in;
-  return handle_parameter_assignment((symbol_c *)symbol->il_assign_operator->accept(*this), symbol->il_operand);
+  return handle_parameter_assignment((symbol_c *)symbol->il_assign_operator->accept(*this), expression);
 }
 
 /*  il_assign_out_operator variable */
--- a/absyntax_utils/get_datatype_info.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/absyntax_utils/get_datatype_info.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -260,6 +260,7 @@
 
 bool get_datatype_info_c::is_sfc_initstep(symbol_c *type_symbol) {
   symbol_c *type_decl = search_base_type_c::get_basetype_decl(type_symbol); 
+  if (NULL == type_decl)                                             {return false;}
   if (typeid(*type_decl) == typeid(initial_step_c))                  {return true;}   /* INITIAL_STEP step_name ':' action_association_list END_STEP */  /* A pseudo data type! */
   return false;
 }
@@ -270,6 +271,7 @@
 
 bool get_datatype_info_c::is_sfc_step(symbol_c *type_symbol) {
   symbol_c *type_decl = search_base_type_c::get_basetype_decl(type_symbol); 
+  if (NULL == type_decl)                                             {return false;}
   if (typeid(*type_decl) == typeid(initial_step_c))                  {return true;}   /* INITIAL_STEP step_name ':' action_association_list END_STEP */  /* A pseudo data type! */
   if (typeid(*type_decl) == typeid(        step_c))                  {return true;}   /*         STEP step_name ':' action_association_list END_STEP */  /* A pseudo data type! */
   return false;
@@ -280,6 +282,7 @@
 
 bool get_datatype_info_c::is_function_block(symbol_c *type_symbol) {
   symbol_c *type_decl = search_base_type_c::get_basetype_decl(type_symbol); 
+  if (NULL == type_decl)                                             {return false;}
   if (typeid(*type_decl) == typeid(function_block_declaration_c))    {return true;}   /*  FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
   return false;
 }
@@ -289,7 +292,8 @@
 
 
 bool get_datatype_info_c::is_subrange(symbol_c *type_symbol) {
-  symbol_c *type_decl = search_base_type_c::get_basetype_decl(type_symbol); /* NOTE: will work correctly once we update the way search_base_type_c works, by adding a new search_effective_type:c */
+  symbol_c *type_decl = search_base_type_c::get_equivtype_decl(type_symbol); /* NOTE: do NOT call search_base_type_c !! */
+  if (NULL == type_decl)                                             {return false;}
   
   if (typeid(*type_decl) == typeid(subrange_type_declaration_c))     {return true;}   /*  subrange_type_name ':' subrange_spec_init */
   if (typeid(*type_decl) == typeid(subrange_spec_init_c))            {return true;}   /* subrange_specification ASSIGN signed_integer */
@@ -305,6 +309,7 @@
 
 bool get_datatype_info_c::is_enumerated(symbol_c *type_symbol) {
   symbol_c *type_decl = search_base_type_c::get_basetype_decl(type_symbol);
+  if (NULL == type_decl)                                             {return false;}
   
   if (typeid(*type_decl) == typeid(enumerated_type_declaration_c))   {return true;}   /*  enumerated_type_name ':' enumerated_spec_init */
   if (typeid(*type_decl) == typeid(enumerated_spec_init_c))          {return true;}   /* enumerated_specification ASSIGN enumerated_value */
@@ -320,6 +325,7 @@
 
 bool get_datatype_info_c::is_array(symbol_c *type_symbol) {
   symbol_c *type_decl = search_base_type_c::get_basetype_decl(type_symbol);
+  if (NULL == type_decl)                                             {return false;}
   
   if (typeid(*type_decl) == typeid(array_type_declaration_c))        {return true;}   /*  identifier ':' array_spec_init */
   if (typeid(*type_decl) == typeid(array_spec_init_c))               {return true;}   /* array_specification [ASSIGN array_initialization} */
@@ -337,6 +343,7 @@
 
 bool get_datatype_info_c::is_structure(symbol_c *type_symbol) {
   symbol_c *type_decl = search_base_type_c::get_basetype_decl(type_symbol);
+  if (NULL == type_decl)                                                       {return false;}
   
   if (typeid(*type_decl) == typeid(structure_type_declaration_c))              {return true;}   /*  structure_type_name ':' structure_specification */
   if (typeid(*type_decl) == typeid(initialized_structure_c))                   {return true;}   /* structure_type_name ASSIGN structure_initialization */
--- a/absyntax_utils/search_base_type.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/absyntax_utils/search_base_type.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -54,7 +54,7 @@
 
 
 
-search_base_type_c::search_base_type_c(void) {current_type_name = NULL; current_basetype = NULL;}
+search_base_type_c::search_base_type_c(void) {current_basetype_name = NULL; current_basetype = NULL; current_equivtype = NULL;}
 
 /* static method! */
 void search_base_type_c::create_singleton(void) {
@@ -63,11 +63,25 @@
 }
 
 /* static method! */
+symbol_c *search_base_type_c::get_equivtype_decl(symbol_c *symbol) {
+  create_singleton();
+  if (NULL == symbol)    return NULL; 
+  search_base_type_singleton->current_basetype_name = NULL;
+  search_base_type_singleton->current_basetype  = NULL; 
+  search_base_type_singleton->current_equivtype = NULL; 
+  symbol_c *basetype = (symbol_c *)symbol->accept(*search_base_type_singleton);
+  if (NULL != search_base_type_singleton->current_equivtype)
+    return search_base_type_singleton->current_equivtype;
+  return basetype;
+}
+
+/* static method! */
 symbol_c *search_base_type_c::get_basetype_decl(symbol_c *symbol) {
   create_singleton();
   if (NULL == symbol)    return NULL; 
-  search_base_type_singleton->current_type_name = NULL;
+  search_base_type_singleton->current_basetype_name = NULL;
   search_base_type_singleton->current_basetype  = NULL; 
+  search_base_type_singleton->current_equivtype = NULL; 
   return (symbol_c *)symbol->accept(*search_base_type_singleton);
 }
 
@@ -75,39 +89,14 @@
 symbol_c *search_base_type_c::get_basetype_id  (symbol_c *symbol) {
   create_singleton();
   if (NULL == symbol)    return NULL; 
-  search_base_type_singleton->current_type_name = NULL;
+  search_base_type_singleton->current_basetype_name = NULL;
   search_base_type_singleton->current_basetype  = NULL; 
+  search_base_type_singleton->current_equivtype = NULL; 
   symbol->accept(*search_base_type_singleton);
-  return (symbol_c *)search_base_type_singleton->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!
- */
-/* static method! */
-bool search_base_type_c::type_is_subrange(symbol_c* type_decl) {
-  create_singleton();
-  search_base_type_singleton->is_subrange = false;
-  type_decl->accept(*search_base_type_singleton);
-  return search_base_type_singleton->is_subrange;
-}
-
-
-/* static method! */
-bool search_base_type_c::type_is_enumerated(symbol_c* type_decl) {
-  create_singleton();
-  search_base_type_singleton->is_enumerated = false;
-  type_decl->accept(*search_base_type_singleton);
-  return search_base_type_singleton->is_enumerated;
-}
-
-bool search_base_type_c::type_is_fb(symbol_c* type_decl) {
-  create_singleton();
-  search_base_type_singleton->is_fb = false;
-  type_decl->accept(*search_base_type_singleton);
-  return search_base_type_singleton->is_fb;
-}
+  return (symbol_c *)search_base_type_singleton->current_basetype_name;
+}
+
+
 
 /*************************/
 /* B.1 - Common elements */
@@ -119,7 +108,7 @@
 void *search_base_type_c::visit(identifier_c *type_name) {
   symbol_c *type_decl;
 
-  this->current_type_name = type_name;
+  this->current_basetype_name = type_name;
   /* if we have reached this point, it is because the current_basetype is not yet pointing to the base datatype we are looking for,
    * so we will be searching for the delcaration of the type named in type_name, which might be the base datatype (we search recursively!)
    */
@@ -236,17 +225,21 @@
 
 /*  subrange_type_name ':' subrange_spec_init */
 void *search_base_type_c::visit(subrange_type_declaration_c *symbol) {
+  this->current_equivtype = symbol;
   return symbol->subrange_spec_init->accept(*this);
 }
 
 /* subrange_specification ASSIGN signed_integer */
 void *search_base_type_c::visit(subrange_spec_init_c *symbol) {
-  this->is_subrange = true;
+  if (NULL == this->current_equivtype)
+    this->current_equivtype = symbol;
   return symbol->subrange_specification->accept(*this);
 }
 
 /*  integer_type_name '(' subrange')' */
 void *search_base_type_c::visit(subrange_specification_c *symbol) {
+  if (NULL == this->current_equivtype)
+    this->current_equivtype = symbol;
   return symbol->integer_type_name->accept(*this);
 }
 
@@ -255,7 +248,7 @@
 
 /*  enumerated_type_name ':' enumerated_spec_init */
 void *search_base_type_c::visit(enumerated_type_declaration_c *symbol) {
-  this->current_type_name = symbol->enumerated_type_name;
+  this->current_basetype_name = symbol->enumerated_type_name;
   /* NOTE: We want search_base_type_c to return a enumerated_type_declaration_c as the base datatpe if possible
    *       (i.e. if it is a named datatype declared inside a TYPE ... END_TYPE declarations, as opposed to an
    *        anonymous datatype declared in a VAR ... AND_VAR declaration).
@@ -268,7 +261,6 @@
 
 /* enumerated_specification ASSIGN enumerated_value */
 void *search_base_type_c::visit(enumerated_spec_init_c *symbol) {
-  this->is_enumerated = true;
   // current_basetype may have been set in the previous enumerated_type_declaration_c visitor, in which case we do not want to overwrite the value!
   if (NULL == this->current_basetype)
     this->current_basetype  = symbol; 
@@ -282,7 +274,6 @@
 /* helper symbol for enumerated_specification->enumerated_spec_init */
 /* enumerated_value_list ',' enumerated_value */
 void *search_base_type_c::visit(enumerated_value_list_c *symbol) {
-  this->is_enumerated = true;
   // current_basetype may have been set in the previous enumerated_type_declaration_c or enumerated_spec_init_c visitors, in which case we do not want to overwrite the value!
   if (NULL == this->current_basetype) 
     this->current_basetype  = symbol; 
@@ -295,7 +286,7 @@
 
 /*  identifier ':' array_spec_init */
 void *search_base_type_c::visit(array_type_declaration_c *symbol) {
-  this->current_type_name = symbol->identifier;
+  this->current_basetype_name = symbol->identifier;
   return symbol->array_spec_init->accept(*this);
 }
 
@@ -332,7 +323,7 @@
  *       structure_element_declaration_list_c
  */
 void *search_base_type_c::visit(structure_type_declaration_c *symbol)  {
-  this->current_type_name = symbol->structure_type_name;
+  this->current_basetype_name = symbol->structure_type_name;
   return symbol->structure_specification->accept(*this);
 }
 
@@ -388,7 +379,6 @@
 /*  FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
 // SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body)
 void *search_base_type_c::visit(function_block_declaration_c *symbol)                   {
-	this->is_fb = true;
 	return (void *)symbol;
 }
 
@@ -400,14 +390,14 @@
 /* INITIAL_STEP step_name ':' action_association_list END_STEP */
 // SYM_REF2(initial_step_c, step_name, action_association_list)
 void *search_base_type_c::visit(initial_step_c *symbol) {
-  this->current_type_name = NULL; /* this pseudo data type does not have a type name! */
+  this->current_basetype_name = NULL; /* this pseudo data type does not have a type name! */
   return (void *)symbol;
 }
 
 /* STEP step_name ':' action_association_list END_STEP */
 // SYM_REF2(step_c, step_name, action_association_list)
 void *search_base_type_c::visit(step_c *symbol) {
-  this->current_type_name = NULL; /* this pseudo data type does not have a type name! */
+  this->current_basetype_name = NULL; /* this pseudo data type does not have a type name! */
   return (void *)symbol;
 }
 
--- a/absyntax_utils/search_base_type.hh	Wed Feb 19 22:25:10 2014 +0100
+++ b/absyntax_utils/search_base_type.hh	Wed Feb 19 22:27:11 2014 +0100
@@ -31,19 +31,35 @@
  */
 
 
-/* Determine the data type on which another data type is based on.
- * If a new default initial value is given, we DO NOT consider it a
- * new base class, and continue looking further!
- *
- * E.g. TYPE new_int_t : INT; END_TYPE;
- *      TYPE new_int2_t : INT = 2; END_TYPE;
- *      TYPE new_subr_t : INT (4..5); END_TYPE;
- *
- *    new_int_t is really an INT!!
- *    new_int2_t is also really an INT!!
- *    new_subr_t is also really an INT!!
- *
- * Note that a FB declaration is also considered a base type, as
+/* Determine the data type on which another data type is based on. */
+
+/*
+ * What is a Base Type?
+ *    A base type is the fundamental data type from which the type is derived.
+ *    The main idea is that if two datatyes (A and B) share a common base type, 
+ *    then these two datatypes may be used interchangeably in an expression.
+ * 
+ * What is an Equivalent Type? 
+ *    An equivalent type is the data type from which the type is derived.
+ *    The Base type and the Equivalent type will always be the same, with the
+ *    exception of subranges!
+ *
+ * E.g. TYPE new_int_t  : INT; END_TYPE;
+ *      TYPE new_int2_t : INT := 2; END_TYPE;
+ *      TYPE new_int3_t : new_int2_t := 3; END_TYPE;
+ *      TYPE new_sub_t  : INT (4..10); END_TYPE;
+ *      TYPE new_sub2_t : new_sub_t  := 5 ; END_TYPE;
+ *      TYPE new_sub3_t : new_sub2_t := 6 ; END_TYPE;
+ *      TYPE new_sub4_t : new_int3_t (4..10); END_TYPE;    <-----  This is NOT legal syntax!
+ *
+ *    new_int_t   : base type->INT          equivalent type->INT
+ *    new_int2_t  : base type->INT          equivalent type->INT
+ *    new_int3_t  : base type->INT          equivalent type->INT
+ *    new_sub_t   : base type->INT          equivalent type->new_sub_t
+ *    new_sub2_t  : base type->INT          equivalent type->new_sub_t
+ *    new_sub3_t  : base type->INT          equivalent type->new_sub_t
+ *
+ * Note too that a FB declaration is also considered a base type, as
  * we may have FB instances declared of a specific FB type.
  */
 
@@ -51,12 +67,9 @@
 class search_base_type_c: public null_visitor_c {
 
   private:
-    symbol_c *current_type_name;
+    symbol_c *current_basetype_name;
     symbol_c *current_basetype;
-    bool is_array;
-    bool is_subrange;
-    bool is_enumerated;
-    bool is_fb;
+    symbol_c *current_equivtype;
     static search_base_type_c *search_base_type_singleton; // Make this a singleton class!
     
   private:  
@@ -64,11 +77,9 @@
 
   public:
     search_base_type_c(void);
-    static symbol_c *get_basetype_decl (symbol_c *symbol);
-    static symbol_c *get_basetype_id   (symbol_c *symbol);
-    static bool      type_is_subrange  (symbol_c *type_decl);
-    static bool      type_is_enumerated(symbol_c *type_decl);
-    static bool      type_is_fb        (symbol_c *type_decl);
+    static symbol_c *get_equivtype_decl(symbol_c *symbol);  /* get the Equivalent Type declaration */
+    static symbol_c *get_basetype_decl (symbol_c *symbol);  /* get the Base       Type declaration */
+    static symbol_c *get_basetype_id   (symbol_c *symbol);  /* get the Base       Type identifier  */
 
   public:
   /*************************/
--- a/absyntax_utils/search_var_instance_decl.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/absyntax_utils/search_var_instance_decl.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -129,36 +129,6 @@
 
 
 
-/* This is a temporary fix. Hopefully, once I clean up stage4 code, and I change the way
- * we generate C code, this function will no longer be needed!
- */
-#include <typeinfo>  /* required for typeid() */
-bool search_var_instance_decl_c::type_is_complex(symbol_c *symbol) {
-  symbol_c *decl;
-  
-  decl = this->get_decl(symbol);
-  if (NULL == decl) ERROR;
-  decl = search_base_type_c::get_basetype_decl(decl);
-  if (NULL == decl) ERROR;
-  
-  return ((typeid( *(decl) ) == typeid( array_specification_c                )) ||
-//        (typeid( *(decl) ) == typeid( array_spec_init_c                    )) ||  /* does not seem to be necessary */
-          (typeid( *(decl) ) == typeid( structure_type_declaration_c         )) ||  
-          (typeid( *(decl) ) == typeid( structure_element_declaration_list_c )) ||
-//        (typeid( *(decl) ) == typeid( structure_type_declaration_c         )) ||  /* does not seem to be necessary */
-          (typeid( *(decl) ) == typeid( initialized_structure_c              )) ||
-          (search_base_type_c::type_is_fb(decl) && current_vartype == external_vt)
-         );
-}
-
-bool search_var_instance_decl_c::type_is_fb(symbol_c *symbol) {
-    symbol_c *decl;
-    search_base_type_c search_base_type;
-
-    decl = this->get_decl(symbol);
-    if (NULL == decl) ERROR;
-    return search_base_type.type_is_fb(decl);
-}
 
 /***************************/
 /* B 0 - Programming Model */
--- a/absyntax_utils/search_var_instance_decl.hh	Wed Feb 19 22:25:10 2014 +0100
+++ b/absyntax_utils/search_var_instance_decl.hh	Wed Feb 19 22:27:11 2014 +0100
@@ -134,14 +134,6 @@
     vt_t         get_vartype(symbol_c *variable_instance_name);
     opt_t        get_option (symbol_c *variable_instance_name);
 
-    /* NOTE: The following function will be completely deleted in the (hopefully near) future. */
-    /* Returns true if the variable is an ARRAY or a STRUCT, otherwise returns false.
-     * Note that for FB, also returns false!
-     */
-    bool type_is_complex(symbol_c *variable_name);
-
-    bool type_is_fb(symbol_c *symbol);
-    
   private:
     symbol_c *search_scope;
     symbol_c *search_name;
--- a/absyntax_utils/search_varfb_instance_type.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/absyntax_utils/search_varfb_instance_type.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -209,7 +209,8 @@
  * structure_type_declaration_c, but for now, let's leave it in...
  */
 void *search_varfb_instance_type_c::visit(structure_type_declaration_c *symbol) {
-  if (NULL == current_field_selector) ERROR;
+  if (NULL == current_field_selector) return NULL; // the source code has a datatype consistency bug that will be caught later!!
+  
   symbol->structure_specification->accept(*this);
   return NULL;
   /* NOTE: structure_specification will point to either a
@@ -228,7 +229,7 @@
  * initialized_structure_c, but for now, let's leave it in...
  */
 void *search_varfb_instance_type_c::visit(initialized_structure_c *symbol)	{
-  if (NULL != current_field_selector) ERROR;
+  if (NULL == current_field_selector) return NULL; // the source code has a datatype consistency bug that will be caught later!!
   
   /* recursively find out the data type of current_field_selector... */
   symbol->structure_type_name->accept(*this);
@@ -239,7 +240,7 @@
 /* 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_field_selector) ERROR;
+  if (NULL == current_field_selector) return NULL; // the source code has a datatype consistency bug that will be caught later!!
 
   /* now search the structure declaration */
   for(int i = 0; i < symbol->n; i++) {
@@ -251,7 +252,7 @@
 
 /*  structure_element_name ':' spec_init */
 void *search_varfb_instance_type_c::visit(structure_element_declaration_c *symbol) {
-  if (NULL == current_field_selector) ERROR;
+  if (NULL == current_field_selector) return NULL; // the source code has a datatype consistency bug that will be caught later!!
 
   if (compare_identifiers(symbol->structure_element_name, current_field_selector) == 0) {
     /* found the type of the element we were looking for! */
@@ -357,7 +358,7 @@
 /*  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) {
-  if (NULL == current_field_selector) ERROR;
+  if (NULL == current_field_selector) return NULL; // the source code has a datatype consistency bug that will be caught later!!
 
   /* now search the function block declaration for the variable... */
   /* If not found, these pointers will all be set to NULL!! */
@@ -378,7 +379,7 @@
 // SYM_REF2(initial_step_c, step_name, action_association_list)
 /* NOTE: this method may be called from visit(structured_variable_c *symbol) method| */
 void *search_varfb_instance_type_c::visit(initial_step_c *symbol) {
-  if (NULL == current_field_selector) ERROR;
+  if (NULL == current_field_selector) return NULL; // the source code has a datatype consistency bug that will be caught later!!
 
   identifier_c T("T");
   identifier_c X("X");
--- a/absyntax_utils/type_initial_value.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/absyntax_utils/type_initial_value.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -220,6 +220,8 @@
 /* helper symbol for enumerated_specification->enumerated_spec_init */
 /* enumerated_value_list ',' enumerated_value */
 void *type_initial_value_c::visit(enumerated_value_list_c *symbol) {
+  /* stage1_2 never creates an enumerated_value_list_c with no entries. If this occurs, then something must have changed! */
+  if (symbol->n <= 0) ERROR;
  /* if no initial value explicitly given, then use the lowest value of the subrange */
   return (void *)symbol->elements[0];
 }
--- a/main.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/main.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -120,8 +120,9 @@
       /* Part 1: Concepts and Function Blocks,              */
       /* Version 1.0 is Official Release                    */
       /******************************************************/
-  printf("  s : allow use of safe extensions\n");
-  printf("  c : create conversion functions\n");
+  printf("  s : allow use of safe extensions (e.g. SAFExxx data types))\n");
+  printf("  n : allow use of nested comments\n");
+  printf("  c : create conversion functions for enumerated data types\n");
   printf("\n");
   printf("%s - Copyright (C) 2003-2011 \n"
          "This program comes with ABSOLUTELY NO WARRANTY!\n"
@@ -133,15 +134,21 @@
 int main(int argc, char **argv) {
   symbol_c *tree_root;
   char * builddir = NULL;
-  stage1_2_options_t stage1_2_options = {false, false, NULL};
+  stage1_2_options_t stage1_2_options;
   int optres, errflg = 0;
   int path_len;
 
+  /* Default values for the command line options... */
+  stage1_2_options.safe_extensions      = false; /* allow use of SAFExxx datatypes */
+  stage1_2_options.full_token_loc       = false; /* error messages specify full token location */
+  stage1_2_options.conversion_functions = false; /* Create a conversion function for derived datatype */
+  stage1_2_options.nested_comments      = false; /* Allow the use of nested comments. */
+  stage1_2_options.includedir           = NULL;  /* Include directory, where included files will be searched for... */
 
   /******************************************/
   /*   Parse command line options...        */
   /******************************************/
-  while ((optres = getopt(argc, argv, ":hvfscI:T:")) != -1) {
+  while ((optres = getopt(argc, argv, ":nhvfscI:T:")) != -1) {
     switch(optres) {
     case 'h':
       printusage(argv[0]);
@@ -164,6 +171,10 @@
       stage1_2_options.conversion_functions = true;
       break;
 
+    case 'n':
+      stage1_2_options.nested_comments = true;
+      break;
+
     case 'I':
       /* NOTE: To improve the usability under windows:
        *       We delete last char's path if it ends with "\".
--- a/stage1_2/iec_bison.yy	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage1_2/iec_bison.yy	Wed Feb 19 22:27:11 2014 +0100
@@ -276,7 +276,7 @@
     long int    last_order;
 } YYLTYPE;
 #define YYLTYPE_IS_DECLARED 1
-#define YYLTYPE_IS_TRIVIAL 1
+#define YYLTYPE_IS_TRIVIAL 0
 #endif
 
 }
@@ -1046,7 +1046,7 @@
 //  - configuration_declaration
 //  - resource_declaration
 //
-%type  <leaf>	optional_global_var_declarations
+%type  <list>	global_var_declarations_list
 // helper symbol for configuration_declaration
 %type  <leaf>	optional_access_declarations
 // helper symbol for configuration_declaration
@@ -5563,7 +5563,7 @@
 
 configuration_declaration:
   CONFIGURATION configuration_name
-   optional_global_var_declarations
+   global_var_declarations_list
    single_resource_declaration
    {variable_name_symtable.pop();
     direct_variable_symtable.pop();}
@@ -5576,7 +5576,7 @@
 	 direct_variable_symtable.pop();
 	}
 | CONFIGURATION configuration_name
-   optional_global_var_declarations
+   global_var_declarations_list
    resource_declaration_list
    optional_access_declarations
    optional_instance_specific_initializations
@@ -5588,7 +5588,7 @@
 }
 /* ERROR_CHECK_BEGIN */
 | CONFIGURATION 
-   optional_global_var_declarations
+   global_var_declarations_list
    single_resource_declaration
    {variable_name_symtable.pop();
     direct_variable_symtable.pop();}
@@ -5597,14 +5597,14 @@
   END_CONFIGURATION
   {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no configuration name defined in configuration declaration."); yynerrs++;}
 | CONFIGURATION
-   optional_global_var_declarations
+   global_var_declarations_list
    resource_declaration_list
    optional_access_declarations
    optional_instance_specific_initializations
   END_CONFIGURATION
   {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no configuration name defined in configuration declaration."); yynerrs++;}
 | CONFIGURATION error
-   optional_global_var_declarations
+   global_var_declarations_list
    single_resource_declaration
    {variable_name_symtable.pop();
     direct_variable_symtable.pop();}
@@ -5613,27 +5613,27 @@
   END_CONFIGURATION
   {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid configuration name defined in configuration declaration."); yyerrok;}
 | CONFIGURATION error
-   optional_global_var_declarations
+   global_var_declarations_list
    resource_declaration_list
    optional_access_declarations
    optional_instance_specific_initializations
   END_CONFIGURATION
   {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid configuration name defined in configuration declaration."); yyerrok;}
 | CONFIGURATION configuration_name
-   optional_global_var_declarations
+   global_var_declarations_list
    optional_access_declarations
    optional_instance_specific_initializations
   END_CONFIGURATION
   {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no resource(s) defined in configuration declaration."); yynerrs++;}
 | CONFIGURATION configuration_name
-   optional_global_var_declarations
+   global_var_declarations_list
    error
    optional_access_declarations
    optional_instance_specific_initializations
   END_CONFIGURATION
   {$$ = NULL; print_err_msg(locf(@4), locl(@4), "invalid resource(s) defined in configuration declaration."); yyerrok;}
 /*| CONFIGURATION configuration_name
-   optional_global_var_declarations
+   global_var_declarations_list
    single_resource_declaration
    {variable_name_symtable.pop();
     direct_variable_symtable.pop();}
@@ -5642,7 +5642,7 @@
   END_OF_INPUT
   {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed configuration declaration."); yyerrok;}*/
 | CONFIGURATION configuration_name
-   optional_global_var_declarations
+   global_var_declarations_list
    resource_declaration_list
    optional_access_declarations
    optional_instance_specific_initializations
@@ -5657,12 +5657,30 @@
 //  - configuration_declaration
 //  - resource_declaration
 //
-optional_global_var_declarations:
+/* NOTE: The IEC 61131-3 v2 standard defines this list as being: [global_var_declarations]
+ *        e.g.:
+ *          'CONFIGURATION' configuration_name  [global_var_declarations] ...
+ *
+ *       However, this means that a single VAR_GLOBAL ... END_VAR construct is allowed
+ *       in each CONFIGURATION or RESOURCE declaration. If the user wishes to have global
+ *       variables with distinct properties (e.g. some with RETAIN, others with CONSTANT,
+ *       and yet other variables with none of these qualifiers), the syntax defined in the 
+ *       standard does not allow this.
+ *       Amazingly, IEC 61131-3 v3 also does not seem to allow it either!!
+ *       Since this is most likely a bug in the standard, we are changing the syntax slightly
+ *       to become:
+ *          'CONFIGURATION' configuration_name  {global_var_declarations} ...
+ *
+ *       Remember that:
+ *          {S}, closure, meaning zero or more concatenations of S.
+ *          [S], option, meaning zero or one occurrence of S.
+ */
+global_var_declarations_list:
   // empty
-	{$$ = NULL;}
-| global_var_declarations
-;
-
+	{$$ = new global_var_declarations_list_c(locloc(@$));}
+| global_var_declarations_list global_var_declarations
+	{$$ = $1; $$->add_element($2);}
+;
 
 // helper symbol for configuration_declaration //
 optional_access_declarations:
@@ -5693,7 +5711,7 @@
 
 resource_declaration:
   RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} resource_name {variable_name_symtable.insert($3, prev_declared_resource_name_token);} ON resource_type_name
-   optional_global_var_declarations
+   global_var_declarations_list
    single_resource_declaration
   END_RESOURCE
 	{$$ = new resource_declaration_c($3, $6, $7, $8, locloc(@$));
@@ -5703,12 +5721,12 @@
 	}
 /* ERROR_CHECK_BEGIN */
 | RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} ON resource_type_name
-   optional_global_var_declarations
+   global_var_declarations_list
    single_resource_declaration
   END_RESOURCE
   {$$ = NULL; print_err_msg(locl(@1), locf(@3), "no resource name defined in resource declaration."); yynerrs++;}
 /*|	RESOURCE {variable_name_symtable.push();direct_variable_symtable.push();} resource_name ON resource_type_name
-   optional_global_var_declarations
+   global_var_declarations_list
    single_resource_declaration
   END_OF_INPUT
 	{$$ = NULL; print_err_msg(locf(@1), locl(@5), "unclosed resource declaration."); yyerrok;}*/
--- a/stage1_2/iec_flex.ll	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage1_2/iec_flex.ll	Wed Feb 19 22:27:11 2014 +0100
@@ -5,7 +5,7 @@
  *
  *  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
+ *  the Free Software Foundation, either version 3 of thest_whitespaceLicense, or
  *  (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
@@ -356,50 +356,90 @@
  *       Unfortunately, flex will join '_' and '4h' to create a legal {identifier} '_4h',
  *       and return that identifier instead! So, we added this state!
  *
- * The state machine has 7 possible states (INITIAL, config, decl, body, st, il, sfc)
+ * There is a main state machine...
+ * 
+ *       +---> INITIAL <-------> config
+ *       |        \
+ *       |        V
+ *       |   header_state
+ *       |        |
+ *       |        V
+ *     vardecl_list_state <------> var_decl
+ *       ^        | 
+ *       |        | [using push()]
+ *       |        |
+ *       |        V
+ *       |       body, 
+ *       |        |
+ *       |        | 
+ *       |   -------------------
+ *       |   |       |         |
+ *       |   v       v         v
+ *       |  st      il        sfc
+ *       |   |       |         |  [using pop() when leaving st/il/sfc => goes to vardecl_list_state]
+ *       |   |       |         |
+ *       -----------------------
+ *
+ * NOTE:- When inside sfc, and an action or transition in ST/IL is found, then 
+ *        we also push() to the body state. This means that sometimes, when pop()ing
+ *        from st and il, the state machine may return to the sfc state!
+ *      - The transitions form sfc to body will be decided by bison, which will
+ *        tell flex to do the transition by calling cmd_goto_body_state().
+ *   
+ * 
  * Possible state changes are:
- *   INITIAL -> goto(decl_state)
- *               (when a FUNCTION, FUNCTION_BLOCK, or PROGRAM is found,
- *                and followed by a VAR declaration)
- *   INITIAL -> goto(body_state) 
- *                (when a FUNCTION, FUNCTION_BLOCK, or PROGRAM is found,
- *                 and _not_ followed by a VAR declaration)
- *                (This transition is actually commented out, since the syntax
- *                 does not allow the declaration of functions, FBs, or programs
- *                 without any VAR declaration!)
  *   INITIAL -> goto(config_state)
  *                (when a CONFIGURATION is found)
- *   decl_state    -> push(decl_state); goto(body_state)
- *                     (when the last END_VAR is found, i.e. the function body starts)
- *   decl_state    -> push(decl_state); goto(sfc_state)
+ * 
+ *   INITIAL -> goto(header_state)
+ *               (when a FUNCTION, FUNCTION_BLOCK, or PROGRAM is found)
+ *   header_state -> goto(vardecl_list_state)
+ *               (When the first VAR token is found, i.e. at begining of first VAR .. END_VAR declaration)
+ * 
+ *  vardecl_list_state -> push current state (vardecl_list_state), and goto(vardecl_state) 
+ *                (when a VAR token is found)
+ *   vardecl_state -> pop() to (vardecl_list_state) 
+ *                (when a END_VAR token is found)
+ * 
+ *   vardecl_list_state -> push current state (vardecl_list_state), and goto(body_state) 
+ *                (when the last END_VAR is found!)
+ *
+ *   body_state    -> goto(sfc_state)
  *                     (when it figures out it is parsing sfc language)
  *   body_state    -> goto(st_state)
  *                     (when it figures out it is parsing st language)
  *   body_state    -> goto(il_state)
  *                     (when it figures out it is parsing il language)
- *   st_state      -> pop()
+ *   st_state      -> pop() to vardecl_list_state
  *                     (when a END_FUNCTION, END_FUNCTION_BLOCK, END_PROGRAM,
  *                      END_ACTION or END_TRANSITION is found)
- *   il_state      -> pop()
+ *   il_state      -> pop() to vardecl_list_state
  *                     (when a END_FUNCTION, END_FUNCTION_BLOCK, END_PROGRAM,
  *                      END_ACTION or END_TRANSITION is found)
- *   decl_state    -> goto(INITIAL)
+ *   sfc_state     -> pop() to vardecl_list_state
  *                     (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found)
- *   sfc_state     -> goto(INITIAL)
+ * 
+ *   vardecl_list_state -> goto(INITIAL)
  *                     (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found)
  *   config_state  -> goto(INITIAL)
  *                     (when a END_CONFIGURATION is found)
- *   sfc_state     -> push(sfc_state); goto(body_state)
+ * 
+ *  
+ *   sfc_state     -> push current state(sfc_state); goto(body_state)
  *                     (when parsing an action. This transition is requested by bison)
- *   sfc_state     -> push(sfc_state); goto(sfc_qualifier_state)
+ *   sfc_state     -> push current state(sfc_state); goto(sfc_qualifier_state)
  *                     (when expecting an action qualifier. This transition is requested by bison)
- *   sfc_qualifier_state -> pop()
+ *   sfc_qualifier_state -> pop() to sfc_state
  *                     (when no longer expecting an action qualifier. This transition is requested by bison)
+ *
  *   config_state  -> push(config_state); goto(task_init_state)
  *                     (when parsing a task initialisation. This transition is requested by bison)
  *   task_init_state -> pop()
  *                     (when no longer parsing task initialisation parameters. This transition is requested by bison)
  *
+ * 
+ * There is another secondary state machine for parsing comments, another for file_includes, 
+ * and yet another for time literals.
  */
 
 
@@ -413,10 +453,16 @@
  */
 %s task_init_state
 
-/* we are parsing a function, program or function block declaration */
-%s decl_state
-
-/* we will be parsing a function body. Whether il/st/sfc remains to be determined */
+/* we are looking for the first VAR inside a function's, program's or function block's declaration */
+/* This is not exclusive (%x) as we must be able to parse the identifier and data types of a function/FB */
+%s header_state
+
+/* we are parsing a function, program or function block sequence of VAR..END_VAR delcarations */
+%x vardecl_list_state 
+/* a substate of the vardecl_list_state: we are inside a specific VAR .. END_VAR */
+%s vardecl_state
+
+/* we will be parsing a function body/action/transition. Whether il/st/sfc remains to be determined */
 %x body_state
 
 /* we are parsing il code -> flex must return the EOL tokens!       */
@@ -437,6 +483,9 @@
 /* we are parsing a TIME# literal. We must not return any {identifier} tokens. */
 %x time_literal_state
 
+/* we are parsing a comment. */
+%x comment_state
+
 
 /*******************/
 /* File #include's */
@@ -455,8 +504,8 @@
 
 
 file_include_pragma_filename	[^\"]*
-file_include_pragma_beg		"{#include"{st_whitespace_only}\"
-file_include_pragma_end		\"{st_whitespace_only}"}"
+file_include_pragma_beg		"{#include"{st_whitespace}\"
+file_include_pragma_end		\"{st_whitespace}"}"
 file_include_pragma			{file_include_pragma_beg}{file_include_pragma_filename}{file_include_pragma_end}
 
 
@@ -499,6 +548,8 @@
 /* Prelimenary constructs... */
 /*****************************/
 
+/* PRAGMAS */
+/* ======= */
 /* In order to allow the declaration of POU prototypes (Function, FB, Program, ...),
  * especially the prototypes of Functions and FBs defined in the standard
  * (i.e. standard functions and FBs), we extend the IEC 61131-3 standard syntax 
@@ -521,9 +572,41 @@
 
 
 /* Any other pragma... */
-
-pragma "{"[^}]*"}"|"{{"([^}]|"}"[^}])*"}}"
-
+pragma ("{"[^}]*"}")|("{{"([^}]|"}"[^}])*"}}")
+
+
+
+/* COMMENTS */
+/* ======== */
+
+/* In order to allow nested comments, comments are handled by a specific comment_state state */
+/* Whenever a "(*" is found, we push the current state onto the stack, and enter a new instance of the comment_state state.
+ * Whenever a "*)" is found, we pop a state off the stack
+ */
+
+/* comments... */
+comment_beg  "(*"
+comment_end  "*)"
+
+/* However, bison has a shift/reduce conflict in bison, when parsing formal function/FB
+ * invocations with the 'NOT <variable_name> =>' syntax (which needs two look ahead 
+ * tokens to be parsed correctly - and bison being LALR(1) only supports one).
+ * The current work around requires flex to completely parse the '<variable_name> =>'
+ * sequence. This sequence includes whitespace and/or comments between the 
+ * <variable_name> and the "=>" token.
+ * 
+ * This flex rule (sendto_identifier_token) uses the whitespace/comment as trailing context,
+ * which means we can not use the comment_state method of specifying/finding and ignoring 
+ * comments.
+ * 
+ * For this reason only, we must also define what a complete comment looks like, so
+ * it may be used in this rule. Since the rule uses the whitespace_or_comment
+ * construct as trailing context, this definition of comment must not use any
+ * trailing context either.
+ * 
+ * Aditionally, it is not possible to define nested comments in flex without the use of
+ * states, so for this particular location, we do NOT support nested comments.
+ */
 /* NOTE: this seemingly unnecessary complex definition is required
  *       to be able to eat up comments such as:
  *          '(* Testing... ! ***** ******)'
@@ -534,30 +617,29 @@
 not_asterisk				[^*]
 not_close_parenthesis_nor_asterisk	[^*)]
 asterisk				"*"
-comment_text		{not_asterisk}|(({asterisk}+){not_close_parenthesis_nor_asterisk})
-
+comment_text	({not_asterisk})|(({asterisk}+){not_close_parenthesis_nor_asterisk})
 comment		"(*"({comment_text}*)({asterisk}+)")"
 
 
+
+/* 3.1 Whitespace */
+/* ============== */
 /*
-3.1 Whitespace
- (NOTE: Whitespace IS clearly defined, to include newline!!! See section 2.1.4!!!)
- No definition of whitespace is given, in other words, the characters that may be used to seperate language tokens are not pecisely defined. One may nevertheless make an inteligent guess of using the space (' '), and other characters also commonly considered whitespace in other programming languages (horizontal tab, vertical tab, form feed, etc.).
- The main question is whether the newline character should be considered whitespace. IL language statements use an EOL token (End Of Line) to distinguish between some language constructs. The EOL token itself is openly defined as "normally consist[ing] of the 'paragraph separator' ", leaving the final choice open to each implemention. If we choose the newline character to represent the EOL token, it may then not be considered whitespace.
- On the other hand, some examples that come in a non-normative annex of the specification allow function declarations to span multiple3.1 Whitespace
- (NOTE: Whitespace IS clearly defined, to include newline!!! See section 2.1.4!!!)
- No definition of whitespace is given, in other words, the characters that may be used to seperate language tokens are not pecisely defined. One may nevertheless make an inteligent guess of using the space (' '), and other characters also commonly considered whitespace in other programming languages (horizontal tab, vertical tab, form feed, etc.).
- The main question is whether the newline character should be considered whitespace. IL language statements use an EOL token (End Of Line) to distinguish between some language constructs. The EOL token itself is openly defined as "normally consist[ing] of the 'paragraph separator' ", leaving the final choice open to each implemention. If we choose the newline character to represent the EOL token, it may then not be considered whitespace.
- On the other hand, some examples that come in a non-normative annex of the specification allow function declarations to span multiple lines, which means that the newline character is being considered as whitespace.
- Our implementation works around this issue by including the new line character in the whitespace while parsing function declarations and the ST language, and parsing it as the EOL token only while parsing IL language statements. This requires the use of a state machine in the lexical parser that needs at least some knowledge of the syntax itself.
-*/
-/* NOTE: Our definition of whitespace will only work in ASCII!
- *
- *       Since the IL language needs to know the location of newline
- *       (token EOL -> '\n' ), we need one definition of whitespace
- *       for each language...
- */
-/*
+ * Whitespace is clearly defined (see IEC 61131-3 v2, section 2.1.4)
+ * 
+ * Whitespace definition includes the newline character.
+ * 
+ * However, the standard is inconsistent in that in IL the newline character 
+ * is considered a token (EOL - end of line). 
+ * In our implementation we therefore have two definitions of whitespace
+ *   - one for ST, that includes the newline character
+ *   - one for IL without the newline character.
+ * Additionally, when parsing IL, the newline character is treated as the EOL token.
+ * This requires the use of a state machine in the lexical parser that needs at least 
+ * some knowledge of the syntax itself.
+ *
+ * NOTE: Our definition of whitespace will only work in ASCII!
+ *
  * NOTE: we cannot use
  *         st_whitespace	[:space:]*
  *       since we use {st_whitespace} as trailing context. In our case
@@ -569,22 +651,18 @@
  *       generating the invalid (in this case) warning...
  */
 
-st_whitespace_only	[ \f\n\r\t\v]*
-il_whitespace_only	[ \f\r\t\v]*
-
-st_whitespace_text	{st_whitespace_only}|{comment}|{pragma}
-il_whitespace_text	{il_whitespace_only}|{comment}|{pragma}
-
-st_whitespace	{st_whitespace_text}*
-il_whitespace	{il_whitespace_text}*
-
-st_whitespace_text_no_pragma	{st_whitespace_only}|{comment}
-il_whitespace_text_no_pragma	{il_whitespace_only}|{comment}
-
-st_whitespace_no_pragma	{st_whitespace_text_no_pragma}*
-il_whitespace_no_pragma	{il_whitespace_text_no_pragma}*
-
-qualified_identifier	{identifier}(\.{identifier})*
+st_whitespace			[ \f\n\r\t\v]*
+il_whitespace			[ \f\r\t\v]*
+
+st_whitespace_or_pragma_or_commentX	({st_whitespace})|({pragma})|({comment})
+il_whitespace_or_pragma_or_commentX	({il_whitespace})|({pragma})|({comment})
+
+st_whitespace_or_pragma_or_comment	{st_whitespace_or_pragma_or_commentX}*
+il_whitespace_or_pragma_or_comment	{il_whitespace_or_pragma_or_commentX}*
+
+
+
+qualified_identifier	{identifier}(\.{identifier})+
 
 
 
@@ -733,7 +811,6 @@
  *       minutes      ::= fixed_point 'm' | integer 'm' ['_'] seconds
  *       seconds      ::= fixed_point 's' | integer 's' ['_'] milliseconds
  *       milliseconds ::= fixed_point 'ms'
-
  */
 
 interval_ms_X		({integer_0_999}(\.{integer})?)ms
@@ -853,20 +930,20 @@
 	/* Pragmas sent to syntax analyser (bison) */
 {disable_code_generation_pragma}               return disable_code_generation_pragma_token;
 {enable_code_generation_pragma}                return enable_code_generation_pragma_token;
-<body_state>{disable_code_generation_pragma}   return disable_code_generation_pragma_token;
-<body_state>{enable_code_generation_pragma}    return enable_code_generation_pragma_token;
+<body_state,vardecl_list_state>{disable_code_generation_pragma}   return disable_code_generation_pragma_token;
+<body_state,vardecl_list_state>{enable_code_generation_pragma}    return enable_code_generation_pragma_token;
 
 	/* Any other pragma we find, we just pass it up to the syntax parser...   */
 	/* Note that the <body_state> state is exclusive, so we have to include it here too. */
 {pragma}	{/* return the pragmma without the enclosing '{' and '}' */
-         int cut = yytext[1]=='{'?2:1;
+		 int cut = yytext[1]=='{'?2:1;
 		 yytext[strlen(yytext)-cut] = '\0';
 		 yylval.ID=strdup(yytext+cut);
 		 return pragma_token;
 		}
-<body_state>{pragma} {/* return the pragmma without the enclosing '{' and '}' */
+<body_state,vardecl_list_state>{pragma} {/* return the pragmma without the enclosing '{' and '}' */
 		 int cut = yytext[1]=='{'?2:1;
-         yytext[strlen(yytext)-cut] = '\0';
+		 yytext[strlen(yytext)-cut] = '\0';
 		 yylval.ID=strdup(yytext+cut);
 		 return pragma_token;
 		}
@@ -950,7 +1027,7 @@
 	/* Handle all the state changes! */
 	/*********************************/
 
-	/* INITIAL -> decl_state */
+	/* INITIAL -> header_state */
 <INITIAL>{
 	/* NOTE: how about functions that do not declare variables, and go directly to the body_state???
 	 *      - According to Section 2.5.1.3 (Function Declaration), item 2 in the list, a FUNCTION
@@ -966,12 +1043,12 @@
 	 *       All the above means that we needn't worry about PROGRAMs, FUNCTIONs or
 	 *       FUNCTION_BLOCKs that do not have at least one VAR_END before the body_state.
 	 *       If the code has an error, and no VAR_END before the body, we will simply
-	 *       continue in the <decl_state> state, untill the end of the FUNCTION, FUNCTION_BLOCK
+	 *       continue in the <vardecl_state> state, untill the end of the FUNCTION, FUNCTION_BLOCK
 	 *       or PROGAM.
 	 */
-FUNCTION				BEGIN(decl_state); return FUNCTION;
-FUNCTION_BLOCK				BEGIN(decl_state); return FUNCTION_BLOCK;
-PROGRAM					BEGIN(decl_state); return PROGRAM;
+FUNCTION				yy_push_state(header_state); return FUNCTION;
+FUNCTION_BLOCK				yy_push_state(header_state); return FUNCTION_BLOCK;
+PROGRAM					yy_push_state(header_state); return PROGRAM;
 CONFIGURATION				BEGIN(config_state); return CONFIGURATION;
 }
 
@@ -989,69 +1066,84 @@
 }
 	*/
 
-	/* decl_state -> (body_state | sfc_state) */
-<decl_state>{
-END_VAR{st_whitespace}VAR		{unput_text(strlen("END_VAR")); 
-					 return END_VAR;
-					}
-END_VAR{st_whitespace}INITIAL_STEP	{unput_text(strlen("END_VAR")); 
-					 yy_push_state(sfc_state); 
-					 return END_VAR;
-					}
-END_VAR{st_whitespace}			{unput_text(strlen("END_VAR")); 
-					 cmd_goto_body_state(); 
-					 return END_VAR;
-					}
-}
-
-	/* body_state -> (il_state | st_state) */
+	/* header_state -> (vardecl_list_state) */
+<header_state>{
+VAR				| /* execute the next rule's action, i.e. fall-through! */
+VAR_INPUT			|
+VAR_OUTPUT			|
+VAR_IN_OUT			|
+VAR_EXTERNAL			|
+VAR_GLOBAL			|
+VAR_TEMP			|
+VAR_CONFIG			|
+VAR_ACCESS			unput_text(0); BEGIN(vardecl_list_state);
+}
+
+
+	/* vardecl_list_state -> (vardecl_state | body_state | INITIAL) */
+<vardecl_list_state>{
+VAR_INPUT			| /* execute the next rule's action, i.e. fall-through! */
+VAR_OUTPUT			|
+VAR_IN_OUT			|
+VAR_EXTERNAL			|
+VAR_GLOBAL			|
+VAR_TEMP			|
+VAR_CONFIG			|
+VAR_ACCESS			|
+VAR				unput_text(0); yy_push_state(vardecl_state);
+
+END_FUNCTION			unput_text(0); BEGIN(INITIAL); 
+END_FUNCTION_BLOCK		unput_text(0); BEGIN(INITIAL); 
+END_PROGRAM			unput_text(0); BEGIN(INITIAL); 
+
+.				unput_text(0); yy_push_state(body_state); /* anything else, just change to body_state! */
+}
+
+
+	/* vardecl_list_state -> pop to $previous_state (vardecl_list_state) */
+<vardecl_state>{
+END_VAR				yy_pop_state(); return END_VAR; /* pop back to header_state */
+}
+
+
+	/* body_state -> (il_state | st_state | sfc_state) */
 <body_state>{
-{st_whitespace_no_pragma}			/* Eat any whitespace */
-{qualified_identifier}{st_whitespace}":="	unput_text(0); BEGIN(st_state);
-{direct_variable_standard}{st_whitespace}":="	unput_text(0); BEGIN(st_state);
-{qualified_identifier}"["			unput_text(0); BEGIN(st_state);
-
-RETURN						unput_text(0); BEGIN(st_state);
-IF						unput_text(0); BEGIN(st_state);
-CASE						unput_text(0); BEGIN(st_state);
-FOR						unput_text(0); BEGIN(st_state);
-WHILE						unput_text(0); BEGIN(st_state);
-REPEAT						unput_text(0); BEGIN(st_state);
-EXIT						unput_text(0); BEGIN(st_state);
+INITIAL_STEP			unput_text(0); BEGIN(sfc_state); 
+
+{qualified_identifier}		unput_text(0); BEGIN(st_state); /* will always be followed by '[' for an array access, or ':=' as the left hand of an assignment statement */
+{direct_variable_standard}	unput_text(0); BEGIN(st_state); /* will always be followed by ':=' as the left hand of an assignment statement */
+
+RETURN				unput_text(0); BEGIN(st_state);
+IF				unput_text(0); BEGIN(st_state);
+CASE				unput_text(0); BEGIN(st_state);
+FOR				unput_text(0); BEGIN(st_state);
+WHILE				unput_text(0); BEGIN(st_state);
+EXIT				unput_text(0); BEGIN(st_state);
+REPEAT				unput_text(0); BEGIN(st_state);
 
 	/* ':=' occurs only in transitions, and not Function or FB bodies! */
-:=						unput_text(0); BEGIN(st_state);
-
-	/* Hopefully, the above rules (along with the last one),
-         * used to distinguish ST from IL, are 
-	 * enough to handle all ocurrences. However, if
-	 * there is some situation where the compiler is getting confused,
-	 * we add the following rule to detect 'label:' in IL code. This will
-	 * allow the user to insert a label right at the beginning (which
-	 * will probably not be used further by his code) simply as a way
-	 * to force the compiler to interpret his code as IL code.
-	 */
-{identifier}{st_whitespace}":"{st_whitespace}	unput_text(0); BEGIN(il_state);
+:=				unput_text(0); BEGIN(st_state);
 
 {identifier}	{int token = get_identifier_token(yytext);
-		 if (token == prev_declared_fb_name_token) {
-		   /* the code has a call to a function block */
-		   /* NOTE: if we ever decide to allow the user to use IL operator tokens
-		    * (LD, ST, ...) as identifiers for variable names (including
-		    * function block instances), then the above inference/conclusion 
-		    * may be incorrect, and this condition may have to be changed!
-		    */	
-		   BEGIN(st_state);
+		 if ((token == prev_declared_fb_name_token) || (token == prev_declared_variable_name_token)) {
+		   /* the code has a call to a function block OR has an assingment with a variable as the lvalue */
+		   unput_text(0); BEGIN(st_state);
+		 } else
+ 		 if (token == prev_declared_derived_function_name_token) {
+		   /* the code has a call to a function - must be IL */
+		   unput_text(0); BEGIN(il_state);
 		 } else {
-		   BEGIN(il_state);
+		   /* Might be a lable in IL, or a bug in ST/IL code. We jump to IL */
+		   unput_text(0); BEGIN(il_state);
 		 }
-		 unput_text(0);
 		}
 
-.		unput_text(0); BEGIN(il_state);
+.		unput_text(0); BEGIN(il_state); /* Don't know what it could be. This is most likely a bug. Let's just to a random state... */
 }	/* end of body_state lexical parser */
 
-	/* (il_state | st_state) -> $previous_state (decl_state or sfc_state) */
+
+
+	/* (il_state | st_state) -> pop to $previous_state (vardecl_list_state or sfc_state) */
 <il_state,st_state>{
 END_FUNCTION		yy_pop_state(); unput_text(0);
 END_FUNCTION_BLOCK	yy_pop_state(); unput_text(0);
@@ -1060,19 +1152,13 @@
 END_ACTION		yy_pop_state(); unput_text(0);
 }
 
-	/* sfc_state -> INITIAL */
+	/* sfc_state -> pop to $previous_state (vardecl_list_state or sfc_state) */
 <sfc_state>{
 END_FUNCTION		yy_pop_state(); unput_text(0);
 END_FUNCTION_BLOCK	yy_pop_state(); unput_text(0);
 END_PROGRAM		yy_pop_state(); unput_text(0);
 }
 
-	/* decl_state -> INITIAL */
-<decl_state>{
-END_FUNCTION		BEGIN(INITIAL); return END_FUNCTION;
-END_FUNCTION_BLOCK	BEGIN(INITIAL); return END_FUNCTION_BLOCK;
-END_PROGRAM		BEGIN(INITIAL); return END_PROGRAM;
-}
 	/* config -> INITIAL */
 END_CONFIGURATION	BEGIN(INITIAL); return END_CONFIGURATION;
 
@@ -1083,10 +1169,19 @@
 	/***************************************/
 	/* NOTE: pragmas are handled right at the beginning... */
 
-<INITIAL,config_state,decl_state,st_state,sfc_state,task_init_state,sfc_qualifier_state>{st_whitespace_no_pragma}	/* Eat any whitespace */
-<il_state>{il_whitespace_no_pragma}		/* Eat any whitespace */
-
-
+	/* The whitespace */
+<INITIAL,header_state,config_state,body_state,vardecl_list_state,vardecl_state,st_state,sfc_state,task_init_state,sfc_qualifier_state>{st_whitespace}	/* Eat any whitespace */
+<il_state>{il_whitespace}		/* Eat any whitespace */
+
+	/* The comments */
+<body_state,vardecl_list_state>{comment_beg}		yy_push_state(comment_state);
+{comment_beg}						yy_push_state(comment_state);
+<comment_state>{
+{comment_beg}						{if (get_opt_nested_comments()) yy_push_state(comment_state);}
+{comment_end}						yy_pop_state();
+.							/* Ignore text inside comment! */
+\n							/* Ignore text inside comment! */
+}
 
 	/*****************************************/
 	/* B.1.1 Letters, digits and identifiers */
@@ -1639,8 +1734,8 @@
 	/*****************************************/
 	/* B.1.1 Letters, digits and identifiers */
 	/*****************************************/
-<st_state>{identifier}/({st_whitespace})"=>"	{yylval.ID=strdup(yytext); return sendto_identifier_token;}
-<il_state>{identifier}/({il_whitespace})"=>"	{yylval.ID=strdup(yytext); return sendto_identifier_token;}
+<st_state>{identifier}/({st_whitespace_or_pragma_or_comment})"=>"	{yylval.ID=strdup(yytext); return sendto_identifier_token;}
+<il_state>{identifier}/({il_whitespace_or_pragma_or_comment})"=>"	{yylval.ID=strdup(yytext); return sendto_identifier_token;}
 {identifier} 				{yylval.ID=strdup(yytext);
 					 // printf("returning identifier...: %s, %d\n", yytext, get_identifier_token(yytext));
 					 return get_identifier_token(yytext);}
--- a/stage1_2/stage1_2.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage1_2/stage1_2.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -63,6 +63,12 @@
 bool safe_extensions_ = false;
 bool get_opt_safe_extensions() {return safe_extensions_;}
 
+/************************************/
+/* whether to allow nested comments */
+/************************************/
+bool nested_comments_ = false;
+bool get_opt_nested_comments() {return nested_comments_;}
+
 /******************************************************/
 /* whether we are supporting conversion functions     */
 /* for enumerate data types                           */
@@ -241,6 +247,7 @@
        *       We now set those variables...
        */
 
+  nested_comments_ = options.nested_comments;    
   safe_extensions_ = options.safe_extensions;
   conversion_functions_ = options.conversion_functions;
   return stage2__(filename, options.includedir, tree_root_ref, options.full_token_loc);
--- a/stage1_2/stage1_2.hh	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage1_2/stage1_2.hh	Wed Feb 19 22:27:11 2014 +0100
@@ -57,12 +57,10 @@
 		/* Version 1.0 – Official Release                     */
 		/******************************************************/
 	bool safe_extensions;
-		/* error messages specify full token location */
-	bool full_token_loc; 
-		/* Include directory, where included files will be searched for... */
-	bool conversion_functions;
-		/* Create a conversion function for derived datatype */
-	const char *includedir;
+	bool full_token_loc;       /* error messages specify full token location */
+	bool conversion_functions; /* Create a conversion function for derived datatype */
+	bool nested_comments;      /* Allow the use of nested comments. */
+	const char *includedir;    /* Include directory, where included files will be searched for... */
 } stage1_2_options_t;
 
 
--- a/stage1_2/stage1_2_priv.hh	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage1_2/stage1_2_priv.hh	Wed Feb 19 22:27:11 2014 +0100
@@ -88,6 +88,10 @@
 /******************************************************/
 bool get_opt_safe_extensions();
 
+/************************************/
+/* whether to allow nested comments */
+/************************************/
+bool get_opt_nested_comments();
 
 
 /*************************************************************/
--- a/stage3/declaration_check.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage3/declaration_check.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -112,8 +112,14 @@
         continue;
       }
       
-      if (search_var_instance_glo_decl->get_option(var_name) != search_var_instance_ext_decl.get_option(var_name))
-        STAGE3_ERROR(0, glo_decl, glo_decl, "Declaration error.  The external variable options do not match with thos of the global variable.");
+      /* Check whether variable's constness (CONSTANT) is compatible.
+       *        VAR_GLOBAL is contant     => VAR_EXTERNAL must also be CONSTANT
+       *        VAR_GLOBAL is not contant => VAR_EXTERNAL may be CONSTANT, or not!
+       */
+      search_var_instance_decl_c::opt_t ext_opt = search_var_instance_ext_decl. get_option(var_name);
+      search_var_instance_decl_c::opt_t glo_opt = search_var_instance_glo_decl->get_option(var_name);
+      if ((glo_opt == search_var_instance_decl_c::constant_opt) && (ext_opt != search_var_instance_decl_c::constant_opt))
+        STAGE3_ERROR(0, glo_decl, glo_decl, "Declaration error. The external variable must be declared as constant, as it maps to a constant global variable.");
 
       /* TODO: Check redefinition data type.
        *       We need a new class (like search_base_type class) to get type id by variable declaration.
--- a/stage3/fill_candidate_datatypes.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage3/fill_candidate_datatypes.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -555,17 +555,13 @@
  *        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;
-	
+	symbol_c *fb_decl = (NULL == il_operand)? NULL : search_varfb_instance_type->get_basetype_decl(il_operand);
+	if (! get_datatype_info_c::is_function_block(fb_decl)) fb_decl = NULL;
+
+	/* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
+	/* However, when calling using the 'S' and 'R' operators, this error is not caught by stage 2, as these operators have two possible semantics */
+	// if (NULL == fb_type_id) ERROR;
+
 	/* 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!
@@ -594,10 +590,55 @@
 
 
 
+
+/* handle the S and R IL operators... */
+/* operator_str should be set to either "S" or "R" */
+void *fill_candidate_datatypes_c::handle_S_and_R_operator(symbol_c *symbol, const char *operator_str, symbol_c *&called_fb_declaration) {
+	/* NOTE: this operator has two possible semantic meanings:
+	 *          - Set/Reset the BOOL operand variable to true
+	 *          - call the FB specified by the operand.
+	 *       Which of the two semantics will have to be determined by the datatype of the operand!
+	 */
+	symbol_c *prev_instruction_type, *operand_type;
+
+	if (NULL == prev_il_instruction) return NULL;
+	if (NULL == il_operand)          return NULL;
+
+	/* Try the Set/Reset semantics */
+	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];
+			/* IEC61131-3, Table 52, Note (e) states that the datatype of the operand must be BOOL!
+			 * IEC61131-3, Table 52, line 3 states that this operator should "Set operand to 1 if current result is Boolean 1"
+			 *     which implies that the prev_instruction_type MUST also be BOOL compatible.
+			 */
+			if (get_datatype_info_c::is_BOOL_compatible(prev_instruction_type) && get_datatype_info_c::is_BOOL_compatible(operand_type))
+				add_datatype_to_candidate_list(symbol, prev_instruction_type);
+		}
+	}
+
+	/* if the appropriate semantics is not a Set/Reset of a boolean variable, the we try for the FB invocation! */
+	if (symbol->candidate_datatypes.size() == 0) {
+		handle_implicit_il_fb_call(symbol,  operator_str, called_fb_declaration);
+		/* If it is also not a valid FB call, make sure the candidate_datatypes is empty (handle_implicit_il_fb_call may leave it non-empty!!) */
+		/* From here on out, all later code will consider the symbol->called_fb_declaration being NULL as an indication that this operator must use the
+		 * Set/Reset semantics, so we must also guarantee that the remainder of the state of this symbol is compatible with that assumption!
+		 */
+		if (NULL == called_fb_declaration)
+			symbol->candidate_datatypes.clear();
+	}
+
+	if (debug) std::cout << operator_str << " [" << prev_il_instruction->candidate_datatypes.size() << "," << il_operand->candidate_datatypes.size() << "] ==> "  << symbol->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; 
+	if (NULL == l_expr) return NULL; /* if no prev_il_instruction */
+	if (NULL == r_expr) return NULL; /* if no IL operand!! */
 
 	for(unsigned int i = 0; i < l_expr->candidate_datatypes.size(); i++)
 		for(unsigned int j = 0; j < r_expr->candidate_datatypes.size(); j++)
@@ -627,7 +668,7 @@
 	handle_binary_expression(widen_table, symbol, l_expr, r_expr);
 	for(unsigned int i = 0; i < l_expr->candidate_datatypes.size(); i++)
 		for(unsigned int j = 0; j < r_expr->candidate_datatypes.size(); j++) {
-			if ((l_expr->candidate_datatypes[i] == r_expr->candidate_datatypes[j]) && search_base_type_c::type_is_enumerated(l_expr->candidate_datatypes[i]))
+			if ((l_expr->candidate_datatypes[i] == r_expr->candidate_datatypes[j]) && get_datatype_info_c::is_enumerated(l_expr->candidate_datatypes[i]))
 				add_datatype_to_candidate_list(symbol, &get_datatype_info_c::bool_type_name);
 		}
 	return NULL;
@@ -1112,12 +1153,29 @@
 	/* 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);
+	add_datatype_to_candidate_list(symbol, search_varfb_instance_type->get_basetype_decl(symbol));   /* will only add if non NULL */
 	
 	/* recursively call the subscript list, so we can check the data types of the expressions used for the subscripts */
 	symbol->subscript_list->accept(*this);
 
+	/* recursively call the subscripted_variable. We need to do this since the array variable may be stored inside a structured
+	 * variable (i.e. if it is an element inside a struct), in which case we want to recursively visit every element of the struct,
+	 * as it may contain more arrays whose subscripts must also be visited!
+	 * e.g.   structvar.a1[v1+2].b1.c1[v2+3].d1
+	 *        TYPE
+	 *           d_s: STRUCT d1: int; d2: int;
+	 *           d_a: ARRAY [1..3] OF d_s;  
+	 *           c_s: STRUCT c1: d_a; c2: d_a;
+	 *           b_s: STRUCT b1: c_s; b2: c_s;
+	 *           b_a: ARRAY [1..3] OF b_s;  
+	 *           a_s: STRUCT a1: b_a; a2: b_a;
+	 *        END_TYPE 
+	 *        VAR
+	 *          structvar: a_s;
+	 *        END_VAR
+	 */
+	symbol->subscripted_variable->accept(*this);
+
 	if (debug) std::cout << "ARRAY_VAR [" << symbol->candidate_datatypes.size() << "]\n";	
 	return NULL;
 }
@@ -1136,11 +1194,18 @@
  *           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) {
+	/* 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.
+	 */
 	add_datatype_to_candidate_list(symbol, search_varfb_instance_type->get_basetype_decl(symbol));  /* will only add if non NULL */
+	/* However, we do need to visit each record type recursively!
+	 * Remember that a structured variable may be stored inside an array (e.g. arrayvar[33].elem1)
+	 * The array subscripts may contain a complex expression (e.g. arrayvar[ varx + 33].elem1) whose datatype must be correctly determined!
+	 * The expression, may even contain a function call to an overloaded function!
+	 *      (e.g.  arrayvar[ varx + TRUNC(realvar)].elem1)
+	 */
+	symbol->record_variable->accept(*this);
 	return NULL;
 }
 
@@ -1529,21 +1594,11 @@
  * | 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 */
+/* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 */
 // 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;
+	symbol_c *fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name);
+	if (! get_datatype_info_c::is_function_block(fb_decl)) 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;
@@ -1640,6 +1695,7 @@
 /* B 2.2 Operators */
 /*******************/
 void *fill_candidate_datatypes_c::visit(LD_operator_c *symbol) {
+	if (NULL == il_operand)          return NULL;
 	for(unsigned int i = 0; i < il_operand->candidate_datatypes.size(); i++) {
 		add_datatype_to_candidate_list(symbol, il_operand->candidate_datatypes[i]);
 	}
@@ -1648,6 +1704,7 @@
 }
 
 void *fill_candidate_datatypes_c::visit(LDN_operator_c *symbol) {
+	if (NULL == il_operand)          return NULL;
 	for(unsigned int i = 0; i < il_operand->candidate_datatypes.size(); i++) {
 		if      (get_datatype_info_c::is_ANY_BIT_compatible(il_operand->candidate_datatypes[i]))
 			add_datatype_to_candidate_list(symbol, il_operand->candidate_datatypes[i]);
@@ -1660,6 +1717,7 @@
 	symbol_c *prev_instruction_type, *operand_type;
 
 	if (NULL == prev_il_instruction) return NULL;
+	if (NULL == il_operand)          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];
@@ -1676,6 +1734,7 @@
 	symbol_c *prev_instruction_type, *operand_type;
 
 	if (NULL == prev_il_instruction) return NULL;
+	if (NULL == il_operand)          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];
@@ -1696,6 +1755,7 @@
 	 *       We do not need to generate an error message. This error will be caught somewhere else!
 	 */
 	if (NULL == prev_il_instruction) return NULL;
+	if (NULL == il_operand)          return NULL;
 	for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) {
 		if (get_datatype_info_c::is_ANY_BIT_compatible(prev_il_instruction->candidate_datatypes[i]))
 			add_datatype_to_candidate_list(symbol, prev_il_instruction->candidate_datatypes[i]);
@@ -1705,58 +1765,17 @@
 }
 
 
-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 (get_datatype_info_c::is_type_equal(prev_instruction_type,operand_type) && get_datatype_info_c::is_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 (get_datatype_info_c::is_type_equal(prev_instruction_type,operand_type) && get_datatype_info_c::is_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(   S_operator_c *symbol) {return handle_S_and_R_operator   (symbol,   "S", symbol->called_fb_declaration);}
+void *fill_candidate_datatypes_c::visit(   R_operator_c *symbol) {return handle_S_and_R_operator   (symbol,   "R", symbol->called_fb_declaration);}
+
+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(  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);}
@@ -1945,17 +1964,9 @@
 /* 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;
+	symbol_c *fb_decl = search_varfb_instance_type->get_basetype_decl(symbol->fb_name);
+	if (! get_datatype_info_c::is_function_block(fb_decl )) fb_decl = NULL;
+	if (NULL == fb_decl) ERROR; /* Although a call to a non-declared FB is a semantic error, this is currently caught by stage 2! */
 	
 	if (symbol->   formal_param_list != NULL) symbol->formal_param_list->accept(*this);
 	if (symbol->nonformal_param_list != NULL) symbol->nonformal_param_list->accept(*this);
--- a/stage3/fill_candidate_datatypes.hh	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage3/fill_candidate_datatypes.hh	Wed Feb 19 22:27:11 2014 +0100
@@ -89,7 +89,8 @@
     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_implicit_il_fb_call(symbol_c *il_instruction, const char *param_name,   symbol_c *&called_fb_declaration);
+    void *handle_S_and_R_operator   (symbol_c *symbol,         const char *operator_str, symbol_c *&called_fb_declaration);
     void *handle_equality_comparison(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr);
     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);
--- a/stage3/lvalue_check.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage3/lvalue_check.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -114,7 +114,7 @@
 	 * when an expression is found, we may replace this check with an assertion...
 	 * if (NULL == struct_elem) ERROR;
 	 */
-	symbol_c *struct_elem = decompose_lvalue.next_part();
+	symbol_c *struct_elem = decompose_lvalue.get_next();
 	if (NULL == struct_elem) return;
 	
 	symbol_c *type_decl   = search_var_instance_decl->get_decl(struct_elem);
@@ -135,7 +135,7 @@
 	function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(basetype_id);
 	if (function_block_type_symtable.end_value() == fb_decl) return;
 
-	while (NULL != (struct_elem = decompose_lvalue.next_part())) {
+	while (NULL != (struct_elem = decompose_lvalue.get_next())) {
 		search_var_instance_decl_c   fb_search_var_instance_decl(fb_decl);
 		if (search_var_instance_decl_c::output_vt == fb_search_var_instance_decl.get_vartype(struct_elem)) {
 			STAGE3_ERROR(0, struct_elem, struct_elem, "Assignment to FB output variable is not allowed.");
@@ -156,16 +156,13 @@
 void lvalue_check_c::check_assignment_to_constant(symbol_c *lvalue) {
 	unsigned int option = search_var_instance_decl->get_option(lvalue);
 	if (option == search_var_instance_decl_c::constant_opt) {
-		STAGE3_ERROR(0, lvalue, lvalue, "Assignment to CONSTANT variables is not be allowed.");
+		STAGE3_ERROR(0, lvalue, lvalue, "Assignment to CONSTANT variables is not allowed.");
 	}
 }
 
 
 /*  No assigning values to expressions. */
 void lvalue_check_c::check_assignment_to_expression(symbol_c *lvalue) {
-	/* This may occur in function invocations, when passing values (possibly an expression) to one 
-	 * of the function's OUTPUT or IN_OUT parameters.
-	 */
 	/* This may occur in function invocations, when passing values (possibly an expression) to one
 	 * of the function's OUTPUT or IN_OUT parameters.
 	 */
@@ -233,21 +230,39 @@
 	     (typeid( *lvalue ) == typeid( neg_expression_c               )) ||
 	     (typeid( *lvalue ) == typeid( not_expression_c               )) ||
 	     (typeid( *lvalue ) == typeid( function_invocation_c          )))
-		STAGE3_ERROR(0, lvalue, lvalue, "Assigning an expression to an OUT or IN_OUT parameter is not allowed.");
+		STAGE3_ERROR(0, lvalue, lvalue, "Assignment to an expression or a literal value is not allowed.");
 }                                                                  
 
 
 
+/*  No assigning values to IL lists. */
+void lvalue_check_c::check_assignment_to_il_list(symbol_c *lvalue) {
+	/* This may occur in formal invocations in IL, where an embedded IL list may be used instead of a symbolic_variable
+	 * when passing an IN_OUT parameter! Note that it will never occur to OUT parameters, as the syntax does not allow it,
+	 * although this does not affect out algorithm here!
+	 */
+	if ( 
+	     /****************************************/
+	     /* B.2 - Language IL (Instruction List) */
+	     /****************************************/
+	     /***********************************/
+	     /* B 2.1 Instructions and Operands */
+	     /***********************************/
+	     (typeid( *lvalue ) == typeid( simple_instr_list_c)))
+		STAGE3_ERROR(0, lvalue, lvalue, "Assigning an IL list to an IN_OUT parameter is not allowed.");
+}                                                                  
 
 
 
 
 void lvalue_check_c::verify_is_lvalue(symbol_c *lvalue) {
+	if (NULL == lvalue) return; // missing operand in source code being compiled. Error will be caught and reported by datatype checking!
 	int init_error_count = error_count;  /* stop the checks once an error has been found... */
 	if (error_count == init_error_count)  check_assignment_to_expression(lvalue);
+	if (error_count == init_error_count)  check_assignment_to_il_list   (lvalue);
 	if (error_count == init_error_count)  check_assignment_to_controlvar(lvalue);
-	if (error_count == init_error_count)  check_assignment_to_output(lvalue);
-	if (error_count == init_error_count)  check_assignment_to_constant(lvalue);
+	if (error_count == init_error_count)  check_assignment_to_output    (lvalue);
+	if (error_count == init_error_count)  check_assignment_to_constant  (lvalue);
 }
 
 
@@ -261,6 +276,12 @@
  */
 #include <string.h> /* required for strcmp() */
 void lvalue_check_c::check_nonformal_call(symbol_c *f_call, symbol_c *f_decl) {
+	/* if data type semantic verification was unable to determine which function is being called,
+	 * then it does not make sense to go ahead and check for lvalues to unknown parameters.
+	 * We simply bug out!
+	 */
+	if (NULL == f_decl) return;
+	
 	symbol_c *call_param_value;
 	identifier_c *param_name;
 	function_param_iterator_c       fp_iterator(f_decl);
@@ -286,9 +307,9 @@
 			/* If the parameter is either OUT or IN_OUT, we check if 'call_param_value' is a valid lvalue */
 			if ((function_param_iterator_c::direction_out == param_direction) || (function_param_iterator_c::direction_inout == param_direction)) 
 				verify_is_lvalue(call_param_value);
-			/* parameter values to IN parameters may be expressions with function invocations that must also be checked! */
-			if (function_param_iterator_c::direction_in == param_direction) 
-				call_param_value->accept(*this);  
+			/* parameter values to IN  parameters may be expressions with function invocations that must also be checked! */
+			/* parameter values to OUT or IN_OUT parameters may contain arrays, whose subscripts contain expressions that must be checked! */
+			call_param_value->accept(*this);  
 		}
 	}
 }
@@ -326,10 +347,9 @@
 			/* If the parameter is either OUT or IN_OUT, we check if 'call_param_value' is a valid lvalue */
 			if ((function_param_iterator_c::direction_out == param_direction) || (function_param_iterator_c::direction_inout == param_direction)) 
 				verify_is_lvalue(call_param_value);
-			/* parameter values to IN parameters may be expressions with function invocations that must also be checked! */
-			if (function_param_iterator_c::direction_in == param_direction) 
-				call_param_value->accept(*this);  
-		
+			/* parameter values to IN  parameters may be expressions with function invocations that must also be checked! */
+			/* parameter values to OUT or IN_OUT parameters may contain arrays, whose subscripts contain expressions that must be checked! */
+			call_param_value->accept(*this);  
  		}
 	}
 }
--- a/stage3/lvalue_check.hh	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage3/lvalue_check.hh	Wed Feb 19 22:27:11 2014 +0100
@@ -60,6 +60,8 @@
     void check_assignment_to_output    (symbol_c *lvalue);
     void check_assignment_to_constant  (symbol_c *lvalue);
     void check_assignment_to_expression(symbol_c *lvalue);
+    void check_assignment_to_il_list   (symbol_c *lvalue);
+    
     void check_formal_call   (symbol_c *f_call, symbol_c *f_decl);
     void check_nonformal_call(symbol_c *f_call, symbol_c *f_decl);
 
--- a/stage3/narrow_candidate_datatypes.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage3/narrow_candidate_datatypes.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -322,11 +322,9 @@
 
 	/* 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);
+		set_datatype(called_fb_declaration, il_operand); /* only set it if it is in the candidate datatypes list! */  
 		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
@@ -336,8 +334,10 @@
 		return NULL;
 	}
 
+	symbol_c *fb_decl = (NULL == il_operand)? NULL : il_operand->datatype;
+	
 	if (NULL == fb_decl) {
-		/* the il_operand is a not FB instance */
+		/* the il_operand is a not FB instance, or it simply does not even exist, */
 		/* 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);
@@ -649,7 +649,11 @@
 /*********************/
 /* B 1.4 - Variables */
 /*********************/
-
+// SYM_REF1(symbolic_variable_c, var_name)
+void *narrow_candidate_datatypes_c::visit(symbolic_variable_c *symbol) {
+	symbol->var_name->datatype = symbol->datatype;
+	return NULL;
+}
 /********************************************/
 /* B 1.4.1 - Directly Represented Variables */
 /********************************************/
@@ -662,6 +666,14 @@
 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);
+
+	/* Set the datatype of the subscripted variable and visit it recursively. For the reason why we do this,                                                 */
+	/* Please read the comments in the array_variable_c and structured_variable_c visitors in the fill_candidate_datatypes.cc file! */
+	symbol->subscripted_variable->accept(*this); // visit recursively
+
+	if (symbol->subscripted_variable->candidate_datatypes.size() == 1)
+	  symbol->subscripted_variable->datatype = symbol->subscripted_variable->candidate_datatypes[0]; // set the datatype
+
 	return NULL;
 }
 
@@ -681,6 +693,24 @@
 
 
 
+/*  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 *narrow_candidate_datatypes_c::visit(structured_variable_c *symbol) {
+	/* Set the datatype of the record_variable and visit it recursively. For the reason why we do this,                                                      */
+	/* Please read the comments in the array_variable_c and structured_variable_c visitors in the fill_candidate_datatypes.cc file! */
+	symbol->record_variable->accept(*this); // visit recursively
+
+	if (symbol->record_variable->candidate_datatypes.size() == 1)
+	  symbol->record_variable->datatype = symbol->record_variable->candidate_datatypes[0]; // set the datatype
+
+	return NULL;
+}
+
 
 /******************************************/
 /* B 1.4.3 - Declaration & Initialisation */
@@ -973,7 +1003,7 @@
  * | 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 */
+/* NOTE: The parameter 'called_fb_declaration'is used to pass data between stage 3 and stage4 */
 // 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;
@@ -1056,18 +1086,66 @@
 /*******************/
 /* B 2.2 Operators */
 /*******************/
+/* Sets the datatype of the il_operand, and calls it recursively!
+ * 
+ * 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!
+ *
+ *       So, if yoy wish to set the prev_il_instruction->datatype = symbol->datatype;
+ *       do it __before__ calling set_il_operand_datatype() (which in turn calls il_operand->accept(*this)) !!
+ */
+void *narrow_candidate_datatypes_c::set_il_operand_datatype(symbol_c *il_operand, symbol_c *datatype) {
+	if (NULL == il_operand) return NULL; /* if no IL operand => error in the source code!! */
+
+	/* If il_operand already has a non-NULL datatype (remember, narrow algorithm runs twice over IL lists!),
+	 * but narrow algorithm has not yet been able to determine what datatype it should take? This is strange,
+	 * and most probably an error!
+	 */
+	if ((NULL != il_operand->datatype) && (NULL == datatype)) ERROR;
+
+	/* If the il_operand's datatype has already been set previously, and
+	 * the narrow algorithm has already determined the datatype the il_operand should take!
+	 *   ...we just make sure that the new datatype is the same as the current il_operand's datatype
+	 */
+	if ((NULL != il_operand->datatype)  && (NULL != datatype)) {
+		/* Both datatypes are an invalid_type_name_c. This implies they are the same!! */
+		if ((!get_datatype_info_c::is_type_valid(datatype)) && ((!get_datatype_info_c::is_type_valid(il_operand->datatype)))) 
+			return NULL;;
+		/* OK, so both the datatypes are valid, but are they equal? */
+		if ( !get_datatype_info_c::is_type_equal(il_operand->datatype, datatype)) 
+			ERROR; 
+		/* The datatypes are the same. We have nothing to do, so we simply return! */
+		return NULL;
+	}
+
+	/* Set the il_operand's datatype. Note that the new 'datatype' may even be NULL!!! */
+	il_operand->datatype = datatype;
+	/* Even if we are not able to determine the il_operand's datatype ('datatype' is NULL), we still visit it recursively,
+	 * to give a chance of any complex expressions embedded in the il_operand (e.g. expressions inside array subscripts!) 
+	 * to be narrowed too.
+	 */
+	il_operand->accept(*this);
+	return NULL;
+}
+
+
+
+
 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. 
+	if (NULL == il_operand) return NULL; /* if no IL operand => error in the source code!! */
+
+	 /* NOTE 1: the il_operand __may__ be pointing to a parenthesized list of IL instructions. 
 	 * e.g.  LD 33
 	 *       AND ( 45
 	 *            OR 56
@@ -1082,134 +1160,130 @@
 	 *         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;
-				il_operand->accept(*this);
-				
-				/* NOTE: DO NOT search any further! Return immediately!
-				 * Since we support SAFE*** datatypes, multiple entries in the widen_table may be compatible.
-				 * If we try to set more than one distinct datatype on the same symbol, then the datatype will be set to
-				 * an invalid_datatype, which is NOT what we want!
-				 */
-				return NULL;
+	if (NULL != symbol->datatype) { // next IL instructions were able to determine the datatype this instruction should produce
+		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 */
+					set_il_operand_datatype(il_operand, operand_type);
+					
+					/* NOTE: DO NOT search any further! Return immediately!
+					 * Since we support SAFE*** datatypes, multiple entries in the widen_table may be compatible.
+					 * If we try to set more than one distinct datatype on the same symbol, then the datatype will be set to
+					 * an invalid_datatype, which is NOT what we want!
+					 */
+					return NULL;
+				}
 			}
 		}
 	}
-	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 */
+	/* We were not able to determine the required datatype, but we still give the il_operand a chance to be narrowed! */
+	set_il_operand_datatype(il_operand, NULL);
+	return NULL;
+}
+
+
+
+
+/* Narrow IL operators whose execution is conditional on the boolean value in the accumulator.
+ * Basically, narrow the JMPC, JMPCN, RETC, RETCN, CALC, and CALCN operators!
+ * Also does part of the S and R operator narrowing!!!
+ */
+void *narrow_candidate_datatypes_c::narrow_conditional_operator(symbol_c *symbol) {
+	/* if the next IL instructions needs us to provide a datatype other than a BOOL or a SAFEBOOL, 
+	 * then we have an internal compiler error - most likely in fill_candidate_datatypes_c 
+	 */
+	// I (mario) am confident the fill/narrow algorithms are working correctly, so for now we can disable the assertions!
+	//if ((NULL != symbol->datatype) && (!get_datatype_info_c::is_BOOL_compatible(symbol->datatype))) ERROR;
+	//if (symbol->candidate_datatypes.size() > 2) ERROR; /* may contain, at most, a BOOL and a SAFEBOOL */
+
+	/* NOTE: If there is no IL instruction following this S, R, CALC, CALCN, JMPC, JMPCN, RETC, or RETCN 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
+	 * 
+	 * NOTE: Note that this algorithm we are implementing is slightly wrong. 
+	 *        (a) It ignores that a SAFEBOOL may be needed instead of a BOOL datatype. 
+	 *        (b) It also ignores that this method gets to be called twice on the same 
+	 *            object (the narrow algorithm runs through the IL list twice in order to
+	 *            handle forward JMPs), so the assumption that we must immediately set our
+	 *            own datatype if we get called with a NULL symbol->datatype is incorrect 
+	 *           (it may be that the second time it is called it will be with the correct datatype!).
+	 * 
+	 *       These two issues (a) and (b) together means that we should only really be setting our own
+	 *       datatype if we are certain that the following IL instructions will never set it for us
+	 *       - basically if the following IL instruction is a LD, or a JMP to a LD, or a JMP to a JMP to a LD,
+	 *        etc..., or a conditional JMP whose both branches go to LD, etc...!!!
+	 *       
+	 *       At the moment, it seems to me that we would need to write a visitor class to do this for us!
+	 *       I currently have other things on my mind at the moment, so I will leave this for later...
+	 *       For the moment we just set it to BOOL, and ignore the support of SAFEBOOL!
+	 */
+	if (NULL == symbol->datatype) set_datatype(&get_datatype_info_c::bool_type_name /* datatype*/, symbol /* symbol */);
+	if (NULL == symbol->datatype) ERROR; // the BOOL is not on the candidate_datatypes! Strange... Probably a bug in fill_candidate_datatype_c
+
+	/* 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;
+}
+
+
+
+void *narrow_candidate_datatypes_c::narrow_S_and_R_operator(symbol_c *symbol, const char *param_name, symbol_c *called_fb_declaration) {
+	if (NULL != called_fb_declaration) 
+	  /* FB call semantics */  
+	  return narrow_implicit_il_fb_call(symbol, param_name, called_fb_declaration); 
+	
+	/* Set/Reset semantics */  
+	narrow_conditional_operator(symbol);
+	/* set the datatype for the il_operand */
+	if ((NULL != il_operand) && (il_operand->candidate_datatypes.size() > 0))
+		set_il_operand_datatype(il_operand, il_operand->candidate_datatypes[0]);
+	return NULL;
+}
+
+
+
+void *narrow_candidate_datatypes_c::narrow_store_operator(symbol_c *symbol) {
+	if (symbol->candidate_datatypes.size() == 1) {
+		symbol->datatype = symbol->candidate_datatypes[0];
+		/* set the desired datatype of the previous il instruction */
+		set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);
+		/* In the case of the ST operator, we must set the datatype of the il_instruction_c object that points to this ST_operator_c ourselves,
+		 * since the following il_instruction_c objects have not done it, as is normal/standard for other instructions!
+		 */
+		current_il_instruction->datatype = symbol->datatype;
+	}
+	
 	/* 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);
-	/* In the case of the ST operator, we must set the datatype of the il_instruction_c object that points to this ST_operator_c ourselves,
-	 * since the following il_instruction_c objects have not done it, as is normal/standard for other instructions!
-	 */
-	current_il_instruction->datatype = symbol->datatype;
-	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);
-}
-
+	set_il_operand_datatype(il_operand, symbol->datatype);
+	return NULL;
+}
+
+
+
+void *narrow_candidate_datatypes_c::visit(  LD_operator_c *symbol)  {return set_il_operand_datatype(il_operand, symbol->datatype);}
+void *narrow_candidate_datatypes_c::visit( LDN_operator_c *symbol)  {return set_il_operand_datatype(il_operand, symbol->datatype);}
+
+void *narrow_candidate_datatypes_c::visit(  ST_operator_c *symbol)  {return narrow_store_operator(symbol);}
+void *narrow_candidate_datatypes_c::visit( STN_operator_c *symbol)  {return narrow_store_operator(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!
+ *       This error will be detected in print_datatypes_error_c!!
+ */
+/* This operator does not change the data type, it simply inverts the bits in the ANT_BIT data types! */
+/* So, we merely set the desired datatype of the previous il instruction */
+void *narrow_candidate_datatypes_c::visit( NOT_operator_c *symbol)  {set_datatype_in_prev_il_instructions(symbol->datatype, fake_prev_il_instruction);return NULL;}
+
+void *narrow_candidate_datatypes_c::visit(   S_operator_c *symbol)  {return narrow_S_and_R_operator   (symbol, "S",   symbol->called_fb_declaration);}
+void *narrow_candidate_datatypes_c::visit(   R_operator_c *symbol)  {return narrow_S_and_R_operator   (symbol, "R",   symbol->called_fb_declaration);}
 
 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);}
@@ -1239,44 +1313,17 @@
 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) && (!get_datatype_info_c::is_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) && (!get_datatype_info_c::is_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)} */
+/* visitors to CAL_operator_c, CALC_operator_c and CALCN_operator_c are called from visit(il_fb_call_c *) {symbol->il_call_operator->accept(*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);}
+void *narrow_candidate_datatypes_c::visit( CALC_operator_c *symbol) {return narrow_conditional_operator(symbol);}
+void *narrow_candidate_datatypes_c::visit(CALCN_operator_c *symbol) {return narrow_conditional_operator(symbol);}
+void *narrow_candidate_datatypes_c::visit( RETC_operator_c *symbol) {return narrow_conditional_operator(symbol);}
+void *narrow_candidate_datatypes_c::visit(RETCN_operator_c *symbol) {return narrow_conditional_operator(symbol);}
+void *narrow_candidate_datatypes_c::visit( JMPC_operator_c *symbol) {return narrow_conditional_operator(symbol);}
+void *narrow_candidate_datatypes_c::visit(JMPCN_operator_c *symbol) {return narrow_conditional_operator(symbol);}
 
 /* Symbol class handled together with function call checks */
 // void *visit(il_assign_operator_c *symbol, variable_name);
@@ -1313,7 +1360,7 @@
 				l_expr->datatype = l_type;
 				r_expr->datatype = r_type;
 				count ++;
-			} else if ((l_type == r_type) && search_base_type_c::type_is_enumerated(l_type) && get_datatype_info_c::is_BOOL_compatible(symbol->datatype)) {
+			} else if ((l_type == r_type) && get_datatype_info_c::is_enumerated(l_type) && get_datatype_info_c::is_BOOL_compatible(symbol->datatype)) {
 				if (NULL != deprecated_operation)  *deprecated_operation = false;
 				l_expr->datatype = l_type;
 				r_expr->datatype = r_type;
@@ -1469,7 +1516,7 @@
 void *narrow_candidate_datatypes_c::visit(case_statement_c *symbol) {
 	for (unsigned int i = 0; i < symbol->expression->candidate_datatypes.size(); i++) {
 		if ((get_datatype_info_c::is_ANY_INT(symbol->expression->candidate_datatypes[i]))
-				 || (search_base_type_c::type_is_enumerated(symbol->expression->candidate_datatypes[i])))
+				 || (get_datatype_info_c::is_enumerated(symbol->expression->candidate_datatypes[i])))
 			symbol->expression->datatype = symbol->expression->candidate_datatypes[i];
 	}
 	symbol->expression->accept(*this);
--- a/stage3/narrow_candidate_datatypes.hh	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage3/narrow_candidate_datatypes.hh	Wed Feb 19 22:27:11 2014 +0100
@@ -71,20 +71,21 @@
 
     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_spec_init           (symbol_c *symbol, symbol_c *type_decl, symbol_c *init_value);
+    void *narrow_type_decl           (symbol_c *symbol, symbol_c *type_name, symbol_c *spec_init);
+    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 *symbol, const char *param_name, symbol_c *&called_fb_declaration);
+    void *narrow_S_and_R_operator    (symbol_c *symbol, const char *param_name, symbol_c * called_fb_declaration);
+    void *narrow_store_operator      (symbol_c *symbol);
+    void *narrow_conditional_operator(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, bool allow_enums = false);
     void *narrow_equality_comparison(const struct widen_entry widen_table[], symbol_c *symbol, symbol_c *l_expr, symbol_c *r_expr, bool *deprecated_operation = NULL);
 
-    void *narrow_spec_init(symbol_c *symbol, symbol_c *type_decl, symbol_c *init_value);
-    void *narrow_type_decl(symbol_c *symbol, symbol_c *type_name, symbol_c *spec_init);
-
-    void *narrow_conditional_flow_control_IL_instruction(symbol_c *symbol);
+    void *set_il_operand_datatype    (symbol_c *il_operand, symbol_c *datatype);
+
 
 
   public:
@@ -181,6 +182,7 @@
     /*********************/
     /* B 1.4 - Variables */
     /*********************/
+    void *visit(symbolic_variable_c *symbol);
     /********************************************/
     /* B 1.4.1 - Directly Represented Variables */
     /********************************************/
@@ -189,6 +191,7 @@
     /*************************************/
     void *visit(array_variable_c *symbol);
     void *visit(subscript_list_c *symbol);
+    void *visit(structured_variable_c *symbol);
 
     /******************************************/
     /* B 1.4.3 - Declaration & Initialisation */
--- a/stage3/print_datatypes_error.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage3/print_datatypes_error.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -160,7 +160,7 @@
 			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;
@@ -195,7 +195,7 @@
 					}
 				} else ERROR;
 
-				if (NULL == param_value->datatype) {
+				if (!get_datatype_info_c::is_type_valid(param_value->datatype)) {
 					function_invocation_error = true;
 					STAGE3_ERROR(0, param_value, param_value, "Data type incompatibility between parameter '%s' and value being passed, when invoking %s '%s'", ((identifier_c *)param_name)->value, POU_str, ((identifier_c *)fcall_data.function_name)->value);
 					continue; /* jump to next parameter */
@@ -204,7 +204,6 @@
 		}
 	}
 	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! */
@@ -251,10 +250,12 @@
 					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 (!get_datatype_info_c::is_type_valid(param_value->datatype)) {
-					function_invocation_error = true;
-					STAGE3_ERROR(0, param_value, param_value, "Data type incompatibility for value passed in position %d when invoking %s '%s'", i, POU_str, ((identifier_c *)fcall_data.function_name)->value);
+				} else {
+					if (!get_datatype_info_c::is_type_valid(param_value->datatype)) {
+						function_invocation_error = true;
+						STAGE3_ERROR(0, param_value, param_value, "Data type incompatibility for value passed in position %d when invoking %s '%s'", i, POU_str, ((identifier_c *)fcall_data.function_name)->value);
+					}
+					param_value->accept(*this);
 				}
 			}
 	}
@@ -279,7 +280,7 @@
 		STAGE3_ERROR(0, il_operator, il_operator, "Missing operand for FB call operator '%s'.", param_name);
 		return NULL;
 	}
-	il_operand->accept(*this);
+	// il_operand->accept(*this);  // NOT required. The il_simple_operation_c already visits it!!
 	
 	if (NULL == called_fb_declaration) {
 		STAGE3_ERROR(0, il_operator, il_operand, "Invalid FB call: operand is not a FB instance.");
@@ -315,7 +316,7 @@
 	 *       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) {
+	if (!get_datatype_info_c::is_type_valid(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);
@@ -336,7 +337,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "ANY_REAL data type not valid in this location.");
 	}
 	return NULL;
@@ -345,7 +346,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location.");
 	}
 	return NULL;
@@ -354,7 +355,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "ANY_REAL data type not valid in this location.");
 	}
 	return NULL;
@@ -363,7 +364,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location.");
 	}
 	return NULL;
@@ -372,7 +373,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location.");
 	}
 	return NULL;
@@ -381,7 +382,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location.");
 	}
 	return NULL;
@@ -390,7 +391,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location.");
 	}
 	return NULL;
@@ -399,7 +400,7 @@
 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.", get_datatype_info_c::get_id_str(symbol->type));
-	} else if (NULL == symbol->datatype) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "ANY_INT data type not valid in this location.");
 	}
 	return NULL;
@@ -408,7 +409,7 @@
 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.", get_datatype_info_c::get_id_str(symbol->type));
-	} else if (NULL == symbol->datatype) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "ANY_REAL data type not valid in this location.");
 	}
 	return NULL;
@@ -417,7 +418,7 @@
 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.", get_datatype_info_c::get_id_str(symbol->type));
-	} else if (NULL == symbol->datatype) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "ANY_BIT data type not valid in this location.");
 	}
 	return NULL;
@@ -426,7 +427,7 @@
 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.", get_datatype_info_c::get_id_str(symbol->type));
-	} else if (NULL == symbol->datatype) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "ANY_BOOL data type not valid in this location.");
 	}
 	return NULL;
@@ -435,7 +436,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "ANY_BOOL data type not valid in this location.");
 	}
 	return NULL;
@@ -444,7 +445,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "ANY_BOOL data type not valid in this location.");
 	}
 	return NULL;
@@ -456,7 +457,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "WSTRING data type not valid in this location.");
 	}
 	return NULL;
@@ -465,7 +466,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "STRING data type not valid in this location.");
 	}
 	return NULL;
@@ -480,7 +481,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "TIME data type not valid in this location.");
 	}
 	return NULL;
@@ -492,7 +493,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "TOD data type not valid in this location.");
 	}
 	return NULL;
@@ -501,7 +502,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "DATE data type not valid in this location.");
 	}
 	return NULL;
@@ -510,7 +511,7 @@
 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) {
+	} else if (!get_datatype_info_c::is_type_valid(symbol->datatype)) {
 		STAGE3_ERROR(4, symbol, symbol, "DT data type not valid in this location.");
 	}
 	return NULL;
@@ -569,6 +570,10 @@
 /*  subscripted_variable '[' subscript_list ']' */
 // SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
 void *print_datatypes_error_c::visit(array_variable_c *symbol) {
+	/* the subscripted variable may be a structure or another array variable, that must also be visisted! */
+	/* Please read the comments in the array_variable_c and structured_variable_c visitors in the fill_candidate_datatypes.cc file! */
+	symbol->subscripted_variable->accept(*this); 
+	
 	if (symbol->candidate_datatypes.size() == 0)
 		STAGE3_ERROR(0, symbol, symbol, "Array variable not declared in this scope.");
 	
@@ -584,7 +589,7 @@
 		int start_error_count = error_count;
 		symbol->elements[i]->accept(*this);
 		/* The following error message will only get printed if the current_display_error_level is set higher than 0! */
-		if ((start_error_count == error_count) && (NULL == symbol->elements[i]->datatype))
+		if ((start_error_count == error_count) && (!get_datatype_info_c::is_type_valid(symbol->elements[i]->datatype)))
 			STAGE3_ERROR(0, symbol, symbol, "Invalid data type for array subscript field.");
 	}
 	return NULL;
@@ -598,13 +603,13 @@
  *           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) {
+	/* the record variable may be another structure or even an array variable, that must also be visisted! */
+	/* Please read the comments in the array_variable_c and structured_variable_c visitors in the fill_candidate_datatypes.cc file! */
+	symbol->record_variable->accept(*this);
+	
 	if (symbol->candidate_datatypes.size() == 0)
-		STAGE3_ERROR(0, symbol, symbol, "Undeclared structured/FB variable.");
+		STAGE3_ERROR(0, symbol, symbol, "Undeclared structured (or FB) variable, or non-existant field (variable) in structure (FB).");
 	return NULL;
 }
 
@@ -757,10 +762,8 @@
 
 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 */
+	if (NULL != 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;
@@ -929,50 +932,22 @@
 /* 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);
+	if (NULL == il_operand) {
+		STAGE3_ERROR(0, symbol, symbol, "Missing operand for %s operator.", il_operator);		// message (a)
+	} else 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);		// message (b)
+	} else if (NULL == symbol->datatype) {  // do NOT use !get_datatype_info_c::is_type_valid() here!
+		STAGE3_WARNING(symbol, symbol, "Result of '%s' operation is never used.", il_operator);		// message (c)
 	} 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;
-}
+		STAGE3_WARNING(symbol, symbol, "Deprecated operation for '%s' operator.", il_operator);		// message (d)
+	return NULL;
+}
+
+
+void *print_datatypes_error_c::visit(  LD_operator_c *symbol) {return print_binary_operator_errors("LD"  , symbol);}  // I believe it will never emit messages (b) and (c)!!
+void *print_datatypes_error_c::visit( LDN_operator_c *symbol) {return print_binary_operator_errors("LDN" , symbol);}  // I believe it will never emit message (c)
+void *print_datatypes_error_c::visit(  ST_operator_c *symbol) {return print_binary_operator_errors("ST"  , symbol);}  // I believe it will never emit message (c)
+void *print_datatypes_error_c::visit( STN_operator_c *symbol) {return print_binary_operator_errors("STN" , symbol);}  // I believe it will never emit message (c)
 
 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>
@@ -980,27 +955,21 @@
 	 *       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)
+	if (il_operand != NULL) {
 		STAGE3_ERROR(0, symbol, symbol, "'NOT' operator may not have an operand.");
-	if (symbol->candidate_datatypes.size() == 0)
+	} else 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;
+	if (NULL != symbol->called_fb_declaration) /* FB call semantics */  return handle_implicit_il_fb_invocation("S", symbol, symbol->called_fb_declaration);
+	else                                       /* Reset   semantics */  return print_binary_operator_errors    ("S", symbol);
 }
 
 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;
+	if (NULL != symbol->called_fb_declaration) /* FB call semantics */  return handle_implicit_il_fb_invocation("R", symbol, symbol->called_fb_declaration);
+	else                                       /* Reset   semantics */  return print_binary_operator_errors    ("R", symbol);
 }
 
 void *print_datatypes_error_c::visit( S1_operator_c *symbol) {return handle_implicit_il_fb_invocation( "S1", symbol, symbol->called_fb_declaration);}
@@ -1035,7 +1004,7 @@
 
 
 void *print_datatypes_error_c::handle_conditional_flow_control_IL_instruction(symbol_c *symbol, const char *oper) {
-	if (NULL == symbol->datatype)
+	if (!get_datatype_info_c::is_type_valid(symbol->datatype))
 		STAGE3_ERROR(0, symbol, symbol, "%s operator must be preceded by an IL instruction producing a BOOL value.", oper);
 	return NULL;
 }
@@ -1142,10 +1111,10 @@
 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))
+	if ((!get_datatype_info_c::is_type_valid(symbol->l_exp->datatype)) &&
+	    (!get_datatype_info_c::is_type_valid(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;
 }
@@ -1183,8 +1152,8 @@
 
 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)) {
+	if ((!get_datatype_info_c::is_type_valid(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)
@@ -1198,8 +1167,8 @@
 
 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)) {
+	if ((!get_datatype_info_c::is_type_valid(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)
@@ -1210,8 +1179,8 @@
 
 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)) {
+	if ((!get_datatype_info_c::is_type_valid(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);
@@ -1229,24 +1198,24 @@
 	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)) {
+	if ((!get_datatype_info_c::is_type_valid(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)) {
+	if ((!get_datatype_info_c::is_type_valid(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)) {
+	if ((!get_datatype_info_c::is_type_valid(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)) {
+	    (!get_datatype_info_c::is_type_valid(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 */
--- a/stage4/generate_c/generate_c.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage4/generate_c/generate_c.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -340,6 +340,131 @@
 /***********************************************************************/
 /***********************************************************************/
 
+/* A helper class that analyses if the datatype of a variable is 'complex'. */
+/* 'complex' means that it is either a strcuture or an array!               */
+class analyse_variable_c: public search_visitor_c {
+  private:
+    static analyse_variable_c *singleton_;
+
+  public:
+    analyse_variable_c(void) {};
+    
+    static bool is_complex_type(symbol_c *symbol) {
+      if (NULL == symbol) ERROR;
+      if (!get_datatype_info_c::is_type_valid     (symbol->datatype)) ERROR;
+      return (   get_datatype_info_c::is_structure(symbol->datatype) 
+              || get_datatype_info_c::is_array    (symbol->datatype) 
+             );
+    }
+
+    
+  private:
+    symbol_c *last_fb, *first_non_fb_identifier;
+
+  public:  
+    /* returns the first element (from left to right) in a structured variable that is not a FB, i.e. is either a structure or an array! */
+    /* eg:
+     *      fb1.fb2.fb3.real       returns ??????
+     *      fb1.fb2.struct1.real   returns struct1
+     *      struct1.real           returns struct1
+     */
+    static symbol_c *find_first_nonfb(symbol_c *symbol) {
+      if (NULL == singleton_)       singleton_ = new analyse_variable_c();
+      if (NULL == singleton_)       ERROR;
+      if (NULL == symbol)           ERROR;
+      
+      singleton_->last_fb                 = NULL;
+      singleton_->first_non_fb_identifier = NULL;
+      return (symbol_c *)symbol->accept(*singleton_);
+    }
+    
+    /* returns true if a strcutured variable (e.g. fb1.fb2.strcut1.real) contains a structure or array */
+    /* eg:
+     *      fb1.fb2.fb3.real       returns FALSE
+     *      fb1.fb2.struct1.real   returns TRUE
+     *      struct1.real           returns TRUE
+     */
+    static bool contains_complex_type(symbol_c *symbol) {
+      if (NULL == symbol) ERROR;
+      if (!get_datatype_info_c::is_type_valid(symbol->datatype)) ERROR;
+      
+      symbol_c *first_non_fb = (symbol_c *)find_first_nonfb(symbol);
+      return is_complex_type(first_non_fb->datatype);
+    }
+    
+    
+    /* returns the datatype of the variable returned by find_first_nonfb() */
+    /* eg:
+     *      fb1.fb2.fb3.real       returns ??????
+     *      fb1.fb2.struct1.real   returns datatype of struct1
+     *      struct1.real           returns datatype of struct1
+     */
+    static search_var_instance_decl_c::vt_t first_nonfb_vardecltype(symbol_c *symbol, symbol_c *scope) {
+      if (NULL == symbol) ERROR;
+      if (!get_datatype_info_c::is_type_valid(symbol->datatype)) ERROR;
+      
+      symbol_c *first_non_fb = (symbol_c *)find_first_nonfb(symbol);
+      if (NULL != singleton_->last_fb) {
+        scope = singleton_->last_fb->datatype;
+        symbol = singleton_->first_non_fb_identifier;
+      }
+      
+      search_var_instance_decl_c search_var_instance_decl(scope);
+      
+      return search_var_instance_decl.get_vartype(symbol);
+    }
+    
+    
+    /*********************/
+    /* B 1.4 - Variables */
+    /*********************/
+    void *visit(symbolic_variable_c *symbol) {
+      if (!get_datatype_info_c::is_type_valid    (symbol->datatype)) ERROR;
+      if (!get_datatype_info_c::is_function_block(symbol->datatype)) {
+         first_non_fb_identifier = symbol; 
+         return (void *)symbol;
+      }
+      last_fb = symbol;
+      return NULL;
+    }
+    
+    /*************************************/
+    /* B.1.4.2   Multi-element Variables */
+    /*************************************/
+    
+    // SYM_REF2(structured_variable_c, record_variable, field_selector)
+    void *visit(structured_variable_c *symbol) {
+      symbol_c *res = (symbol_c *)symbol->record_variable->accept(*this);
+      if (NULL != res) return res;
+      
+      if (!get_datatype_info_c::is_type_valid    (symbol->datatype)) ERROR;
+      if (!get_datatype_info_c::is_function_block(symbol->datatype)) {
+         first_non_fb_identifier = symbol->field_selector; 
+         return (void *)symbol;
+      }
+
+      last_fb = symbol;      
+      return NULL;      
+    }
+    
+    /*  subscripted_variable '[' subscript_list ']' */
+    //SYM_REF2(array_variable_c, subscripted_variable, subscript_list)
+    void *visit(array_variable_c *symbol) {
+      void *res = symbol->subscripted_variable->accept(*this);
+      if (NULL != res) return res;
+      return (void *)symbol;      
+    }
+
+    
+};
+
+analyse_variable_c *analyse_variable_c::singleton_ = NULL;
+
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+/***********************************************************************/
+
 
 #include "generate_c_st.cc"
 #include "generate_c_il.cc"
@@ -588,15 +713,13 @@
     } inlinearray_mode_t;
 
   private:
-    stage4out_c *s4o_ptr;
     std::map<std::string, int> inline_array_defined;
     std::string current_array_name;
     inlinearray_mode_t current_mode;
 
   public:
     generate_c_datatypes_c(stage4out_c *s4o_ptr, stage4out_c *s4o_incl_ptr)
-      : generate_c_typedecl_c(s4o_ptr, s4o_incl_ptr) {
-      generate_c_datatypes_c::s4o_ptr = s4o_ptr;
+      : generate_c_typedecl_c(s4o_incl_ptr) {
       current_mode = none_im;
     };
     virtual ~generate_c_datatypes_c(void) {
@@ -782,11 +905,20 @@
     void *visit(array_spec_init_c *symbol) {
       switch (current_mode) {
         case arraydeclaration_im:
+          {
+            array_specification_c *specification = dynamic_cast<array_specification_c*>(symbol->array_specification);
+            if (specification != NULL)
+              symbol->array_specification->accept(*this);
+          }
+          break;
         case arrayname_im:
           {
             array_specification_c *specification = dynamic_cast<array_specification_c*>(symbol->array_specification);
             if (specification != NULL)
               symbol->array_specification->accept(*this);
+            identifier_c *name = dynamic_cast<identifier_c*>(symbol->array_specification);
+            if (name != NULL)
+              s4o_incl.print(name->value);
           }
           break;
         default:
@@ -1013,14 +1145,13 @@
 /***********************************************************************/
 
 
-class generate_c_pous_c: public generate_c_typedecl_c {
+class generate_c_pous_c: public generate_c_base_c {
   private:
-    stage4out_c *s4o_ptr;
+    stage4out_c &s4o_incl;
     
   public:
     generate_c_pous_c(stage4out_c *s4o_ptr, stage4out_c *s4o_incl_ptr)
-      : generate_c_typedecl_c(s4o_ptr, s4o_incl_ptr) {
-      generate_c_pous_c::s4o_ptr = s4o_ptr;
+      : generate_c_base_c(s4o_ptr), s4o_incl(*s4o_incl_ptr) {
     };
     virtual ~generate_c_pous_c(void) {}
 
@@ -1054,8 +1185,8 @@
 /********************/
 /* 2.1.6 - Pragmas  */
 /********************/
-void *visit(enable_code_generation_pragma_c * symbol)   {s4o_ptr->enable_output();  return NULL;}
-void *visit(disable_code_generation_pragma_c * symbol)  {s4o_ptr->disable_output(); return NULL;} 
+void *visit(enable_code_generation_pragma_c * symbol)   {s4o.enable_output();  return NULL;}
+void *visit(disable_code_generation_pragma_c * symbol)  {s4o.disable_output(); return NULL;} 
 
 /*************************/
 /* B.1 - Common elements */
@@ -1617,16 +1748,13 @@
 /***********************************************************************/
 /***********************************************************************/
 
-class generate_c_config_c: public generate_c_typedecl_c {
+class generate_c_config_c: public generate_c_base_c {
     private:
-    stage4out_c *s4o_ptr;
-    stage4out_c *s4o_incl_ptr;
+    stage4out_c &s4o_incl;
     
     public:
     generate_c_config_c(stage4out_c *s4o_ptr, stage4out_c *s4o_incl_ptr)
-      : generate_c_typedecl_c(s4o_ptr, s4o_incl_ptr) {
-      generate_c_config_c::s4o_ptr = s4o_ptr;
-      generate_c_config_c::s4o_incl_ptr = s4o_incl_ptr;
+      : generate_c_base_c(s4o_ptr), s4o_incl(*s4o_incl_ptr) {
     };
 
     virtual ~generate_c_config_c(void) {}
@@ -1646,14 +1774,14 @@
 /* 2.1.6 - Pragmas  */
 /********************/
 void *visit(enable_code_generation_pragma_c * symbol)   {
-    s4o_ptr->enable_output();
-    s4o_incl_ptr->enable_output();
+    s4o.enable_output();
+    s4o_incl.enable_output();
     return NULL;
 }
 
 void *visit(disable_code_generation_pragma_c * symbol)  {
-    s4o_ptr->disable_output();
-    s4o_incl_ptr->disable_output();    
+    s4o.disable_output();
+    s4o_incl.disable_output();    
     return NULL;
 }
     
--- a/stage4/generate_c/generate_c_base.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage4/generate_c/generate_c_base.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -227,7 +227,8 @@
           symbol_c *value,
           symbol_c *fb_name = NULL,
           bool temp = false) {
-      bool is_subrange = search_base_type_c::type_is_subrange(type);
+      if (!get_datatype_info_c::is_type_valid(type)) ERROR;
+      bool is_subrange = get_datatype_info_c::is_subrange(type);
       if (is_subrange) {
 		s4o.print("__CHECK_");
 		type->accept(*this);
@@ -582,6 +583,60 @@
 /********************************/
   /* leave for derived classes... */
 
+  
+/* enumerated_type_name '#' identifier */
+void *visit(enumerated_value_c *symbol) {
+  if (NULL == symbol->datatype) {
+    debug_c::print(symbol);
+    ERROR;
+  }
+  
+  symbol_c *type_name = get_datatype_info_c::get_id(symbol->datatype);
+  if (NULL == type_name) {
+    ERROR_MSG("C code generator does not currently support anonymous enumerated data types.");
+  }
+  
+  type_name->accept(*this);
+  s4o.print("__");
+  symbol->value->accept(*this);
+  return NULL;
+}
+
+
+  
+/* NOTE:     visit(subrange_spec_init_c *)
+ *      and  visit(subrange_specification_c *)
+ *      together simply print out the integer datatype
+ *      on which the subrange is based.
+ *
+ *      Future code clean-ups should delete these two
+ *      visit mehotds, and make sure whoever calls them 
+ *      uses symbol->datatype instead!
+ */ 
+/* subrange_specification ASSIGN signed_integer */
+void *visit(subrange_spec_init_c *symbol) {
+  TRACE("subrange_spec_init_c");
+  symbol->subrange_specification->accept(*this);
+  return NULL;
+}
+
+/*  integer_type_name '(' subrange')' */
+void *visit(subrange_specification_c *symbol) {
+  TRACE("subrange_specification_c");
+  symbol->integer_type_name->accept(*this);
+  return NULL;
+}
+  
+  
+/* helper symbol for array_specification */
+/* array_subrange_list ',' subrange */
+void *visit(array_subrange_list_c *symbol) {
+  TRACE("array_subrange_list_c");
+  print_list(symbol);
+  return NULL;
+}  
+  
+  
 /*********************/
 /* B 1.4 - Variables */
 /*********************/
--- a/stage4/generate_c/generate_c_il.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage4/generate_c/generate_c_il.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -126,7 +126,7 @@
 
 
 
-class generate_c_il_c: public generate_c_typedecl_c, il_default_variable_visitor_c {
+class generate_c_il_c: public generate_c_base_c, il_default_variable_visitor_c {
 
   public:
     typedef enum {
@@ -197,7 +197,7 @@
 
   public:
     generate_c_il_c(stage4out_c *s4o_ptr, symbol_c *name, symbol_c *scope, const char *variable_prefix = NULL)
-    : generate_c_typedecl_c(s4o_ptr),
+    : generate_c_base_c(s4o_ptr),
       implicit_variable_current    (IL_DEFVAR,      NULL),
       implicit_variable_result     (IL_DEFVAR,      NULL),
       implicit_variable_result_back(IL_DEFVAR_BACK, NULL)
@@ -367,7 +367,8 @@
       unsigned int vartype = search_var_instance_decl->get_vartype(symbol);
       if (wanted_variablegeneration == fparam_output_vg) {
         if (vartype == search_var_instance_decl_c::external_vt) {
-          if (search_var_instance_decl->type_is_fb(symbol))
+          if (!get_datatype_info_c::is_type_valid    (symbol->datatype)) ERROR;
+          if ( get_datatype_info_c::is_function_block(symbol->datatype))
             s4o.print(GET_EXTERNAL_FB_BY_REF);
           else
             s4o.print(GET_EXTERNAL_BY_REF);
@@ -379,7 +380,8 @@
       }
       else {
         if (vartype == search_var_instance_decl_c::external_vt) {
-          if (search_var_instance_decl->type_is_fb(symbol))
+          if (!get_datatype_info_c::is_type_valid    (symbol->datatype)) ERROR;
+          if ( get_datatype_info_c::is_function_block(symbol->datatype))
             s4o.print(GET_EXTERNAL_FB);
           else
             s4o.print(GET_EXTERNAL);
@@ -394,8 +396,7 @@
       variablegeneration_t old_wanted_variablegeneration = wanted_variablegeneration;
       wanted_variablegeneration = complextype_base_vg;
       symbol->accept(*this);
-      if (search_var_instance_decl->type_is_complex(symbol))
-        s4o.print(",");
+      s4o.print(",");
       wanted_variablegeneration = complextype_suffix_vg;
       symbol->accept(*this);
       s4o.print(")");
@@ -410,11 +411,13 @@
             symbol_c* fb_value = NULL,
             bool negative = false) {
 
-      bool type_is_complex = search_var_instance_decl->type_is_complex(symbol);
+      bool type_is_complex = false;
       if (fb_symbol == NULL) {
         unsigned int vartype = search_var_instance_decl->get_vartype(symbol);
+        type_is_complex = analyse_variable_c::contains_complex_type(symbol);
         if (vartype == search_var_instance_decl_c::external_vt) {
-          if (search_var_instance_decl->type_is_fb(symbol))
+          if (!get_datatype_info_c::is_type_valid    (symbol->datatype)) ERROR;
+          if ( get_datatype_info_c::is_function_block(symbol->datatype))
             s4o.print(SET_EXTERNAL_FB);
           else
             s4o.print(SET_EXTERNAL);
@@ -446,7 +449,7 @@
       symbol->accept(*this);
       s4o.print(",");
       if (negative) {
-	    if (get_datatype_info_c::is_BOOL_compatible(this->current_operand->datatype))
+        if (get_datatype_info_c::is_BOOL_compatible(this->current_operand->datatype))
           s4o.print("!");
         else
           s4o.print("~");
@@ -572,7 +575,7 @@
 // SYM_REF2(structured_variable_c, record_variable, field_selector)
 void *visit(structured_variable_c *symbol) {
   TRACE("structured_variable_c");
-  bool type_is_complex = search_var_instance_decl->type_is_complex(symbol->record_variable);
+  bool type_is_complex = analyse_variable_c::is_complex_type(symbol->record_variable);
   switch (wanted_variablegeneration) {
     case complextype_base_vg:
     case complextype_base_assignment_vg:
@@ -839,6 +842,14 @@
       break;
     }
     
+    /* We do not yet support embedded IL lists, so we abort the compiler if we find one */
+    /* Note that in IL function calls the syntax does not allow embeded IL lists, so this check is not necessary here! */
+    /*
+    {simple_instr_list_c *instruction_list = dynamic_cast<simple_instr_list_c *>(param_value);
+     if (NULL != instruction_list) STAGE4_ERROR(param_value, param_value, "The compiler does not yet support formal invocations in IL that contain embedded IL lists. Aborting!");
+    }
+    */
+    
     if ((param_value == NULL) && (param_direction == function_param_iterator_c::direction_in)) {
       /* No value given for parameter, so we must use the default... */
       /* First check whether default value specified in function declaration...*/
@@ -1060,6 +1071,11 @@
     if ((param_value == NULL) && !fp_iterator.is_en_eno_param_implicit())
       param_value = function_call_param_iterator.next_nf();
 
+    /* We do not yet support embedded IL lists, so we abort the compiler if we find one */
+    {simple_instr_list_c *instruction_list = dynamic_cast<simple_instr_list_c *>(param_value);
+     if (NULL != instruction_list) STAGE4_ERROR(param_value, param_value, "The compiler does not yet support formal invocations in IL that contain embedded IL lists. Aborting!");
+    }
+    
     symbol_c *param_type = fp_iterator.param_type();
     if (param_type == NULL) ERROR;
     
@@ -1228,6 +1244,11 @@
       break;
     }
     
+    /* We do not yet support embedded IL lists, so we abort the compiler if we find one */
+    {simple_instr_list_c *instruction_list = dynamic_cast<simple_instr_list_c *>(param_value);
+     if (NULL != instruction_list) STAGE4_ERROR(param_value, param_value, "The compiler does not yet support formal invocations in IL that contain embedded IL lists. Aborting!");
+    }
+    
     if ((param_value == NULL) && (param_direction == function_param_iterator_c::direction_in)) {
       /* No value given for parameter, so we must use the default... */
       /* First check whether default value specified in function declaration...*/
@@ -1530,6 +1551,16 @@
 
 
 void *visit(S_operator_c *symbol) {
+  /* This operator must implement one of two possible semantics: 
+   *     - FB call
+   *     - Set all the bits of an ANY_BIT type variable to 1
+   */
+  
+  /* Check whether we must implement the FB call semantics... */
+  if (NULL != symbol->called_fb_declaration)
+    return XXX_CAL_operator( "S", this->current_operand);
+  
+  /* Implement the bit setting semantics... */
   if (wanted_variablegeneration != expression_vg) {
     s4o.print("LD");
     return NULL;
@@ -1552,6 +1583,16 @@
 
 
 void *visit(R_operator_c *symbol) {
+  /* This operator must implement one of two possible semantics: 
+   *     - FB call
+   *     - Set all the bits of an ANY_BIT type variable to 0
+   */
+  
+  /* Check whether we must implement the FB call semantics... */
+  if (NULL != symbol->called_fb_declaration)
+    return XXX_CAL_operator( "R", this->current_operand);
+  
+  /* Implement the bit setting semantics... */
   if (wanted_variablegeneration != expression_vg) {
     s4o.print("LD");
     return NULL;
--- a/stage4/generate_c/generate_c_inlinefcall.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage4/generate_c/generate_c_inlinefcall.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -26,7 +26,7 @@
 #define INLINE_RESULT_TEMP_VAR "__res"
 #define INLINE_PARAM_COUNT "__PARAM_COUNT"
 
-class generate_c_inlinefcall_c: public generate_c_typedecl_c {
+class generate_c_inlinefcall_c: public generate_c_base_c {
 
   public:
     typedef enum {
@@ -76,7 +76,7 @@
 
   public:
     generate_c_inlinefcall_c(stage4out_c *s4o_ptr, symbol_c *name, symbol_c *scope, const char *variable_prefix = NULL)
-    : generate_c_typedecl_c(s4o_ptr),
+    : generate_c_base_c(s4o_ptr),
       implicit_variable_current(IL_DEFVAR, NULL)
     {
       search_varfb_instance_type = new search_varfb_instance_type_c(scope);
@@ -243,7 +243,8 @@
     void *print_getter(symbol_c *symbol) {
       unsigned int vartype = search_var_instance_decl->get_vartype(symbol);
       if (vartype == search_var_instance_decl_c::external_vt) {
-        if (search_var_instance_decl->type_is_fb(symbol))
+        if (!get_datatype_info_c::is_type_valid    (symbol->datatype)) ERROR;
+        if ( get_datatype_info_c::is_function_block(symbol->datatype))
           s4o.print(GET_EXTERNAL_FB);
         else
           s4o.print(GET_EXTERNAL);
@@ -256,8 +257,7 @@
 
       wanted_variablegeneration = complextype_base_vg;
       symbol->accept(*this);
-      if (search_var_instance_decl->type_is_complex(symbol))
-        s4o.print(",");
+      s4o.print(",");
       wanted_variablegeneration = complextype_suffix_vg;
       symbol->accept(*this);
       s4o.print(")");
@@ -270,7 +270,8 @@
                        symbol_c* value) {
       unsigned int vartype = search_var_instance_decl->get_vartype(symbol);
       if (vartype == search_var_instance_decl_c::external_vt) {
-        if (search_var_instance_decl->type_is_fb(symbol))
+        if (!get_datatype_info_c::is_type_valid    (symbol->datatype)) ERROR;
+        if ( get_datatype_info_c::is_function_block(symbol->datatype))
           s4o.print(SET_EXTERNAL_FB);
          else
           s4o.print(SET_EXTERNAL);
@@ -286,7 +287,7 @@
       s4o.print(",");
       wanted_variablegeneration = expression_vg;
       print_check_function(type, value, NULL, true);
-      if (search_var_instance_decl->type_is_complex(symbol)) {
+      if (analyse_variable_c::contains_complex_type(symbol)) {
         s4o.print(",");
         wanted_variablegeneration = complextype_suffix_vg;
         symbol->accept(*this);
@@ -337,7 +338,7 @@
     // SYM_REF2(structured_variable_c, record_variable, field_selector)
     void *visit(structured_variable_c *symbol) {
       TRACE("structured_variable_c");
-      bool type_is_complex = search_var_instance_decl->type_is_complex(symbol->record_variable);
+      bool type_is_complex = analyse_variable_c::is_complex_type(symbol->record_variable);
       if (generating_inlinefunction) {
         switch (wanted_variablegeneration) {
           case complextype_base_vg:
@@ -512,6 +513,14 @@
           break;
         }
       
+        /* We do not yet support embedded IL lists, so we abort the compiler if we find one */
+        /* Note that in IL function calls the syntax does not allow embeded IL lists, so this check is not necessary here! */
+        /*
+        {simple_instr_list_c *instruction_list = dynamic_cast<simple_instr_list_c *>(param_value);
+         if (NULL != instruction_list) STAGE4_ERROR(param_value, param_value, "The compiler does not yet support formal invocations in IL that contain embedded IL lists. Aborting!");
+        }
+        */
+
         if ((param_value == NULL) && (param_direction == function_param_iterator_c::direction_in)) {
           /* No value given for parameter, so we must use the default... */
           /* First check whether default value specified in function declaration...*/
@@ -669,7 +678,12 @@
         if ((param_value == NULL) && (fp_iterator.is_extensible_param())) {
           break;
         }
-    
+        
+        /* We do not yet support embedded IL lists, so we abort the compiler if we find one */
+        {simple_instr_list_c *instruction_list = dynamic_cast<simple_instr_list_c *>(param_value);
+         if (NULL != instruction_list) STAGE4_ERROR(param_value, param_value, "The compiler does not yet support formal invocations in IL that contain embedded IL lists. Aborting!");
+        }
+
         if ((param_value == NULL) && (param_direction == function_param_iterator_c::direction_in)) {
           /* No value given for parameter, so we must use the default... */
           /* First check whether default value specified in function declaration...*/
--- a/stage4/generate_c/generate_c_sfc.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage4/generate_c/generate_c_sfc.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -657,7 +657,7 @@
 /***********************************************************************/
 /***********************************************************************/
 
-class generate_c_sfc_c: public generate_c_typedecl_c {
+class generate_c_sfc_c: public generate_c_base_c {
   
   private:
     std::list<VARIABLE> variable_list;
@@ -667,7 +667,7 @@
     
   public:
     generate_c_sfc_c(stage4out_c *s4o_ptr, symbol_c *name, symbol_c *scope, const char *variable_prefix = NULL)
-    : generate_c_typedecl_c(s4o_ptr) {
+    : generate_c_base_c(s4o_ptr) {
       generate_c_sfc_elements = new generate_c_sfc_elements_c(s4o_ptr, name, scope, variable_prefix);
       search_var_instance_decl = new search_var_instance_decl_c(scope);
       this->set_variable_prefix(variable_prefix);
--- a/stage4/generate_c/generate_c_sfcdecl.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage4/generate_c/generate_c_sfcdecl.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -32,7 +32,7 @@
 /***********************************************************************/
 /***********************************************************************/
 
-class generate_c_sfcdecl_c: protected generate_c_typedecl_c {
+class generate_c_sfcdecl_c: protected generate_c_base_c {
   
   public:
       typedef enum {
@@ -59,7 +59,7 @@
     
   public:
     generate_c_sfcdecl_c(stage4out_c *s4o_ptr, symbol_c *scope, const char *variable_prefix = NULL)
-    : generate_c_typedecl_c(s4o_ptr) {
+    : generate_c_base_c(s4o_ptr) {
       this->set_variable_prefix(variable_prefix);
       search_var_instance_decl = new search_var_instance_decl_c(scope);
     }
--- a/stage4/generate_c/generate_c_st.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage4/generate_c/generate_c_st.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -44,7 +44,7 @@
 /***********************************************************************/
 
 
-class generate_c_st_c: public generate_c_typedecl_c {
+class generate_c_st_c: public generate_c_base_c {
 
   public:
     typedef enum {
@@ -76,10 +76,11 @@
      * so we do not create an object instance when handling
      * a function declaration.
      */
-    search_fb_instance_decl_c *search_fb_instance_decl;
-
+    search_fb_instance_decl_c    *search_fb_instance_decl;
     search_varfb_instance_type_c *search_varfb_instance_type;
     search_var_instance_decl_c   *search_var_instance_decl;
+    
+    symbol_c *scope_;
 
     symbol_c* current_array_type;
     symbol_c* current_param_type;
@@ -94,10 +95,11 @@
 
   public:
     generate_c_st_c(stage4out_c *s4o_ptr, symbol_c *name, symbol_c *scope, const char *variable_prefix = NULL)
-    : generate_c_typedecl_c(s4o_ptr) {
+    : generate_c_base_c(s4o_ptr) {
       search_fb_instance_decl    = new search_fb_instance_decl_c   (scope);
       search_varfb_instance_type = new search_varfb_instance_type_c(scope);
       search_var_instance_decl   = new search_var_instance_decl_c  (scope);
+      scope_ = scope;
       
       this->set_variable_prefix(variable_prefix);
       current_array_type = NULL;
@@ -128,10 +130,11 @@
 
 
 void *print_getter(symbol_c *symbol) {
-  unsigned int vartype = search_var_instance_decl->get_vartype(symbol);
+  unsigned int vartype = analyse_variable_c::first_nonfb_vardecltype(symbol, scope_);
   if (wanted_variablegeneration == fparam_output_vg) {
     if (vartype == search_var_instance_decl_c::external_vt) {
-      if (search_var_instance_decl->type_is_fb(symbol))
+      if (!get_datatype_info_c::is_type_valid    (symbol->datatype)) ERROR;
+      if ( get_datatype_info_c::is_function_block(symbol->datatype))
         s4o.print(GET_EXTERNAL_FB_BY_REF);
       else
         s4o.print(GET_EXTERNAL_BY_REF);
@@ -143,7 +146,8 @@
   }
   else {
     if (vartype == search_var_instance_decl_c::external_vt) {
-      if (search_var_instance_decl->type_is_fb(symbol))
+      if (!get_datatype_info_c::is_type_valid    (symbol->datatype)) ERROR;
+      if ( get_datatype_info_c::is_function_block(symbol->datatype))
         s4o.print(GET_EXTERNAL_FB);
       else
         s4o.print(GET_EXTERNAL);
@@ -158,8 +162,7 @@
   variablegeneration_t old_wanted_variablegeneration = wanted_variablegeneration;
   wanted_variablegeneration = complextype_base_vg;
   symbol->accept(*this);
-  if (search_var_instance_decl->type_is_complex(symbol))
-    s4o.print(",");
+  s4o.print(",");
   wanted_variablegeneration = complextype_suffix_vg;
   symbol->accept(*this);
   s4o.print(")");
@@ -167,6 +170,8 @@
   return NULL;
 }
 
+
+
 void *print_setter(symbol_c* symbol,
         symbol_c* type,
         symbol_c* value,
@@ -175,10 +180,11 @@
   
   bool type_is_complex = false;
   if (fb_symbol == NULL) {
-    unsigned int vartype = search_var_instance_decl->get_vartype(symbol);
-    type_is_complex = search_var_instance_decl->type_is_complex(symbol);
+    unsigned int vartype = analyse_variable_c::first_nonfb_vardecltype(symbol, scope_);
+    type_is_complex = analyse_variable_c::contains_complex_type(symbol);
     if (vartype == search_var_instance_decl_c::external_vt) {
-      if (search_var_instance_decl->type_is_fb(symbol))
+      if (!get_datatype_info_c::is_type_valid    (symbol->datatype)) ERROR;
+      if ( get_datatype_info_c::is_function_block(symbol->datatype))
         s4o.print(SET_EXTERNAL_FB);
       else
         s4o.print(SET_EXTERNAL);
@@ -328,7 +334,7 @@
 // SYM_REF2(structured_variable_c, record_variable, field_selector)
 void *visit(structured_variable_c *symbol) {
   TRACE("structured_variable_c");
-  bool type_is_complex = search_var_instance_decl->type_is_complex(symbol->record_variable);
+  bool type_is_complex = analyse_variable_c::is_complex_type(symbol->record_variable);
   switch (wanted_variablegeneration) {
     case complextype_base_vg:
     case complextype_base_assignment_vg:
@@ -858,20 +864,20 @@
 
 
 /* fb_name '(' [param_assignment_list] ')' */
-/* param_assignment_list -> may be NULL ! */
-//SYM_REF2(fb_invocation_c, 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 *visit(fb_invocation_c *symbol) {
   TRACE("fb_invocation_c");
-  /* first figure out what is the name of the function block type of the function block being called... */
-  symbol_c *function_block_type_name = this->search_fb_instance_decl->get_type_name(symbol->fb_name);
-    /* should never occur. The function block instance MUST have been declared... */
-  if (function_block_type_name == NULL) ERROR;
-
-  /* Now find the declaration of the function block type being called... */
-  function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(function_block_type_name);
-    /* should never occur. The function block type being called MUST be in the symtable... */
-  if (fb_decl == function_block_type_symtable.end_value()) ERROR;
-
+  
+  /* find the declaration of the function block type being called... */
+  symbol_c *fb_decl = symbol->called_fb_declaration;
+  if (fb_decl == NULL) ERROR;
+  /* figure out the name of the function block type of the function block being called... */
+  symbol_c *function_block_type_name = get_datatype_info_c::get_id(fb_decl);
+  if (NULL == function_block_type_name) ERROR;
+  
   /* loop through each function block parameter, find the value we should pass
    * to it, and then output the c equivalent...
    */
--- a/stage4/generate_c/generate_c_typedecl.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage4/generate_c/generate_c_typedecl.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -31,16 +31,9 @@
   private:
     symbol_c* current_type_name;
     bool array_is_derived;
-
     generate_c_base_c *basedecl;
 
   public:
-    generate_c_typedecl_c(stage4out_c *s4o_ptr, stage4out_c *s4o_incl_ptr): generate_c_base_c(s4o_ptr), s4o_incl(*s4o_incl_ptr) {
-      current_typedefinition = none_td;
-      current_basetypedeclaration = none_bd;
-      current_type_name = NULL;
-      basedecl = new generate_c_base_c(&s4o_incl);
-    }
     generate_c_typedecl_c(stage4out_c *s4o_ptr): generate_c_base_c(s4o_ptr), s4o_incl(*s4o_ptr) {
       current_typedefinition = none_td;
       current_basetypedeclaration = none_bd;
@@ -98,9 +91,6 @@
       return NULL;
     }
 
-    bool type_is_fb(symbol_c* type_decl) {
-      return search_base_type_c::type_is_fb(type_decl);
-    }
 
 /***************************/
 /* B 0 - Programming Model */
@@ -193,6 +183,7 @@
 
 /*  integer_type_name '(' subrange')' */
 void *visit(subrange_specification_c *symbol) {
+  TRACE("subrange_specification_c");
   if (current_typedefinition == subrange_td) {
     switch (current_basetypedeclaration) {
       case subrangebasetype_bd:
@@ -200,45 +191,52 @@
         break;
       case subrangetest_bd:
         if (symbol->subrange != NULL) {
-          current_type_name->accept(*this);
-          s4o.print(" __CHECK_");
-          current_type_name->accept(*this);
-          s4o.print("(");
-          current_type_name->accept(*this);
-          s4o.print(" value) {\n");
-          s4o.indent_right();
-
-          if (search_base_type_c::type_is_subrange(symbol->integer_type_name)) {
-            s4o.print(s4o.indent_spaces + "value = __CHECK_");
+          s4o_incl.print("static inline ");
+          current_type_name->accept(*basedecl);
+          s4o_incl.print(" __CHECK_");
+          current_type_name->accept(*basedecl);
+          s4o_incl.print("(");
+          current_type_name->accept(*basedecl);
+          s4o_incl.print(" value) {\n");
+          s4o_incl.indent_right();
+
+          /* NOTE: IEC 61131-3 v2 syntax mandates that the integer type name be one of SINT, ..., LINT, USINT, ... ULIT */
+          /*       For this reason, the following condition will always be false, and therefore this is a block
+           *       of dead code. However, let's not delete it for now. It might come in useful for IEC 61131-3 v3.
+           *       For the moment, we just comment it out!
+           */
+          /*
+          if (get_datatype_info_c::is_subrange(symbol->integer_type_name)) {
+            s4o_incl.print(s4o_incl.indent_spaces + "value = __CHECK_");
             symbol->integer_type_name->accept(*this);
-            s4o.print("(value);\n");
+            s4o_incl.print("(value);\n");
           }
+          */
 
           symbol->subrange->accept(*this);
 
-          s4o.indent_left();
-          s4o.print("}\n");
+          s4o_incl.indent_left();
+          s4o_incl.print("}\n");
         }
         else {
-          s4o.print("#define __CHECK_");
-          current_type_name->accept(*this);
-          s4o.print(" __CHECK_");
-          symbol->integer_type_name->accept(*this);
-          s4o.print("\n");
+          s4o_incl.print("#define __CHECK_");
+          current_type_name->accept(*basedecl);
+          s4o_incl.print(" __CHECK_");
+          symbol->integer_type_name->accept(*basedecl);
+          s4o_incl.print("\n");
         }
         break;
       default:
         break;
     }
   }
-  else {
-    symbol->integer_type_name->accept(*basedecl);
-  }
-  return NULL;
-}
+  return NULL;
+}
+
 
 /*  signed_integer DOTDOT signed_integer */
 void *visit(subrange_c *symbol) {
+  TRACE("subrange_c");
   int dimension;
   switch (current_typedefinition) {
     case array_td:
@@ -251,26 +249,26 @@
         symbol->lower_limit->accept(*this);
       break;
     case subrange_td:
-      s4o.print(s4o.indent_spaces + "if (value < ");
-      symbol->lower_limit->accept(*this);
-      s4o.print(")\n");
-      s4o.indent_right();
-      s4o.print(s4o.indent_spaces + "return ");
-      symbol->lower_limit->accept(*this);
-      s4o.print(";\n");
-      s4o.indent_left();
-      s4o.print(s4o.indent_spaces + "else if (value > ");
-      symbol->upper_limit->accept(*this);
-      s4o.print(")\n");
-      s4o.indent_right();
-      s4o.print(s4o.indent_spaces + "return ");
-      symbol->upper_limit->accept(*this);
-      s4o.print(";\n");
-      s4o.indent_left();
-      s4o.print(s4o.indent_spaces + "else\n");
-      s4o.indent_right();
-      s4o.print(s4o.indent_spaces + "return value;\n");
-      s4o.indent_left();
+      s4o_incl.print(s4o_incl.indent_spaces + "if (value < ");
+      symbol->lower_limit->accept(*basedecl);
+      s4o_incl.print(")\n");
+      s4o_incl.indent_right();
+      s4o_incl.print(s4o_incl.indent_spaces + "return ");
+      symbol->lower_limit->accept(*basedecl);
+      s4o_incl.print(";\n");
+      s4o_incl.indent_left();
+      s4o_incl.print(s4o_incl.indent_spaces + "else if (value > ");
+      symbol->upper_limit->accept(*basedecl);
+      s4o_incl.print(")\n");
+      s4o_incl.indent_right();
+      s4o_incl.print(s4o_incl.indent_spaces + "return ");
+      symbol->upper_limit->accept(*basedecl);
+      s4o_incl.print(";\n");
+      s4o_incl.indent_left();
+      s4o_incl.print(s4o_incl.indent_spaces + "else\n");
+      s4o_incl.indent_right();
+      s4o_incl.print(s4o_incl.indent_spaces + "return value;\n");
+      s4o_incl.indent_left();
     default:
       break;
   }
@@ -311,29 +309,15 @@
 /* helper symbol for enumerated_specification->enumerated_spec_init */
 /* enumerated_value_list ',' enumerated_value */
 void *visit(enumerated_value_list_c *symbol) {
+  TRACE("enumerated_value_list_c");
   print_list_incl(symbol, s4o_incl.indent_spaces, ",\n"+s4o_incl.indent_spaces, "\n");
   return NULL;
 }
 
 /* enumerated_type_name '#' identifier */
-void *visit(enumerated_value_c *symbol) {
-  if (current_typedefinition == enumerated_td)
-    current_type_name->accept(*basedecl);
-  else {
-    if (NULL == symbol->datatype) {
-      debug_c::print(symbol);
-      ERROR;
-    }
-    symbol_c *type_name = get_datatype_info_c::get_id(symbol->datatype);
-    if (NULL == type_name) {
-//       ERROR_MSG("generate_c does not support anonymous enumerated data types.");
-    } else
-    type_name->accept(*basedecl);
-  }
-  s4o_incl.print("__");
-  symbol->value->accept(*basedecl);
-  return NULL;
-}
+/* Handled by generate_c_base_c class!!
+void *visit(enumerated_value_c *symbol) {}
+*/
 
 /*  identifier ':' array_spec_init */
 void *visit(array_type_declaration_c *symbol) {
@@ -396,6 +380,7 @@
 
 /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */
 void *visit(array_specification_c *symbol) {
+  TRACE("array_specification_c");
   switch (current_basetypedeclaration) {
     case arraybasetype_bd:
       symbol->non_generic_type_name->accept(*this);
@@ -412,18 +397,12 @@
   return NULL;
 }
 
-/* helper symbol for array_specification */
-/* array_subrange_list ',' subrange */
-void *visit(array_subrange_list_c *symbol) {
-  print_list(symbol);
-  return NULL;
-}
 
 /*  TYPE type_declaration_list END_TYPE */
 void *visit(data_type_declaration_c *symbol) {
   TRACE("data_type_declaration_c");
   symbol->type_declaration_list->accept(*this);
-  s4o.print("\n\n");
+  s4o_incl.print("\n\n");
   return NULL;
 }
 
@@ -443,12 +422,12 @@
   symbol->simple_spec_init->accept(*this);
   s4o_incl.print(")\n");
 
-  if (search_base_type_c::type_is_subrange(symbol->simple_type_name)) {
-    s4o.print("#define __CHECK_");
-    current_type_name->accept(*this);
-    s4o.print(" __CHECK_");
+  if (get_datatype_info_c::is_subrange(symbol->simple_type_name)) {
+    s4o_incl.print("#define __CHECK_");
+    current_type_name->accept(*basedecl);
+    s4o_incl.print(" __CHECK_");
     symbol->simple_spec_init->accept(*this);
-    s4o.print("\n");
+    s4o_incl.print("\n");
   }
 
   return NULL;
@@ -568,7 +547,7 @@
   s4o_incl.print(" ");
   symbol->structure_element_name->accept(*basedecl);
   s4o_incl.print(";\n");
-  s4o_incl.print(s4o.indent_spaces);
+  s4o_incl.print(s4o_incl.indent_spaces);
 
   return NULL;
 }
--- a/stage4/generate_c/generate_c_vardecl.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage4/generate_c/generate_c_vardecl.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -1851,7 +1851,8 @@
    */
   this->current_var_type_symbol = symbol->specification;
   this->current_var_init_symbol = NULL;
-  bool is_fb = type_is_fb(this->current_var_type_symbol);
+  if(!get_datatype_info_c::is_type_valid(this->current_var_type_symbol)) ERROR;
+  bool is_fb = get_datatype_info_c::is_function_block(this->current_var_type_symbol);
 
   /* now to produce the c equivalent... */
   switch (wanted_varformat) {
@@ -2071,7 +2072,8 @@
 void *visit(global_var_list_c *symbol) {
   TRACE("global_var_list_c");
   list_c *list = dynamic_cast<list_c *>(symbol);
-  bool is_fb = type_is_fb(this->current_var_type_symbol);
+  if(!get_datatype_info_c::is_type_valid(this->current_var_type_symbol)) ERROR;
+  bool is_fb = get_datatype_info_c::is_function_block(this->current_var_type_symbol);
   /* should NEVER EVER occur!! */
   if (list == NULL) ERROR;
 
--- a/stage4/generate_iec/generate_iec.cc	Wed Feb 19 22:25:10 2014 +0100
+++ b/stage4/generate_iec/generate_iec.cc	Wed Feb 19 22:27:11 2014 +0100
@@ -1422,6 +1422,10 @@
 }
 
 
+/* intermediate helper symbol for configuration_declaration  */
+/*  { global_var_declarations_list }   */
+void *visit(global_var_declarations_list_c *symbol) {return print_list(symbol);}
+
 /* helper symbol for configuration_declaration */
 /*| resource_declaration_list resource_declaration */
 void *visit(resource_declaration_list_c *symbol) {return print_list(symbol);}