# HG changeset patch # User Mario de Sousa # Date 1353947895 0 # Node ID 7b90dd17f0ba7f4c6598086b4f6ca4a2dfc5e87e # Parent 8f05bde3efa8b6665b7c8aca7f6f4d92b8a3115d# Parent 36f91a5e4fc8ce354207c33601f8dae684961f54 merge diff -r 36f91a5e4fc8 -r 7b90dd17f0ba absyntax/absyntax.def --- 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) diff -r 36f91a5e4fc8 -r 7b90dd17f0ba absyntax/absyntax.hh --- 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 // required for NULL #include +#include #include #include // 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 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 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: \ diff -r 36f91a5e4fc8 -r 7b90dd17f0ba absyntax/visitor.cc --- 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, ...) \ diff -r 36f91a5e4fc8 -r 7b90dd17f0ba absyntax_utils/debug_ast.cc --- 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, "(----,"); diff -r 36f91a5e4fc8 -r 7b90dd17f0ba lib/iec_std_lib.h --- 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 #include #include @@ -2157,3 +2161,5 @@ /********************************************/ /* Do we support this? */ + +#endif /* _IEC_STD_LIB_H */ diff -r 36f91a5e4fc8 -r 7b90dd17f0ba lib/iec_types.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*/ diff -r 36f91a5e4fc8 -r 7b90dd17f0ba lib/iec_types_all.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 diff -r 36f91a5e4fc8 -r 7b90dd17f0ba stage1_2/iec_flex.ll --- 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. */ } diff -r 36f91a5e4fc8 -r 7b90dd17f0ba stage3/Makefile.am --- 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 diff -r 36f91a5e4fc8 -r 7b90dd17f0ba stage3/Makefile.in --- 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@ diff -r 36f91a5e4fc8 -r 7b90dd17f0ba stage3/constant_folding.cc --- 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; diff -r 36f91a5e4fc8 -r 7b90dd17f0ba stage3/enum_declaration_check.cc --- /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 . + * + * + * 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 ¤t_display_error_level; + + public: + populate_enumvalue_symtable_c(int &error_count_, int ¤t_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 (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(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; +} diff -r 36f91a5e4fc8 -r 7b90dd17f0ba stage3/enum_declaration_check.hh --- /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 . + * + * + * 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); +}; diff -r 36f91a5e4fc8 -r 7b90dd17f0ba stage3/fill_candidate_datatypes.cc --- 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: diff -r 36f91a5e4fc8 -r 7b90dd17f0ba stage3/stage3.cc --- 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);