merge
authorMario de Sousa <msousa@fe.up.pt>
Mon, 26 Nov 2012 16:38:15 +0000
changeset 755 7b90dd17f0ba
parent 752 8f05bde3efa8 (diff)
parent 754 36f91a5e4fc8 (current diff)
child 756 634f476cb60f
merge
--- a/absyntax/absyntax.def	Fri Nov 23 11:38:57 2012 +0100
+++ b/absyntax/absyntax.def	Mon Nov 26 16:38:15 2012 +0000
@@ -114,7 +114,8 @@
 /***************************/
 /* B 0 - Programming Model */
 /***************************/
-SYM_LIST(library_c)
+/* enumvalue_symtable is filled in by enum_declaration_check_c, during stage3 semantic verification, with a list of all enumerated constants declared inside this POU */
+SYM_LIST(library_c, enumvalue_symtable_t enumvalue_symtable;)
 
 
 /*************************/
@@ -701,7 +702,8 @@
 /***********************/
 /* B 1.5.1 - Functions */
 /***********************/
-SYM_REF4(function_declaration_c, derived_function_name, type_name, var_declarations_list, function_body)
+/* 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_REF4(function_declaration_c, derived_function_name, type_name, var_declarations_list, function_body, enumvalue_symtable_t enumvalue_symtable;)
 
 /* intermediate helper symbol for
  * - function_declaration
@@ -721,7 +723,8 @@
 /* B 1.5.2 - Function Blocks */
 /*****************************/
 /*  FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */
-SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body)
+/* enumvalue_symtable is filled in by enum_declaration_check_c, during stage3 semantic verification, with a list of all enumerated constants declared inside this POU */
+SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body, enumvalue_symtable_t enumvalue_symtable;)
 
 /* intermediate helper symbol for function_declaration */
 /*  { io_var_declarations | other_var_declarations }   */
@@ -743,7 +746,8 @@
 /* B 1.5.3 - Programs */
 /**********************/
 /*  PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */
-SYM_REF3(program_declaration_c, program_type_name, var_declarations, function_block_body)
+/* enumvalue_symtable is filled in by enum_declaration_check_c, during stage3 semantic verification, with a list of all enumerated constants declared inside this POU */
+SYM_REF3(program_declaration_c, program_type_name, var_declarations, function_block_body, enumvalue_symtable_t enumvalue_symtable;)
 
 /* intermediate helper symbol for program_declaration_c */
 /*  { io_var_declarations | other_var_declarations }   */
@@ -826,7 +830,8 @@
    optional_instance_specific_initializations
 END_CONFIGURATION
 */
-SYM_REF5(configuration_declaration_c, configuration_name, global_var_declarations, resource_declarations, access_declarations, instance_specific_initializations)
+/* 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;)
 
 /* helper symbol for configuration_declaration */
 SYM_LIST(resource_declaration_list_c)
@@ -837,7 +842,8 @@
    single_resource_declaration
 END_RESOURCE
 */
-SYM_REF4(resource_declaration_c, resource_name, resource_type_name, global_var_declarations, resource_declaration)
+/* 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_REF4(resource_declaration_c, resource_name, resource_type_name, global_var_declarations, resource_declaration, enumvalue_symtable_t enumvalue_symtable;)
 
 /* task_configuration_list program_configuration_list */
 SYM_REF2(single_resource_declaration_c, task_configuration_list, program_configuration_list)
--- a/absyntax/absyntax.hh	Fri Nov 23 11:38:57 2012 +0100
+++ b/absyntax/absyntax.hh	Mon Nov 26 16:38:15 2012 +0000
@@ -48,6 +48,7 @@
 
 #include <stdio.h> // required for NULL
 #include <vector>
+#include <map>
 #include <string>
 #include <stdint.h>  // required for uint64_t, etc...
 #include "../main.hh" // required for uint8_t, real_64_t, ..., and the macros INT8_MAX, REAL32_MAX, ... */
@@ -72,6 +73,28 @@
 
 
 
+/* Case insensitive string compare */
+  /* Case insensitive string compare copied from
+   * "The C++ Programming Language" - 3rd Edition
+   * by Bjarne Stroustrup, ISBN 0201889544.
+   */
+class nocasecmp_c {
+    public:
+      bool operator() (const std::string& x, const std::string& y) const {
+        std::string::const_iterator ix = x.begin();
+        std::string::const_iterator iy = y.begin();
+
+        for(; (ix != x.end()) && (iy != y.end()) && (toupper(*ix) == toupper(*iy)); ++ix, ++iy);
+        if (ix == x.end()) return (iy != y.end());
+        if (iy == y.end()) return false;
+        return (toupper(*ix) < toupper(*iy));
+      };
+  };
+
+
+
+
+
 
 
 
@@ -99,7 +122,7 @@
 
     /*
      * Annotations produced during stage 3
-     */
+     */    
     /*** Data type analysis ***/
     std::vector <symbol_c *> candidate_datatypes; /* All possible data types the expression/literal/etc. may take. Filled in stage3 by fill_candidate_datatypes_c class */
     /* Data type of the expression/literal/etc. Filled in stage3 by narrow_candidate_datatypes_c 
@@ -138,6 +161,12 @@
     } const_value_t;
     const_value_t const_value;
     
+    /*** Enumeration datatype checking ***/    
+    /* Not all symbols will contain the following anotations, which is why they are not declared here in symbol_c
+     * They will be declared only inside the symbols that require them (have a look at absyntax.def)
+     */
+    typedef std::multimap<std::string, symbol_c *, nocasecmp_c> enumvalue_symtable_t;
+    
 
   public:
     /* default constructor */
@@ -153,6 +182,8 @@
 };
 
 
+
+
 class token_c: public symbol_c {
   public:
     /* WARNING: only use this method for debugging purposes!! */
@@ -169,6 +200,8 @@
 };
 
 
+
+
  /* a list of symbols... */
 class list_c: public symbol_c {
   public:
@@ -200,6 +233,11 @@
 
 
 
+
+
+
+
+
 #define SYM_LIST(class_name_c, ...)											\
 class class_name_c:	public list_c {											\
   public:														\
--- a/absyntax/visitor.cc	Fri Nov 23 11:38:57 2012 +0100
+++ b/absyntax/visitor.cc	Mon Nov 26 16:38:15 2012 +0000
@@ -70,7 +70,7 @@
 
 null_visitor_c::~null_visitor_c(void) {return;}
 
-#define SYM_LIST(class_name_c)	\
+#define SYM_LIST(class_name_c, ...)	\
   void *null_visitor_c::visit(class_name_c *symbol) {return NULL;}
 
 #define SYM_TOKEN(class_name_c, ...)	\
@@ -174,7 +174,7 @@
 }
 
 
-#define SYM_LIST(class_name_c)	\
+#define SYM_LIST(class_name_c, ...)	\
   void *iterator_visitor_c::visit(class_name_c *symbol) {return visit_list(symbol);}
 
 #define SYM_TOKEN(class_name_c, ...)	\
@@ -318,7 +318,7 @@
 }
 
 
-#define SYM_LIST(class_name_c)	\
+#define SYM_LIST(class_name_c, ...)	\
   void *search_visitor_c::visit(class_name_c *symbol) {return visit_list(symbol);}
 
 #define SYM_TOKEN(class_name_c, ...)	\
--- a/absyntax_utils/debug_ast.cc	Fri Nov 23 11:38:57 2012 +0100
+++ b/absyntax_utils/debug_ast.cc	Mon Nov 26 16:38:15 2012 +0000
@@ -100,8 +100,9 @@
   fprintf(stderr, "  datatype=");
   if (NULL == symbol->datatype)
     fprintf(stderr, "NULL\t\t");
-  else 
-    fprintf(stderr, symbol->datatype->absyntax_cname());
+  else {
+	  fprintf(stderr, "%s", symbol->datatype->absyntax_cname());
+  }
   fprintf(stderr, "\t<-{");
   if (symbol->candidate_datatypes.size() == 0) {
     fprintf(stderr, "\t\t\t\t\t");
@@ -112,12 +113,12 @@
       else
         fprintf(stderr, "\t\t\t");
   } else {
-    fprintf(stderr, "(%d)\t\t\t\t\t", symbol->candidate_datatypes.size());
+    fprintf(stderr, "(%lu)\t\t\t\t\t", (unsigned long int)symbol->candidate_datatypes.size());
   }
   fprintf(stderr, "}\t");         
   
   /* print the const values... */
-  fprintf(stderr, " constv{f=%f, i=%lld, u=%llu, b=%d}\t", symbol->const_value._real64.value, symbol->const_value._int64.value, symbol->const_value._uint64.value, symbol->const_value._bool.value);
+  fprintf(stderr, " constv{f=%f, i=%"PRId64", u=%"PRIu64", b=%d}\t", symbol->const_value._real64.value, symbol->const_value._int64.value, symbol->const_value._uint64.value, symbol->const_value._bool.value?1:0);
   
 }
 
@@ -126,8 +127,9 @@
 void *print_symbol_c::visit(il_instruction_c *symbol) {
    dump_symbol(symbol);
 
-  fprintf(stderr, "  next_il_=%d ", symbol->next_il_instruction.size());
-  fprintf(stderr, "  prev_il_=%d ", symbol->prev_il_instruction.size());
+   /* NOTE: std::map.size() returns a size_type, whose type is dependent on compiler/platform. To be portable, we need to do an explicit type cast. */
+  fprintf(stderr, "  next_il_=%lu ", (unsigned long int)symbol->next_il_instruction.size());
+  fprintf(stderr, "  prev_il_=%lu ", (unsigned long int)symbol->prev_il_instruction.size());
   
   if (symbol->prev_il_instruction.size() == 0)
     fprintf(stderr, "(----,");
--- a/lib/iec_std_lib.h	Fri Nov 23 11:38:57 2012 +0100
+++ b/lib/iec_std_lib.h	Mon Nov 26 16:38:15 2012 +0000
@@ -26,6 +26,10 @@
  *       $gcc -E iec_std_lib.h 
  */
 
+#ifndef _IEC_STD_LIB_H
+#define _IEC_STD_LIB_H
+
+
 #include <limits.h>
 #include <float.h>
 #include <math.h>
@@ -2157,3 +2161,5 @@
 /********************************************/
 
 /* Do we support this? */
+
+#endif /* _IEC_STD_LIB_H */
--- a/lib/iec_types.h	Fri Nov 23 11:38:57 2012 +0100
+++ b/lib/iec_types.h	Mon Nov 26 16:38:15 2012 +0000
@@ -32,7 +32,7 @@
 typedef struct {
     long int tv_sec;            /* Seconds.  */
     long int tv_nsec;           /* Nanoseconds.  */
-}__attribute__((packed)) IEC_TIMESPEC;
+} /* __attribute__((packed)) */ IEC_TIMESPEC;  /* packed is gcc specific! */
 
 typedef IEC_TIMESPEC IEC_TIME;
 typedef IEC_TIMESPEC IEC_DATE;
@@ -51,6 +51,6 @@
 typedef struct {
     __strlen_t len;
     uint8_t body[STR_MAX_LEN];
-} __attribute__((packed)) IEC_STRING;
+} /* __attribute__((packed)) */ IEC_STRING;  /* packed is gcc specific! */
 
 #endif /*IEC_TYPES_H*/
--- a/lib/iec_types_all.h	Fri Nov 23 11:38:57 2012 +0100
+++ b/lib/iec_types_all.h	Mon Nov 26 16:38:15 2012 +0000
@@ -62,8 +62,10 @@
 /* Include non windows.h clashing typedefs */
 #include "iec_types.h"
 
-#define TRUE 1
-#define FALSE 0
+#ifndef TRUE
+  #define TRUE 1
+  #define FALSE 0
+#endif
 
 #define __IEC_DEBUG_FLAG 0x01
 #define __IEC_FORCE_FLAG 0x02
--- a/stage1_2/iec_flex.ll	Fri Nov 23 11:38:57 2012 +0100
+++ b/stage1_2/iec_flex.ll	Mon Nov 26 16:38:15 2012 +0000
@@ -416,7 +416,7 @@
 /* we are parsing a function, program or function block declaration */
 %s decl_state
 
-/* we will be parsing a function body. Whether il/st is remains unknown */
+/* we will be parsing a function body. Whether il/st/sfc remains to be determined */
 %x body_state
 
 /* we are parsing il code -> flex must return the EOL tokens!       */
@@ -924,8 +924,7 @@
 			       * calling yyterminate() is equivalent to doing that. 
 			       */ 	
 			    yyterminate();
-			  }      
- else {
+			  } else {
 			    --include_stack_ptr;
 			    yy_delete_buffer(YY_CURRENT_BUFFER);
 			    yy_switch_to_buffer((include_stack[include_stack_ptr]).buffer_state);
@@ -1735,12 +1734,10 @@
    *   return 0;
    */
 
-  /* to we stop processing...
-   *
+  /* to stop processing...
    *   return 1;
    */
 
-
   return 1;  /* Stop scanning at end of input file. */
 }
 
--- a/stage3/Makefile.am	Fri Nov 23 11:38:57 2012 +0100
+++ b/stage3/Makefile.am	Mon Nov 26 16:38:15 2012 +0000
@@ -13,5 +13,6 @@
 	lvalue_check.cc \
 	array_range_check.cc \
         constant_folding.cc \
-        declaration_check.cc
+        declaration_check.cc \
+        enum_declaration_check.cc
 
--- a/stage3/Makefile.in	Fri Nov 23 11:38:57 2012 +0100
+++ b/stage3/Makefile.in	Mon Nov 26 16:38:15 2012 +0000
@@ -83,7 +83,8 @@
 	forced_narrow_candidate_datatypes.$(OBJEXT) \
 	print_datatypes_error.$(OBJEXT) datatype_functions.$(OBJEXT) \
 	lvalue_check.$(OBJEXT) array_range_check.$(OBJEXT) \
-	constant_folding.$(OBJEXT) declaration_check.$(OBJEXT)
+	constant_folding.$(OBJEXT) declaration_check.$(OBJEXT) \
+	enum_declaration_check.$(OBJEXT)
 libstage3_a_OBJECTS = $(am_libstage3_a_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/config
 depcomp = $(SHELL) $(top_srcdir)/config/depcomp
@@ -209,7 +210,8 @@
 	lvalue_check.cc \
 	array_range_check.cc \
         constant_folding.cc \
-        declaration_check.cc
+        declaration_check.cc \
+        enum_declaration_check.cc
 
 all: all-am
 
@@ -291,6 +293,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/constant_folding.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/datatype_functions.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/declaration_check.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/enum_declaration_check.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fill_candidate_datatypes.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flow_control_analysis.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/forced_narrow_candidate_datatypes.Po@am__quote@
--- a/stage3/constant_folding.cc	Fri Nov 23 11:38:57 2012 +0100
+++ b/stage3/constant_folding.cc	Mon Nov 26 16:38:15 2012 +0000
@@ -253,7 +253,7 @@
   int64_t      ret;
   std::string  str = "";
   char        *endptr;
-  const char  *value;
+  const char  *value = NULL;
   int          base;
   integer_c         *integer;
   hex_integer_c     *hex_integer;
@@ -285,7 +285,7 @@
   uint64_t     ret;
   std::string  str = "";
   char        *endptr;
-  const char  *value;
+  const char  *value = NULL;
   int          base;
   integer_c         *integer;
   hex_integer_c     *hex_integer;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/enum_declaration_check.cc	Mon Nov 26 16:38:15 2012 +0000
@@ -0,0 +1,254 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2012  Mario de Sousa (msousa@fe.up.pt)
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * This code is made available on the understanding that it will not be
+ * used in safety-critical situations without a full and competent review.
+ */
+
+/*
+ * An IEC 61131-3 compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+
+/* Declaration sequence is a source code part needed to declare variables.
+ * There are some checks we need to do before start with other analysis:
+ *
+ *   - Check external option redefinition.
+ *   - Check external data type redefinition.
+ *   - Check initial values consistently with the data types of the variables/data types being declared.
+ *   - Check whether a function block uses a CONSTANT qualifier as described in 2.5.2.1.
+ *
+ */
+
+
+#include "enum_declaration_check.hh"
+
+
+
+#define FIRST_(symbol1, symbol2) (((symbol1)->first_order < (symbol2)->first_order)   ? (symbol1) : (symbol2))
+#define  LAST_(symbol1, symbol2) (((symbol1)->last_order  > (symbol2)->last_order)    ? (symbol1) : (symbol2))
+
+#define STAGE3_ERROR(error_level, symbol1, symbol2, ...) {                                                                  \
+  if (current_display_error_level >= error_level) {                                                                         \
+    fprintf(stderr, "%s:%d-%d..%d-%d: error: ",                                                                             \
+            FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column,\
+                                                 LAST_(symbol1,symbol2) ->last_line,  LAST_(symbol1,symbol2) ->last_column);\
+    fprintf(stderr, __VA_ARGS__);                                                                                           \
+    fprintf(stderr, "\n");                                                                                                  \
+    error_count++;                                                                                                     \
+  }                                                                                                                         \
+}
+
+
+#define STAGE3_WARNING(symbol1, symbol2, ...) {                                                                             \
+    fprintf(stderr, "%s:%d-%d..%d-%d: warning: ",                                                                           \
+            FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column,\
+                                                 LAST_(symbol1,symbol2) ->last_line,  LAST_(symbol1,symbol2) ->last_column);\
+    fprintf(stderr, __VA_ARGS__);                                                                                           \
+    fprintf(stderr, "\n");                                                                                                  \
+    warning_found = true;                                                                                                   \
+}
+
+
+
+
+
+
+
+
+/*****************************************************/
+/*                                                   */
+/*  A small helper class...                          */
+/*                                                   */
+/*****************************************************/
+
+/* Add to the local_enumerated_value_symtable the local enum value constants */
+ 
+
+class populate_enumvalue_symtable_c: public iterator_visitor_c {
+  private:
+    symbol_c                        *current_enumerated_type;
+    symbol_c::enumvalue_symtable_t  *enumvalue_symtable;
+
+  private:
+    int &error_count;
+    int &current_display_error_level;    
+
+  public:
+     populate_enumvalue_symtable_c(int &error_count_, int &current_display_error_level_) 
+       : error_count(error_count_), current_display_error_level(current_display_error_level_) {
+       current_enumerated_type = NULL;  
+       enumvalue_symtable = NULL;
+     };
+    ~populate_enumvalue_symtable_c(void) {}
+    
+    void populate(symbol_c::enumvalue_symtable_t *symtable, symbol_c *symbol) {
+       enumvalue_symtable = symtable;
+       symbol->accept(*this);
+       enumvalue_symtable = NULL;
+     }
+
+  protected:
+  /*************************/
+  /* B.1 - Common elements */
+  /*************************/
+  /**********************/
+  /* B.1.3 - Data types */
+  /**********************/
+  /********************************/
+  /* B 1.3.3 - Derived data types */
+  /********************************/
+  /*  enumerated_type_name ':' enumerated_spec_init */
+  void *visit(enumerated_type_declaration_c *symbol) {
+    current_enumerated_type = symbol;
+    symbol->enumerated_spec_init->accept(*this);
+    current_enumerated_type = NULL;
+    return NULL;
+  }
+
+  /* enumerated_specification ASSIGN enumerated_value */
+  void *visit(enumerated_spec_init_c *symbol) {
+    if (NULL == current_enumerated_type)
+      current_enumerated_type = symbol;
+    symbol->enumerated_specification->accept(*this);
+    /* DO NOT visit the symbol->enumerated_value   !!! */
+    current_enumerated_type = NULL;
+    return NULL;
+  }
+
+  /* [enumerated_type_name '#'] identifier */
+  void *visit(enumerated_value_c *symbol) {
+    token_c *value = dynamic_cast <token_c *>(symbol->value);
+    if (NULL == value) ERROR;
+    const char *value_str = value->value;
+
+    if (current_enumerated_type == NULL) ERROR;  
+    /* this is really an ERROR! The initial value may use the syntax NUM_TYPE#enum_value, but in that case we should not have reached this visit method !! */
+    if (symbol->type != NULL) ERROR;  
+
+    symbol_c::enumvalue_symtable_t::iterator lower = enumvalue_symtable->lower_bound(value_str);
+    symbol_c::enumvalue_symtable_t::iterator upper = enumvalue_symtable->upper_bound(value_str);
+    for (; lower != upper; lower++)
+      if (lower->second == current_enumerated_type) {
+        /*  The same identifier is used more than once as an enumerated value/constant inside the same enumerated datat type! */
+        STAGE3_ERROR(0, symbol, symbol, "Duplicate identifier in enumerated data type.");
+        return NULL; /* No need to insert it! It is already in the table! */
+      }
+    
+    /* add it to the local symbol table. */
+    enumvalue_symtable->insert(std::pair<const char *, symbol_c *>(value_str, current_enumerated_type));
+    return NULL;
+  }
+}; // class populate_enumvalue_symtable_c
+
+
+
+
+
+
+
+
+
+
+
+enum_declaration_check_c::enum_declaration_check_c(symbol_c *ignore) {
+  error_count = 0;
+  current_display_error_level = 0;
+  global_enumvalue_symtable = NULL;
+  populate_enumvalue_symtable = new populate_enumvalue_symtable_c(error_count, current_display_error_level);
+}
+
+enum_declaration_check_c::~enum_declaration_check_c(void) {}
+
+int enum_declaration_check_c::get_error_count() {return error_count;}
+
+
+/***************************/
+/* B 0 - Programming Model */
+/***************************/
+void *enum_declaration_check_c::visit(library_c *symbol) {
+  global_enumvalue_symtable = &(symbol->enumvalue_symtable);
+  iterator_visitor_c::visit(symbol); // fall back to base class
+  return NULL;
+}
+
+
+
+/**********************/
+/* B.1.3 - Data types */
+/**********************/
+void *enum_declaration_check_c::visit(data_type_declaration_c *symbol) {
+  if (NULL == global_enumvalue_symtable) ERROR;
+  populate_enumvalue_symtable->populate(global_enumvalue_symtable, symbol);
+  return NULL;
+}
+
+/*********************/
+/* B 1.5.1 Functions */
+/*********************/
+void *enum_declaration_check_c::visit(function_declaration_c *symbol) {
+  populate_enumvalue_symtable->populate(&(symbol->enumvalue_symtable), symbol->var_declarations_list);
+  return NULL;
+}
+
+/***************************/
+/* B 1.5.2 Function blocks */
+/***************************/
+void *enum_declaration_check_c::visit(function_block_declaration_c *symbol) {
+  populate_enumvalue_symtable->populate(&(symbol->enumvalue_symtable), symbol->var_declarations);
+  return NULL;
+}
+
+/**********************/
+/* B 1.5.3 - Programs */
+/**********************/
+void *enum_declaration_check_c::visit(program_declaration_c *symbol) {
+  populate_enumvalue_symtable->populate(&(symbol->enumvalue_symtable), symbol->var_declarations);
+  return NULL;
+}
+
+/********************************/
+/* B 1.7 Configuration elements */
+/********************************/
+void *enum_declaration_check_c::visit(configuration_declaration_c *symbol) {
+  if (NULL != symbol->global_var_declarations)
+    populate_enumvalue_symtable->populate(&(symbol->enumvalue_symtable), symbol->global_var_declarations);
+  if (NULL != symbol->resource_declarations)
+    /* May reference either a list of resource_declaration_c, or a single_resource_declaration_c */
+    populate_enumvalue_symtable->populate(&(symbol->enumvalue_symtable), symbol->resource_declarations);
+  
+  return NULL;
+}
+
+
+void *enum_declaration_check_c::visit(resource_declaration_c *symbol) {
+  if (NULL != symbol->global_var_declarations)
+    populate_enumvalue_symtable->populate(&(symbol->enumvalue_symtable), symbol->global_var_declarations);
+  return NULL;
+}
+
+
+void *enum_declaration_check_c::visit(single_resource_declaration_c *symbol) {
+  /* do NOT visit! */
+  return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stage3/enum_declaration_check.hh	Mon Nov 26 16:38:15 2012 +0000
@@ -0,0 +1,81 @@
+/*
+ *  matiec - a compiler for the programming languages defined in IEC 61131-3
+ *
+ *  Copyright (C) 2012  Mario de Sousa (msousa@fe.up.pt)
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * This code is made available on the understanding that it will not be
+ * used in safety-critical situations without a full and competent review.
+ */
+
+/*
+ * An IEC 61131-3 compiler.
+ *
+ * Based on the
+ * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
+ *
+ */
+
+
+#include "../absyntax_utils/absyntax_utils.hh"
+
+class populate_enumvalue_symtable_c;
+
+class enum_declaration_check_c : public iterator_visitor_c {
+  private:
+    int error_count;
+    int current_display_error_level;
+    populate_enumvalue_symtable_c *populate_enumvalue_symtable;
+    symbol_c::enumvalue_symtable_t *global_enumvalue_symtable;
+    
+  public:
+     enum_declaration_check_c(symbol_c *ignore);
+    ~enum_declaration_check_c(void);
+    int get_error_count();
+
+    
+    /***************************/
+    /* B 0 - Programming Model */
+    /***************************/
+    void *visit(library_c *symbol);
+
+    /**********************/
+    /* B.1.3 - Data types */
+    /**********************/
+    void *visit(data_type_declaration_c *symbol);
+  
+    /***********************/
+    /* B 1.5.1 - Functions */
+    /***********************/
+    void *visit(function_declaration_c *symbol);
+   
+    /*****************************/
+    /* B 1.5.2 - Function Blocks */
+    /*****************************/
+    void *visit(function_block_declaration_c *symbol);
+
+    /******************************************/
+    /* B 1.5.3 - Declaration & Initialisation */
+    /******************************************/
+    void *visit(program_declaration_c *symbol);
+
+    /********************************/
+    /* B 1.7 Configuration elements */
+    /********************************/
+    void *visit(configuration_declaration_c *symbol);
+    void *visit(resource_declaration_c *symbol);
+    void *visit(single_resource_declaration_c *symbol);    
+};
--- a/stage3/fill_candidate_datatypes.cc	Fri Nov 23 11:38:57 2012 +0100
+++ b/stage3/fill_candidate_datatypes.cc	Mon Nov 26 16:38:15 2012 +0000
@@ -75,29 +75,6 @@
 
 
 
-#define FIRST_(symbol1, symbol2) (((symbol1)->first_order < (symbol2)->first_order)   ? (symbol1) : (symbol2))
-#define  LAST_(symbol1, symbol2) (((symbol1)->last_order  > (symbol2)->last_order)    ? (symbol1) : (symbol2))
-
-
-#define STAGE3_ERROR(error_level, symbol1, symbol2, ...) {                                                                  \
-    fprintf(stderr, "%s:%d-%d..%d-%d: error: ",                                                                             \
-            FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column,\
-                                                 LAST_(symbol1,symbol2) ->last_line,  LAST_(symbol1,symbol2) ->last_column);\
-    fprintf(stderr, __VA_ARGS__);                                                                                           \
-    fprintf(stderr, "\n");                                                                                                  \
-}  
-
-
-#define STAGE3_WARNING(symbol1, symbol2, ...) {                                                                             \
-    fprintf(stderr, "%s:%d-%d..%d-%d: warning: ",                                                                           \
-            FIRST_(symbol1,symbol2)->first_file, FIRST_(symbol1,symbol2)->first_line, FIRST_(symbol1,symbol2)->first_column,\
-                                                 LAST_(symbol1,symbol2) ->last_line,  LAST_(symbol1,symbol2) ->last_column);\
-    fprintf(stderr, __VA_ARGS__);                                                                                           \
-    fprintf(stderr, "\n");                                                                                                  \
-}  
-
-
-
 /* set to 1 to see debug info during execution */
 static int debug = 0;
 
@@ -161,7 +138,6 @@
     for (; lower != upper; lower++)
       if (lower->second == current_enumerated_type) {
         /*  The same identifier is used more than once as an enumerated value/constant inside the same enumerated datat type! */
-        STAGE3_ERROR(0, symbol, symbol, "Duplicate identifier in enumerated data type.");
         return NULL; /* No need to insert it! It is already in the table! */
       }
 
@@ -229,13 +205,13 @@
 static enumerated_value_symtable_t local_enumerated_value_symtable;
 
 
-class populate_enumvalue_symtable_c: public iterator_visitor_c {
+class populate_localenumvalue_symtable_c: public iterator_visitor_c {
   private:
     symbol_c *current_enumerated_type;
 
   public:
-     populate_enumvalue_symtable_c(void) {current_enumerated_type = NULL;};
-    ~populate_enumvalue_symtable_c(void) {}
+     populate_localenumvalue_symtable_c(void) {current_enumerated_type = NULL;};
+    ~populate_localenumvalue_symtable_c(void) {}
 
   public:
   /*************************/
@@ -271,7 +247,6 @@
     for (; lower != upper; lower++)
       if (lower->second == current_enumerated_type) {
         /*  The same identifier is used more than once as an enumerated value/constant inside the same enumerated datat type! */
-        STAGE3_ERROR(0, symbol, symbol, "Duplicate identifier in enumerated data type.");
         return NULL; /* No need to insert it! It is already in the table! */
       }
     
@@ -281,7 +256,7 @@
   }
 }; // class populate_enumvalue_symtable_c
 
-static populate_enumvalue_symtable_c populate_enumvalue_symtable;
+static populate_localenumvalue_symtable_c populate_enumvalue_symtable;
 
 
 
@@ -935,7 +910,7 @@
 void *fill_candidate_datatypes_c::visit(enumerated_value_c *symbol) {
 	symbol_c *global_enumerated_type;
 	symbol_c *local_enumerated_type;
-	symbol_c *enumerated_type;
+	symbol_c *enumerated_type = NULL;
 
 	if (NULL != symbol->type) {
 		/* NOTE: This code must take into account the following situation:
--- a/stage3/stage3.cc	Fri Nov 23 11:38:57 2012 +0100
+++ b/stage3/stage3.cc	Mon Nov 26 16:38:15 2012 +0000
@@ -43,6 +43,15 @@
 #include "array_range_check.hh"
 #include "constant_folding.hh"
 #include "declaration_check.hh"
+#include "enum_declaration_check.hh"
+
+
+static int enum_declaration_check(symbol_c *tree_root){
+    enum_declaration_check_c enum_declaration_check(NULL);
+    tree_root->accept(enum_declaration_check);
+    return enum_declaration_check.get_error_count();
+}
+
 
 static int declaration_safety(symbol_c *tree_root){
     declaration_check_c declaration_check(tree_root);
@@ -107,6 +116,7 @@
 
 int stage3(symbol_c *tree_root){
 	int error_count = 0;
+	error_count += enum_declaration_check(tree_root);
 	error_count += declaration_safety(tree_root);
 	error_count += flow_control_analysis(tree_root);
 	error_count += constant_folding(tree_root);