# HG changeset patch # User mjsousa # Date 1416142450 0 # Node ID 477393b00f957e225a99452fd9c8dce186f2a89b # Parent 566414d7ba1f5bc71689553569d93e8c02b7b80a Add support for relaxed datatype model for array datatypes. diff -r 566414d7ba1f -r 477393b00f95 absyntax/absyntax.def --- a/absyntax/absyntax.def Sat Oct 25 13:20:10 2014 +0100 +++ b/absyntax/absyntax.def Sun Nov 16 12:54:10 2014 +0000 @@ -125,6 +125,9 @@ /* B 1.1 - Letters, digits and identifiers */ /*******************************************/ SYM_TOKEN(identifier_c) +/* A special identifier class, used for identifiers that have been previously declared as a derived datatype */ +/* This is currently needed because generate_c stage 4 needs to handle the array datatype identifiers differently to all other identifiers. */ +SYM_TOKEN(derived_datatype_identifier_c) /*********************/ diff -r 566414d7ba1f -r 477393b00f95 absyntax_utils/get_datatype_info.cc --- a/absyntax_utils/get_datatype_info.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/absyntax_utils/get_datatype_info.cc Sun Nov 16 12:54:10 2014 +0000 @@ -199,7 +199,8 @@ /*******************************************/ /* B 1.1 - Letters, digits and identifiers */ /*******************************************/ - void *visit(identifier_c *symbol) {return (void *)symbol->value;}; + void *visit( identifier_c *symbol) {return (void *)symbol->value;}; + void *visit(derived_datatype_identifier_c *symbol) {return (void *)symbol->value;}; /***********************************/ /* B 1.3.1 - Elementary Data Types */ @@ -249,6 +250,11 @@ void *visit(safewstring_type_name_c *symbol) {return (void *)"SAFEWSTRING"; }; /********************************/ + /* B.1.3.2 - Generic data types */ + /********************************/ + void *visit(generic_type_any_c *symbol) {return (void *)"ANY"; }; + + /********************************/ /* B 1.3.3 - Derived data types */ /********************************/ /* simple_type_name ':' simple_spec_init */ @@ -417,17 +423,21 @@ return get_struct_info_c::get_field_type_id(struct_datatype, struct_fieldname); } + + symbol_c *get_datatype_info_c::get_array_storedtype_id(symbol_c *type_symbol) { // returns the datatype of the variables stored in the array - symbol_c *basetype = search_base_type_c::get_basetype_decl(type_symbol); - array_specification_c *symbol = dynamic_cast(basetype); - - if (NULL != symbol) + array_specification_c *symbol = NULL; + if (NULL == symbol) symbol = dynamic_cast(type_symbol); + if (NULL == symbol) symbol = dynamic_cast(search_base_type_c::get_basetype_decl(type_symbol)); + if (NULL != symbol) return symbol->non_generic_type_name; return NULL; // this is not an array! } + + /* Returns true if both datatypes are equivalent (not necessarily equal!). * WARNING: May return true even though the datatypes are not the same/identicial!!! * This occurs when at least one of the datatypes is of a generic @@ -439,7 +449,13 @@ * this function will currently only return true if the dataypes are identicial. */ -/* NOTE: Currently the datatype model used by matiec considers any implicitly defined datatype +/* NOTE: matiec supports a strict and a relaxed data type model. Which datatype model to use is chosen + * as a command line option. + * + * + * The Strict Datatype Model + * ========================= + * The strict datatype model used by matiec considers any implicitly defined datatype * (e.g. an array datatype defined in the variable declaration itself, instead of inside a TYPE ... END_TYPE * construct) to be different (i.e. not the same datatype, and therefore not compatible) to any other * datatype, including with datatypes declared identically to the implicit datatype. @@ -459,6 +475,8 @@ * (this rule is specified in the standard, so we follow it!) * (2) REF_TO datatypes that reference the same datatype * (I dont think the standard says anything about this!) + * (This rule should actually be part of the relaxed datatype model, but for now we + * will leave it in the strict datatype model) * * TYPE * my_array_1_t: ARRAY [1..3] OF INT; @@ -511,6 +529,29 @@ * This rule was adopted as without it, the datatype of the value returned by the REF() * operator would be considered distinct to all other datatypes, and therefore the * REF() operator would be essentially useless. + * + * + * The Relaxed Datatype Model + * ========================== + * In the relaxed datatype model, the same rules as the strict datatype model are followed, with the + * exception of implicitly defined array datatypes, which are now considered equal if they define + * identical datatypes. + * This means that in the following example + * TYPE + * array_t: ARRAY [1..3] OF INT; + * END_TYPE; + * VAR + * array_var1: array_t; + * array_var2: ARRAY [1..3] OF INT; + * array_var3: ARRAY [1..3] OF INT; + * END_VAR + * + * all three variables (array_var1, array_var2, and array_var3) are considered as being of the + * same datatype. + * + * Note that the strict datatype model currently actually uses a relaxed datatype model for + * REF_TO datatypes, so in both the relaxed and strict datatype models matiec currently uses a + * relaxed datatype equivalince for REF_TO datatypes. */ bool get_datatype_info_c::is_type_equal(symbol_c *first_type, symbol_c *second_type) { if (!is_type_valid( first_type)) {return false;} @@ -522,16 +563,117 @@ (is_ANY_generic_type(second_type))) {return true;} /* ANY_ELEMENTARY */ - if ((is_ANY_ELEMENTARY(first_type)) && + if ((is_ANY_ELEMENTARY_compatible(first_type)) && (typeid(*first_type) == typeid(*second_type))) {return true;} - - /* ANY_DERIVED */ + if ( is_ANY_ELEMENTARY_compatible(first_type) + || is_ANY_ELEMENTARY_compatible(second_type)) {return false;} + + /* ANY_DERIVED */ + // from now on, we are sure both datatypes are derived... if (is_ref_to(first_type) && is_ref_to(second_type)) { return is_type_equal(search_base_type_c::get_basetype_decl(get_ref_to(first_type )), search_base_type_c::get_basetype_decl(get_ref_to(second_type))); } - return (first_type == second_type); -} + + // check for same datatype + if (first_type == second_type) {return true;} + + // remaining type equivalence rules are not applied in the strict datatype model + //if (!option...relaxed_datatypemodel) + //return false; + + // check for array equivalence usig the relaxed datatype model + if (is_arraytype_equal_relaxed(first_type, second_type)) {return true;} + + return false; +} + + + +/* A local helper function that transforms strings conatining signed_integers into a normalized + * form, so they can be compared for equality. + * examples: + * 82 -> 82 + * 8_2 -> 82 + * +82 -> 82 + * 082 -> 82 + * +082 -> 82 + * -82 -> -82 + * -8_2 -> -82 + * -082 -> -82 + */ +#include /* required for strlen() */ +static std::string normalize_integer(symbol_c *symbol) { + integer_c *token = dynamic_cast(symbol); + if (NULL == token) ERROR; + + std::string str = ""; + bool leading_zero = true; + unsigned int offset = 0; + + // handle any possible leading '-' or '+' + if (token->value[0] == '-') { + // '-' -> retained + str += token->value[0]; + offset++; + } else if (token->value[0] == '+') + // '+' -> skip, so '+8' and '8' will both result in '8' + offset++; + + for (unsigned int i = offset; i < strlen(token->value); i++) { + if (leading_zero && (token->value[i] != '0')) + leading_zero = false; + if (!leading_zero && token->value[i] != '_') + str += token->value[i]; + } + return str; +} + + +/* A helper method to get_datatype_info_c::is_type_equal() + * Assuming the relaxed datatype model, determine whether the two array datatypes are equal/equivalent + */ +bool get_datatype_info_c::is_arraytype_equal_relaxed(symbol_c *first_type, symbol_c *second_type) { + symbol_c *basetype_1 = search_base_type_c::get_basetype_decl( first_type); + symbol_c *basetype_2 = search_base_type_c::get_basetype_decl(second_type); + array_specification_c *array_1 = dynamic_cast(basetype_1); + array_specification_c *array_2 = dynamic_cast(basetype_2); + + // are they both array datatypes? + if ((NULL == array_1) || (NULL == array_2)) + return false; + + // number of subranges + array_subrange_list_c *subrange_list_1 = dynamic_cast(array_1->array_subrange_list); + array_subrange_list_c *subrange_list_2 = dynamic_cast(array_2->array_subrange_list); + if ((NULL == subrange_list_1) || (NULL == subrange_list_2)) ERROR; + if (subrange_list_1->n != subrange_list_2->n) + return false; + + // comparison of each subrange start and end elements + for (int i = 0; i < subrange_list_1->n; i++) { + subrange_c *subrange_1 = dynamic_cast(subrange_list_1->elements[i]); + subrange_c *subrange_2 = dynamic_cast(subrange_list_2->elements[i]); + if ((NULL == subrange_1) || (NULL == subrange_2)) ERROR; + #if 0 + /* An alternative method of checking whether the subranges have the same values, using the result of the constant folding agorithm. + * This method has the drawback that it inserts a dependency on having to run the constant folding algorithm before + * the get_datatype_info_c::is_type_equal() method is called. + * The probably slower alternative of comparing the strings themselves is therefor used. + */ + if (!constant_folding_c::is_equal_cvalue(subrange_1->lower_limit, subrange_2->lower_limit)) return false; + if (!constant_folding_c::is_equal_cvalue(subrange_1->upper_limit, subrange_2->upper_limit)) return false; + #endif + if (normalize_integer(subrange_1->lower_limit) != normalize_integer(subrange_2->lower_limit)) return false; + if (normalize_integer(subrange_1->upper_limit) != normalize_integer(subrange_2->upper_limit)) return false; + } + + return is_type_equal(search_base_type_c::get_basetype_decl(array_1->non_generic_type_name), + search_base_type_c::get_basetype_decl(array_2->non_generic_type_name)); +} + + + bool get_datatype_info_c::is_type_valid(symbol_c *type) { diff -r 566414d7ba1f -r 477393b00f95 absyntax_utils/get_datatype_info.hh --- a/absyntax_utils/get_datatype_info.hh Sat Oct 25 13:20:10 2014 +0100 +++ b/absyntax_utils/get_datatype_info.hh Sun Nov 16 12:54:10 2014 +0000 @@ -55,6 +55,9 @@ get_datatype_info_c(void) {}; ~get_datatype_info_c(void) {}; + // A helper method to get_datatype_info_c::is_type_equal() + // Assuming the relaxed datatype model, return whether the two array datatypes are equal/equivalent + static bool is_arraytype_equal_relaxed(symbol_c *first_type, symbol_c *second_type); public: static symbol_c *get_id (symbol_c *datatype); /* get the identifier (name) of the datatype); returns NULL if anonymous datatype! Does not work for elementary datatypes!*/ @@ -65,14 +68,17 @@ static symbol_c *get_ref_to (symbol_c *type_symbol); // Defined in IEC 61131-3 v3 (returns the type that is being referenced/pointed to) /* Returns true if both datatypes are equivalent (not necessarily equal!). - * WARNING: May return true even though the datatypes are not the same/identicial!!! - * This occurs when at least one of the datatypes is of a generic - * datatype (or a REF_TO a generic datatype). - * (Generic dataypes: ANY, ANY_INT, ANY_NUM, ...) + * Two datatype models are supported: relaxed and strict (chosen from a command line option). + * WARNING: May return true even though the datatypes are not the same/identical!!! + * In both of the models, this may occur when at least one of the datatypes is of a generic + * datatype (Generic dataypes: ANY, ANY_INT, ANY_NUM, ...), + * or when two REF_TO datatypes both reference an equivalent datatype. + * In only the relaxed datatype, it may also return true if two array datatypes + * have the same subrange limits, and contain the same data. + * * NOTE: Currently only the ANY generic datatype is implemented! * NOTE: Currently stage1_2 only allows the use of the ANY keyword when in conjuntion with - * the REF_TO keyword (i.e. REF_TO ANY), so when handling non REF_TO datatypes, - * this function will currently only return true if the dataypes are identicial. + * the REF_TO keyword (i.e. REF_TO ANY). */ static bool is_type_equal(symbol_c *first_type, symbol_c *second_type); static bool is_type_valid(symbol_c *type); diff -r 566414d7ba1f -r 477393b00f95 absyntax_utils/search_base_type.cc --- a/absyntax_utils/search_base_type.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/absyntax_utils/search_base_type.cc Sun Nov 16 12:54:10 2014 +0000 @@ -105,7 +105,9 @@ /*******************************************/ /* B 1.1 - Letters, digits and identifiers */ /*******************************************/ -void *search_base_type_c::visit(identifier_c *type_name) { + + +void *search_base_type_c::handle_datatype_identifier(token_c *type_name) { symbol_c *type_decl; this->current_basetype_name = type_name; @@ -129,6 +131,9 @@ return NULL; } +void *search_base_type_c::visit( identifier_c *type_name) {return handle_datatype_identifier(type_name);} // still needed to handle FB and program datatypes! +void *search_base_type_c::visit(derived_datatype_identifier_c *type_name) {return handle_datatype_identifier(type_name);} + /*********************/ /* B 1.2 - Constants */ diff -r 566414d7ba1f -r 477393b00f95 absyntax_utils/search_base_type.hh --- a/absyntax_utils/search_base_type.hh Sat Oct 25 13:20:10 2014 +0100 +++ b/absyntax_utils/search_base_type.hh Sun Nov 16 12:54:10 2014 +0000 @@ -74,6 +74,7 @@ private: static void create_singleton(void); + void *handle_datatype_identifier(token_c *type_name); public: search_base_type_c(void); @@ -88,8 +89,8 @@ /*******************************************/ /* B 1.1 - Letters, digits and identifiers */ /*******************************************/ - void *visit(identifier_c *type_name); - + void *visit( identifier_c *type_name); + void *visit(derived_datatype_identifier_c *type_name); /*********************/ /* B 1.2 - Constants */ diff -r 566414d7ba1f -r 477393b00f95 absyntax_utils/spec_init_separator.cc --- a/absyntax_utils/spec_init_separator.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/absyntax_utils/spec_init_separator.cc Sun Nov 16 12:54:10 2014 +0000 @@ -74,7 +74,22 @@ /* B 1.1 - Letters, digits and identifiers */ /*******************************************/ // SYM_TOKEN(identifier_c) -void *spec_init_sperator_c::visit(identifier_c *symbol) { +/* visitor for identifier_c is necessary because spec_init_sperator_c will be called to analyse PROGRAM identfiers, + * which are still transformed into identfier_c, instead of a derived_datatype_identifier_c + */ +void *spec_init_sperator_c::visit( identifier_c *symbol) { + TRACE("spec_init_sperator_c::identifier_c"); + switch (search_what) { + /* if we ever get called sith a simple identifier_c, then it must be a previously declared type... */ + case search_spec: return symbol; + case search_init: return NULL; + } + ERROR; /* should never occur */ + return NULL; + } + + +void *spec_init_sperator_c::visit(derived_datatype_identifier_c *symbol) { TRACE("spec_init_sperator_c::identifier_c"); switch (search_what) { /* if we ever get called sith a simple identifier_c, then it must be a previously declared type... */ diff -r 566414d7ba1f -r 477393b00f95 absyntax_utils/spec_init_separator.hh --- a/absyntax_utils/spec_init_separator.hh Sat Oct 25 13:20:10 2014 +0100 +++ b/absyntax_utils/spec_init_separator.hh Sun Nov 16 12:54:10 2014 +0000 @@ -65,7 +65,8 @@ /* B 1.1 - Letters, digits and identifiers */ /*******************************************/ // SYM_TOKEN(identifier_c) - void *visit(identifier_c *symbol); + void *visit( identifier_c *symbol); + void *visit(derived_datatype_identifier_c *symbol); /********************************/ diff -r 566414d7ba1f -r 477393b00f95 absyntax_utils/type_initial_value.cc --- a/absyntax_utils/type_initial_value.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/absyntax_utils/type_initial_value.cc Sun Nov 16 12:54:10 2014 +0000 @@ -117,8 +117,27 @@ } - -void *type_initial_value_c::visit(identifier_c *type_name) { +/* visitor for identifier_c is necessary because type_initial_value_c will be called to analyse PROGRAM identfiers, + * which are still transformed into identfier_c, instead of a derived_datatype_identifier_c + */ +void *type_initial_value_c::visit( identifier_c *type_name) { + /* look up the type declaration... */ + symbol_c *type_decl = type_symtable.find_value(type_name); + if (type_decl == type_symtable.end_value()) + /* Type declaration not found!! */ + /* NOTE: Variables declared out of function block 'data types', + * for eg: VAR timer: TON; END_VAR + * do not have a default value, so (TON) will never be found in the + * type symbol table. This means we cannot simply consider this + * an error and abort, but must rather return a NULL. + */ + return NULL; + + return type_decl->accept(*this); +} + + +void *type_initial_value_c::visit(derived_datatype_identifier_c *type_name) { /* look up the type declaration... */ symbol_c *type_decl = type_symtable.find_value(type_name); if (type_decl == type_symtable.end_value()) diff -r 566414d7ba1f -r 477393b00f95 absyntax_utils/type_initial_value.hh --- a/absyntax_utils/type_initial_value.hh Sat Oct 25 13:20:10 2014 +0100 +++ b/absyntax_utils/type_initial_value.hh Sun Nov 16 12:54:10 2014 +0000 @@ -86,7 +86,8 @@ void *handle_type_spec(symbol_c *base_type_name, symbol_c *type_spec_init); private: - void *visit(identifier_c *type_name); + void *visit( identifier_c *type_name); + void *visit(derived_datatype_identifier_c *type_name); /***********************************/ /* B 1.3.1 - Elementary Data Types */ diff -r 566414d7ba1f -r 477393b00f95 stage1_2/iec_bison.yy --- a/stage1_2/iec_bison.yy Sat Oct 25 13:20:10 2014 +0100 +++ b/stage1_2/iec_bison.yy Sun Nov 16 12:54:10 2014 +0000 @@ -1608,13 +1608,13 @@ prev_declared_variable_name : prev_declared_variable_name_token {$$ = new identifier_c($1, locloc(@$));}; prev_declared_fb_name : prev_declared_fb_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_simple_type_name : prev_declared_simple_type_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_subrange_type_name : prev_declared_subrange_type_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_enumerated_type_name: prev_declared_enumerated_type_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_array_type_name : prev_declared_array_type_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_structure_type_name : prev_declared_structure_type_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_string_type_name : prev_declared_string_type_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_ref_type_name : prev_declared_ref_type_name_token {$$ = new identifier_c($1, locloc(@$));}; /* defined in IEC 61131-3 v3 */ +prev_declared_simple_type_name : prev_declared_simple_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_subrange_type_name : prev_declared_subrange_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_enumerated_type_name: prev_declared_enumerated_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_array_type_name : prev_declared_array_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_structure_type_name : prev_declared_structure_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_string_type_name : prev_declared_string_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_ref_type_name : prev_declared_ref_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; /* defined in IEC 61131-3 v3 */ prev_declared_derived_function_name : prev_declared_derived_function_name_token {$$ = new identifier_c($1, locloc(@$));}; prev_declared_derived_function_block_name: prev_declared_derived_function_block_name_token {$$ = new identifier_c($1, locloc(@$));}; diff -r 566414d7ba1f -r 477393b00f95 stage3/constant_folding.cc --- a/stage3/constant_folding.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage3/constant_folding.cc Sun Nov 16 12:54:10 2014 +0000 @@ -788,8 +788,21 @@ /***********************************************************************/ /***********************************************************************/ - - +#if 0 +// not currently needed, so comment it out!... +// returns true if both symbols have the same value in all the cvalues +bool constant_folding_c::is_equal_cvalue(symbol_c *symbol_1, symbol_c *symbol_2) { + if (VALID_CVALUE (real64, symbol_1) != VALID_CVALUE (real64, symbol_2)) return false; + if (VALID_CVALUE (uint64, symbol_1) != VALID_CVALUE (uint64, symbol_2)) return false; + if (VALID_CVALUE ( int64, symbol_1) != VALID_CVALUE ( int64, symbol_2)) return false; + if (VALID_CVALUE ( bool, symbol_1) != VALID_CVALUE ( bool, symbol_2)) return false; + if (VALID_CVALUE (real64, symbol_1) && !ISEQUAL_CVALUE(real64, symbol_1, symbol_2)) return false; + if (VALID_CVALUE (uint64, symbol_1) && !ISEQUAL_CVALUE(uint64, symbol_1, symbol_2)) return false; + if (VALID_CVALUE ( int64, symbol_1) && !ISEQUAL_CVALUE( int64, symbol_1, symbol_2)) return false; + if (VALID_CVALUE ( bool, symbol_1) && !ISEQUAL_CVALUE( bool, symbol_1, symbol_2)) return false; + return true; +} +#endif diff -r 566414d7ba1f -r 477393b00f95 stage3/constant_folding.hh --- a/stage3/constant_folding.hh Sat Oct 25 13:20:10 2014 +0100 +++ b/stage3/constant_folding.hh Sun Nov 16 12:54:10 2014 +0000 @@ -66,6 +66,14 @@ virtual ~constant_folding_c(void); int get_error_count(); + #if 0 + // not currently needed, so comment it out!... + /* utility functions for other stage3 algorithms to access the contant folded values */ + /* written as static since we do not need to iteratively visit the symbols! */ + // returns true if both symbols have the same value in all the cvalues + static bool is_equal_cvalue(symbol_c *symbol_1, symbol_c *symbol_2); + #endif + private: /*********************/ /* B 1.2 - Constants */ diff -r 566414d7ba1f -r 477393b00f95 stage3/fill_candidate_datatypes.cc --- a/stage3/fill_candidate_datatypes.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage3/fill_candidate_datatypes.cc Sun Nov 16 12:54:10 2014 +0000 @@ -1303,10 +1303,57 @@ /* B 1.4.3 - Declaration & Initialisation */ /******************************************/ +/* When handling the declaration of variables the fill/narrow algorithm will simply visit the objects + * in the abstract syntax tree defining the desired datatype for the variables. Tis is to set the + * symbol->datatype to the basetype of that datatype. + * + * Note that we do not currently set the symbol->datatype annotation for the identifier_c objects naming the + * variables inside the variable declaration. However, this is liable to change in the future, so do not write + * any code that depends on this! + * + * example: + * VAR var1, var2, var3 : my_type; END_VAR + * (* ^^^^ ^^^^ ^^^^ -> will NOT have the symbol->datatype set (for now, may change in the future!) *) + * (* ^^^^^^^ -> WILL have the symbol->datatype set *) + * + * (remeber too that the identifier_c objects identifying variables inside ST/IL/SFC code *will* have their + * symbol->datatype annotation filled by the fill/narrow algorithm) + */ +void *fill_candidate_datatypes_c::fill_var_declaration(symbol_c *var_list, symbol_c *type) { + /* The type may be either a datatype object (e.g. array_spec_init_c, ...), or a derived_datatype_identifier_c + * naming a previously declared datatype. + * If it is a derived_datatype_identifier_c, we will search the list of all declared datatypes to determine + * the requested datatype. This is done automatically by the search_base_type_c::get_basetype_decl() method, + * so we do not need to do anything special here! + */ + add_datatype_to_candidate_list(type, search_base_type_c::get_basetype_decl(type)); /* will only add if non NULL */ + type->accept(*this); + // handle the extensible_input_parameter_c, etc... + /* The extensible_input_parameter_c will be visited since this class inherits from the iterator_visitor_c. + * It needs to be visited in order to handle the datatype of the first_index parameter of that class. + */ + var_list->accept(*this); + return NULL; +} + + +void *fill_candidate_datatypes_c::visit(var1_init_decl_c *symbol) {return fill_var_declaration(symbol->var1_list, symbol->spec_init);} +void *fill_candidate_datatypes_c::visit(array_var_init_decl_c *symbol) {return fill_var_declaration(symbol->var1_list, symbol->array_spec_init);} +void *fill_candidate_datatypes_c::visit(structured_var_init_decl_c *symbol) {return fill_var_declaration(symbol->var1_list, symbol->initialized_structure);} +void *fill_candidate_datatypes_c::visit(fb_name_decl_c *symbol) {return fill_var_declaration(symbol->fb_name_list, symbol->fb_spec_init);} +void *fill_candidate_datatypes_c::visit(array_var_declaration_c *symbol) {return fill_var_declaration(symbol->var1_list, symbol->array_specification);} +void *fill_candidate_datatypes_c::visit(structured_var_declaration_c *symbol) {return fill_var_declaration(symbol->var1_list, symbol->structure_type_name);} +void *fill_candidate_datatypes_c::visit(external_declaration_c *symbol) {return fill_var_declaration(symbol->global_var_name, symbol->specification);} +void *fill_candidate_datatypes_c::visit(global_var_decl_c *symbol) {return fill_var_declaration(symbol->global_var_spec, symbol->type_specification);} +void *fill_candidate_datatypes_c::visit(incompl_located_var_decl_c *symbol) {return fill_var_declaration(symbol->variable_name, symbol->var_spec);} +//void *fill_candidate_datatypes_c::visit(single_byte_string_var_declaration_c *symbol) {return handle_var_declaration(symbol->single_byte_string_spec);} +//void *fill_candidate_datatypes_c::visit(double_byte_string_var_declaration_c *symbol) {return handle_var_declaration(symbol->double_byte_string_spec);} + + + +// NOTE: this method is not required since fill_candidate_datatypes_c inherits from iterator_visitor_c. TODO: delete this method! void *fill_candidate_datatypes_c::visit(var1_list_c *symbol) { - for(int i = 0; i < symbol->n; i++) { - symbol->elements[i]->accept(*this); // handle the extensible_input_parameter_c, etc... - } + for(int i = 0; i < symbol->n; i++) {symbol->elements[i]->accept(*this);} return NULL; } @@ -1509,10 +1556,56 @@ /* B 1.7 Configuration elements */ /********************************/ void *fill_candidate_datatypes_c::visit(configuration_declaration_c *symbol) { - // TODO !!! - /* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */ - return NULL; -} + if (debug) printf("Filling candidate data types list in configuration %s\n", ((token_c *)(symbol->configuration_name))->value); + current_scope = symbol; +// local_enumerated_value_symtable.reset(); // TODO +// symbol->global_var_declarations->accept(populate_enumvalue_symtable); // TODO + + search_var_instance_decl = new search_var_instance_decl_c(symbol); + symbol->global_var_declarations ->accept(*this); + symbol->resource_declarations ->accept(*this); // points to a single_resource_declaration_c or a resource_declaration_list_c +// symbol->access_declarations ->accept(*this); // TODO +// symbol->instance_specific_initializations->accept(*this); // TODO + + delete search_var_instance_decl; + search_var_instance_decl = NULL; + + current_scope = NULL; +// local_enumerated_value_symtable.reset(); // TODO + return NULL; +} + + +void *fill_candidate_datatypes_c::visit(resource_declaration_c *symbol) { + if (debug) printf("Filling candidate data types list in resource %s\n", ((token_c *)(symbol->resource_name))->value); +// local_enumerated_value_symtable.reset(); // TODO-> this must be replaced with local_enumerated_value_symtable.push(), which is not yet implemented for the dsyntable_c! + symbol_c *prev_scope = current_scope; + current_scope = symbol; + /* TODO Enumeration constants may be defined inside a VAR_GLOBAL .. END_VAR variable declaration list. + * We currently do not yet consider enumeration values defined in the var declarations inside a resource! + */ +// symbol->global_var_declarations->accept(populate_enumvalue_symtable); // TODO! + + search_var_instance_decl_c *prev_search_var_instance_decl = search_var_instance_decl; + search_var_instance_decl = new search_var_instance_decl_c(symbol); + symbol->global_var_declarations->accept(*this); + symbol->resource_declaration ->accept(*this); // points to a single_resource_declaration_c! + + delete search_var_instance_decl; + search_var_instance_decl = prev_search_var_instance_decl; + + current_scope = prev_scope; +// local_enumerated_value_symtable.reset(); // TODO-> this must be replaced with local_enumerated_value_symtable.pop(), which is not yet implemented for the dsyntable_c! + return NULL; +} + + +void *fill_candidate_datatypes_c::visit(single_resource_declaration_c *symbol) { +// symbol->task_configuration_list ->accept(*this); // TODO +// symbol->program_configuration_list ->accept(*this); // TODO + return NULL; +} + /****************************************/ /* B.2 - Language IL (Instruction List) */ diff -r 566414d7ba1f -r 477393b00f95 stage3/fill_candidate_datatypes.hh --- a/stage3/fill_candidate_datatypes.hh Sat Oct 25 13:20:10 2014 +0100 +++ b/stage3/fill_candidate_datatypes.hh Sun Nov 16 12:54:10 2014 +0000 @@ -96,10 +96,11 @@ 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); - void *handle_conditional_il_flow_control_operator(symbol_c *symbol); - void *fill_type_decl(symbol_c *symbol, symbol_c *type_name, symbol_c *spec_init); - void *fill_spec_init(symbol_c *symbol, symbol_c *type_spec, symbol_c *init_value); - + void *handle_conditional_il_flow_control_operator (symbol_c *symbol); + void *fill_type_decl (symbol_c *symbol, symbol_c *type_name, symbol_c *spec_init); + void *fill_spec_init (symbol_c *symbol, symbol_c *type_spec, symbol_c *init_value); + void *fill_var_declaration (symbol_c *var_list, symbol_c *type); + /* a helper function... */ symbol_c *base_type(symbol_c *symbol); @@ -230,9 +231,20 @@ /******************************************/ /* B 1.4.3 - Declaration & Initialisation */ /******************************************/ - void *visit(var1_list_c *symbol); - void *visit(location_c *symbol); - void *visit(located_var_decl_c *symbol); + void *visit(var1_list_c *symbol); + void *visit(location_c *symbol); + void *visit(located_var_decl_c *symbol); + void *visit(var1_init_decl_c *symbol); + void *visit(array_var_init_decl_c *symbol); + void *visit(structured_var_init_decl_c *symbol); + void *visit(fb_name_decl_c *symbol); + void *visit(array_var_declaration_c *symbol); + void *visit(structured_var_declaration_c *symbol); + void *visit(external_declaration_c *symbol); + void *visit(global_var_decl_c *symbol); + void *visit(incompl_located_var_decl_c *symbol); + //void *visit(single_byte_string_var_declaration_c *symbol); + //void *visit(double_byte_string_var_declaration_c *symbol); /**************************************/ /* B 1.5 - Program organization units */ @@ -260,7 +272,9 @@ /********************************/ /* B 1.7 Configuration elements */ /********************************/ - void *visit(configuration_declaration_c *symbol); + void *visit(configuration_declaration_c *symbol); + void *visit(resource_declaration_c *symbol); + void *visit(single_resource_declaration_c *symbol); /****************************************/ /* B.2 - Language IL (Instruction List) */ diff -r 566414d7ba1f -r 477393b00f95 stage3/narrow_candidate_datatypes.cc --- a/stage3/narrow_candidate_datatypes.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage3/narrow_candidate_datatypes.cc Sun Nov 16 12:54:10 2014 +0000 @@ -747,6 +747,44 @@ /* B 1.4.3 - Declaration & Initialisation */ /******************************************/ +/* When handling the declaration of variables the fill/narrow algorithm will simply visit the objects + * in the abstract syntax tree defining the desired datatype for the variables. Tis is to set the + * symbol->datatype to the basetype of that datatype. + * + * Note that we do not currently set the symbol->datatype annotation for the identifier_c objects naming the + * variables inside the variable declaration. However, this is liable to change in the future, so do not write + * any code that depends on this! + * + * example: + * VAR var1, var2, var3 : my_type; END_VAR + * (* ^^^^ ^^^^ ^^^^ -> will NOT have the symbol->datatype set (for now, may change in the future!) *) + * (* ^^^^^^^ -> WILL have the symbol->datatype set *) + * + * (remeber too that the identifier_c objects identifying variables inside ST/IL/SFC code *will* have their + * symbol->datatype annotation filled by the fill/narrow algorithm) + */ +void *narrow_candidate_datatypes_c::narrow_var_declaration(symbol_c *type) { + if (type->candidate_datatypes.size() == 1) + type->datatype = type->candidate_datatypes[0]; + type->accept(*this); + return NULL; +} + + +void *narrow_candidate_datatypes_c::visit(var1_init_decl_c *symbol) {return narrow_var_declaration(symbol->spec_init);} +void *narrow_candidate_datatypes_c::visit(array_var_init_decl_c *symbol) {return narrow_var_declaration(symbol->array_spec_init);} +void *narrow_candidate_datatypes_c::visit(structured_var_init_decl_c *symbol) {return narrow_var_declaration(symbol->initialized_structure);} +void *narrow_candidate_datatypes_c::visit(fb_name_decl_c *symbol) {return narrow_var_declaration(symbol->fb_spec_init);} +void *narrow_candidate_datatypes_c::visit(array_var_declaration_c *symbol) {return narrow_var_declaration(symbol->array_specification);} +void *narrow_candidate_datatypes_c::visit(structured_var_declaration_c *symbol) {return narrow_var_declaration(symbol->structure_type_name);} +void *narrow_candidate_datatypes_c::visit(external_declaration_c *symbol) {return narrow_var_declaration(symbol->specification);} +void *narrow_candidate_datatypes_c::visit(global_var_decl_c *symbol) {return narrow_var_declaration(symbol->type_specification);} +void *narrow_candidate_datatypes_c::visit(incompl_located_var_decl_c *symbol) {return narrow_var_declaration(symbol->var_spec);} +//void *narrow_candidate_datatypes_c::visit(single_byte_string_var_declaration_c *symbol) {return handle_var_declaration(symbol->single_byte_string_spec);} +//void *narrow_candidate_datatypes_c::visit(double_byte_string_var_declaration_c *symbol) {return handle_var_declaration(symbol->double_byte_string_spec);} + + + void *narrow_candidate_datatypes_c::visit(var1_list_c *symbol) { #if 0 /* We don't really need to set the datatype of each variable. We just check the declaration itself! */ for(int i = 0; i < symbol->n; i++) { @@ -856,10 +894,36 @@ /* B 1.7 Configuration elements */ /********************************/ void *narrow_candidate_datatypes_c::visit(configuration_declaration_c *symbol) { - // TODO !!! - /* for the moment we must return NULL so semantic analysis of remaining code is not interrupted! */ - return NULL; -} + if (debug) printf("Narrowing candidate data types list in configuration %s\n", ((token_c *)(symbol->configuration_name))->value); + search_varfb_instance_type = new search_varfb_instance_type_c(symbol); + symbol->global_var_declarations->accept(*this); + symbol->resource_declarations ->accept(*this); // points to a single_resource_declaration_c or a resource_declaration_list_c +// symbol->access_declarations ->accept(*this); // TODO +// symbol->instance_specific_initializations->accept(*this); // TODO + delete search_varfb_instance_type; + search_varfb_instance_type = NULL; + return NULL; +} + + +void *narrow_candidate_datatypes_c::visit(resource_declaration_c *symbol) { + if (debug) printf("Narrowing candidate data types list in resource %s\n", ((token_c *)(symbol->resource_name))->value); + search_varfb_instance_type_c *prev_search_varfb_instance_type = search_varfb_instance_type; + search_varfb_instance_type = new search_varfb_instance_type_c(symbol); + symbol->global_var_declarations->accept(*this); + symbol->resource_declaration ->accept(*this); // points to a single_resource_declaration_c! + delete search_varfb_instance_type; + search_varfb_instance_type = prev_search_varfb_instance_type; + return NULL; +} + + +void *narrow_candidate_datatypes_c::visit(single_resource_declaration_c *symbol) { +// symbol->task_configuration_list ->accept(*this); // TODO +// symbol->program_configuration_list ->accept(*this); // TODO + return NULL; +} + /****************************************/ diff -r 566414d7ba1f -r 477393b00f95 stage3/narrow_candidate_datatypes.hh --- a/stage3/narrow_candidate_datatypes.hh Sat Oct 25 13:20:10 2014 +0100 +++ b/stage3/narrow_candidate_datatypes.hh Sun Nov 16 12:54:10 2014 +0000 @@ -80,9 +80,10 @@ 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_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_var_declaration (symbol_c *type); void *set_il_operand_datatype (symbol_c *il_operand, symbol_c *datatype); @@ -201,9 +202,20 @@ /******************************************/ /* B 1.4.3 - Declaration & Initialisation */ /******************************************/ - void *visit(var1_list_c *symbol); - void *visit(location_c *symbol); - void *visit(located_var_decl_c *symbol); + void *visit(var1_list_c *symbol); + void *visit(location_c *symbol); + void *visit(located_var_decl_c *symbol); + void *visit(var1_init_decl_c *symbol); + void *visit(array_var_init_decl_c *symbol); + void *visit(structured_var_init_decl_c *symbol); + void *visit(fb_name_decl_c *symbol); + void *visit(array_var_declaration_c *symbol); + void *visit(structured_var_declaration_c *symbol); + void *visit(external_declaration_c *symbol); + void *visit(global_var_decl_c *symbol); + void *visit(incompl_located_var_decl_c *symbol); + //void *visit(single_byte_string_var_declaration_c *symbol); + //void *visit(double_byte_string_var_declaration_c *symbol); /**************************************/ /* B 1.5 - Program organization units */ @@ -231,7 +243,10 @@ /********************************/ /* B 1.7 Configuration elements */ /********************************/ - void *visit(configuration_declaration_c *symbol); + void *visit(configuration_declaration_c *symbol); + void *visit(resource_declaration_c *symbol); + void *visit(single_resource_declaration_c *symbol); + /****************************************/ /* B.2 - Language IL (Instruction List) */ /****************************************/ diff -r 566414d7ba1f -r 477393b00f95 stage4/generate_c/generate_c.cc --- a/stage4/generate_c/generate_c.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage4/generate_c/generate_c.cc Sun Nov 16 12:54:10 2014 +0000 @@ -250,7 +250,7 @@ * LEN( STRING) : INT -> prints out -> INT__STRING * MUL(TIME, INT) : TIME -> prints out -> TIME__TIME__INT */ -class print_function_parameter_data_types_c: public generate_c_base_c { +class print_function_parameter_data_types_c: public generate_c_base_and_typeid_c { private: symbol_c *current_type; bool_type_name_c tmp_bool; @@ -269,7 +269,7 @@ public: print_function_parameter_data_types_c(stage4out_c *s4o_ptr): - generate_c_base_c(s4o_ptr) + generate_c_base_and_typeid_c(s4o_ptr) {current_type = NULL;} /**************************************/ @@ -752,185 +752,6 @@ -/***********************************************************************/ -/***********************************************************************/ -/***********************************************************************/ -/***********************************************************************/ -/***********************************************************************/ - - -identifier_c *generate_unique_id(const char *prefix = "", symbol_c *clone = NULL) { - static int counter = 0; - - counter++; - int len = snprintf(NULL, 0, "%s__UID_%d", prefix, counter); // UID -> Unique IDentifier - char *str = (char *)malloc(len+1); - if (snprintf(str, len+1, "%s__UID_%d", prefix, counter) < 0) ERROR; - - identifier_c *id = new identifier_c(str); - if (NULL == id) ERROR; - if (NULL != clone) - *(dynamic_cast(id)) = *(dynamic_cast(clone)); - return id; -} - - -identifier_c *generate_unique_id(symbol_c *prefix, symbol_c *clone = NULL) { - token_c *token = dynamic_cast(prefix); - //if (NULL == token) ERROR; - if (NULL == token) - return generate_unique_id("", clone); - return generate_unique_id(token->value, clone); -} - - -/* This class will generate a new datatype for each implicitly declared array datatype - * (i.e. arrays declared in a variable declaration, or a struct datatype declaration...) - * It will do the same for implicitly declared REF_TO datatypes. - * - * The class will be called once for each POU declaration, and once for each derived datatype declaration. - * - * e.g.: - * VAR a: ARRAY [1..3] OF INT; END_VAR <---- ARRAY datatype is implicitly declared inside the variable declaration - * TYPE STRUCT - * a: ARRAY [1..3] OF INT; <---- ARRAY datatype is implicitly declared inside the struct type declaration - * b: INT; - * END_STRUCT - * END_TYPE - */ -class generate_c_datatypes_c: public iterator_visitor_c { - private: - generate_c_typedecl_c generate_c_typedecl; - symbol_c *prefix; - public: - generate_c_datatypes_c(stage4out_c *s4o_incl_ptr) - : generate_c_typedecl(s4o_incl_ptr) { - prefix = NULL; - }; - virtual ~generate_c_datatypes_c(void) { - } - - /*************************/ - /* B.1 - Common elements */ - /*************************/ - /**********************/ - /* B.1.3 - Data types */ - /**********************/ - /********************************/ - /* B 1.3.3 - Derived data types */ - /********************************/ - /* identifier ':' array_spec_init */ - void *visit(array_type_declaration_c *symbol) {return NULL;} // This is not an implicitly defined array! - - /* ref_spec: REF_TO (non_generic_type_name | function_block_type_name) */ - void *visit(ref_spec_c *symbol) { - identifier_c *id = generate_unique_id(prefix, symbol); - /* Warning: The following is dangerous... - * We are asking the generate_c_typedecl_c visitor to visit a newly created ref_spec_init_c object - * that has not been through stage 3, and therefore does not have stage 3 annotations filled in. - * This will only work if generate_c_typedecl_c does ot depend on the stage 3 annotations! - */ - ref_spec_init_c ref_spec(symbol, NULL); - ref_type_decl_c ref_decl(id, &ref_spec); - ref_decl.accept(generate_c_typedecl); // Must be done _before_ adding the annotation, due to the way generate_c_typedecl_c works - symbol->anotations_map["generate_c_annotaton__implicit_type_id"] = id; - return NULL; - } - - /* For the moment, we do not support initialising reference data types */ - /* ref_spec_init: ref_spec [ ASSIGN ref_initialization ] */ - /* NOTE: ref_initialization may be NULL!! */ - // SYM_REF2(ref_spec_init_c, ref_spec, ref_initialization) - void *visit(ref_spec_init_c *symbol) { - symbol->ref_spec->accept(*this); - int implicit_id_count = symbol->ref_spec->anotations_map.count("generate_c_annotaton__implicit_type_id"); - if (implicit_id_count > 1) ERROR; - if (implicit_id_count == 1) - symbol->anotations_map["generate_c_annotaton__implicit_type_id"] = symbol->ref_spec->anotations_map["generate_c_annotaton__implicit_type_id"]; - return NULL; - } - - /* ref_type_decl: identifier ':' ref_spec_init */ - void *visit(ref_type_decl_c *symbol) {return NULL;} // This is not an implicitly defined REF_TO! - - /******************************************/ - /* B 1.4.3 - Declaration & Initialization */ - /******************************************/ - void *visit(edge_declaration_c *symbol) {return NULL;} - void *visit(en_param_declaration_c *symbol) {return NULL;} - void *visit(eno_param_declaration_c *symbol) {return NULL;} - - /* array_specification [ASSIGN array_initialization] */ - /* array_initialization may be NULL ! */ - void *visit(array_spec_init_c *symbol) { - symbol->array_specification->accept(*this); - int implicit_id_count = symbol->array_specification->anotations_map.count("generate_c_annotaton__implicit_type_id"); - if (implicit_id_count > 1) ERROR; - if (implicit_id_count == 1) - symbol->anotations_map["generate_c_annotaton__implicit_type_id"] = symbol->array_specification->anotations_map["generate_c_annotaton__implicit_type_id"]; - return NULL; - } - - /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */ - void *visit(array_specification_c *symbol) { - identifier_c *id = generate_unique_id(prefix, symbol); - /* Warning: The following is dangerous... - * We are asking the generate_c_typedecl_c visitor to visit a newly created array_type_declaration_c object - * that has not been through stage 3, and therefore does not have stage 3 annotations filled in. - * This will only work if generate_c_typedecl_c does ot depend on the stage 3 annotations! - */ - array_spec_init_c array_spec(symbol, NULL); - array_type_declaration_c array_decl(id, &array_spec); - array_decl.accept(generate_c_typedecl); // Must be done _before_ adding the annotation, due to the way generate_c_typedecl_c works - symbol->anotations_map["generate_c_annotaton__implicit_type_id"] = id; - return NULL; - } - - /* var1_list ':' initialized_structure */ - // SYM_REF2(structured_var_init_decl_c, var1_list, initialized_structure) - void *visit(structured_var_init_decl_c *symbol) {return NULL;} - - /* fb_name_list ':' function_block_type_name ASSIGN structure_initialization */ - /* structure_initialization -> may be NULL ! */ - void *visit(fb_name_decl_c *symbol) {return NULL;} - - /* var1_list ':' structure_type_name */ - //SYM_REF2(structured_var_declaration_c, var1_list, structure_type_name) - void *visit(structured_var_declaration_c *symbol) {return NULL;} - - - /***********************/ - /* B 1.5.1 - Functions */ - /***********************/ - void *visit(function_declaration_c *symbol) { - prefix = symbol->derived_function_name; - symbol->var_declarations_list->accept(*this); - prefix = NULL; - return NULL; - } - /*****************************/ - /* B 1.5.2 - Function Blocks */ - /*****************************/ - void *visit(function_block_declaration_c *symbol) { - prefix = symbol->fblock_name; - symbol->var_declarations->accept(*this); - prefix = NULL; - return NULL; - } - /**********************/ - /* B 1.5.3 - Programs */ - /**********************/ - void *visit(program_declaration_c *symbol) { - prefix = symbol->program_type_name; - symbol->var_declarations->accept(*this); - prefix = NULL; - return NULL; - } -}; - - - - @@ -986,8 +807,8 @@ /* FUNCTION derived_function_name ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ /* | FUNCTION derived_function_name ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ static void handle_function(function_declaration_c *symbol, stage4out_c &s4o, bool print_declaration) { - generate_c_vardecl_c *vardecl = NULL; - generate_c_base_c print_base(&s4o); + generate_c_vardecl_c *vardecl = NULL; + generate_c_base_and_typeid_c print_base(&s4o); TRACE("function_declaration_c"); @@ -1123,9 +944,9 @@ /* 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) static void handle_function_block(function_block_declaration_c *symbol, stage4out_c &s4o, bool print_declaration) { - generate_c_vardecl_c *vardecl; - generate_c_sfcdecl_c *sfcdecl; - generate_c_base_c print_base(&s4o); + generate_c_vardecl_c *vardecl; + generate_c_sfcdecl_c *sfcdecl; + generate_c_base_and_typeid_c print_base(&s4o); TRACE("function_block_declaration_c"); /* (A) Function Block data structure declaration... */ @@ -1325,9 +1146,9 @@ /* PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */ //SYM_REF4(program_declaration_c, program_type_name, var_declarations, function_block_body, unused) static void handle_program(program_declaration_c *symbol, stage4out_c &s4o, bool print_declaration) { - generate_c_vardecl_c *vardecl; - generate_c_sfcdecl_c *sfcdecl; - generate_c_base_c print_base(&s4o); + generate_c_vardecl_c *vardecl; + generate_c_sfcdecl_c *sfcdecl; + generate_c_base_and_typeid_c print_base(&s4o); TRACE("program_declaration_c"); /* (A) Program data structure declaration... */ @@ -1499,13 +1320,13 @@ /***********************************************************************/ /***********************************************************************/ -class generate_c_config_c: public generate_c_base_c { +class generate_c_config_c: public generate_c_base_and_typeid_c { private: stage4out_c &s4o_incl; public: generate_c_config_c(stage4out_c *s4o_ptr, stage4out_c *s4o_incl_ptr) - : generate_c_base_c(s4o_ptr), s4o_incl(*s4o_incl_ptr) { + : generate_c_base_and_typeid_c(s4o_ptr), s4o_incl(*s4o_incl_ptr) { }; virtual ~generate_c_config_c(void) {} @@ -1710,7 +1531,7 @@ /***********************************************************************/ -class generate_c_resources_c: public generate_c_typedecl_c { +class generate_c_resources_c: public generate_c_base_and_typeid_c { search_var_instance_decl_c *search_config_instance; search_var_instance_decl_c *search_resource_instance; @@ -1726,7 +1547,7 @@ public: generate_c_resources_c(stage4out_c *s4o_ptr, symbol_c *config_scope, symbol_c *resource_scope, unsigned long time) - : generate_c_typedecl_c(s4o_ptr) { + : generate_c_base_and_typeid_c(s4o_ptr) { current_configuration = config_scope; search_config_instance = new search_var_instance_decl_c(config_scope); search_resource_instance = new search_var_instance_decl_c(resource_scope); @@ -2237,9 +2058,9 @@ stage4out_c located_variables_s4o; stage4out_c variables_s4o; - generate_c_datatypes_c generate_c_datatypes; - generate_c_typedecl_c generate_c_typedecl; - generate_c_pous_c generate_c_pous; + generate_c_typedecl_c generate_c_typedecl; + generate_c_implicit_typedecl_c generate_c_implicit_typedecl; + generate_c_pous_c generate_c_pous; symbol_c *current_configuration; @@ -2257,8 +2078,8 @@ pous_incl_s4o(builddir, "POUS", "h"), located_variables_s4o(builddir, "LOCATED_VARIABLES","h"), variables_s4o(builddir, "VARIABLES","csv"), - generate_c_datatypes(&pous_incl_s4o), - generate_c_typedecl (&pous_incl_s4o) + generate_c_typedecl (&pous_incl_s4o), + generate_c_implicit_typedecl(&pous_incl_s4o, &generate_c_typedecl) { current_builddir = builddir; current_configuration = NULL; @@ -2337,7 +2158,7 @@ /* helper symbol for data_type_declaration */ void *visit(type_declaration_list_c *symbol) { for(int i = 0; i < symbol->n; i++) { - symbol->elements[i]->accept(generate_c_datatypes); + symbol->elements[i]->accept(generate_c_implicit_typedecl); symbol->elements[i]->accept(generate_c_typedecl); } return NULL; @@ -2349,14 +2170,14 @@ #define handle_pou(fname,pname) \ if (!allow_output) return NULL;\ if (generate_pou_filepairs__) {\ - const char *pou_name = get_datatype_info_c::get_id_str(pname);\ + const char *pou_name = get_datatype_info_c::get_id_str(pname);\ stage4out_c s4o_c(current_builddir, pou_name, "c");\ stage4out_c s4o_h(current_builddir, pou_name, "h");\ s4o_c.print("#include \""); s4o_c.print(pou_name); s4o_c.print(".h\"\n");\ s4o_h.print("#ifndef __"); s4o_h.print(pou_name); s4o_h.print("_H\n");\ s4o_h.print("#define __"); s4o_h.print(pou_name); s4o_h.print("_H\n");\ - generate_c_datatypes_c generate_c_datatypes__(&s4o_h);\ - symbol->accept(generate_c_datatypes__); /* generate implicitly delcared datatypes (arrays and ref_to) */\ + generate_c_implicit_typedecl_c generate_c_implicit_typedecl__(&s4o_h);\ + symbol->accept(generate_c_implicit_typedecl__); /* generate implicitly delcared datatypes (arrays and ref_to) */\ generate_c_pous_c::fname(symbol, s4o_h, true); /* generate the .h file */\ generate_c_pous_c::fname(symbol, s4o_c, false);/* generate the .c file */\ s4o_h.print("#endif /* __"); s4o_h.print(pou_name); s4o_h.print("_H */\n");\ @@ -2368,7 +2189,7 @@ pous_incl_s4o.print(".h\"\n");\ pous_s4o. print(".c\"\n");\ } else {\ - symbol->accept(generate_c_datatypes);\ + symbol->accept(generate_c_implicit_typedecl);\ generate_c_pous_c::fname(symbol, pous_incl_s4o, true);\ generate_c_pous_c::fname(symbol, pous_s4o, false);\ } @@ -2403,7 +2224,7 @@ /********************************/ void *visit(configuration_declaration_c *symbol) { if (symbol->global_var_declarations != NULL) - symbol->global_var_declarations->accept(generate_c_datatypes); + symbol->global_var_declarations->accept(generate_c_implicit_typedecl); static int configuration_count = 0; if (configuration_count++) { @@ -2446,7 +2267,7 @@ void *visit(resource_declaration_c *symbol) { if (symbol->global_var_declarations != NULL) - symbol->global_var_declarations->accept(generate_c_datatypes); + symbol->global_var_declarations->accept(generate_c_implicit_typedecl); symbol->resource_name->accept(*this); stage4out_c resources_s4o(current_builddir, current_name, "c"); generate_c_resources_c generate_c_resources(&resources_s4o, current_configuration, symbol, common_ticktime); diff -r 566414d7ba1f -r 477393b00f95 stage4/generate_c/generate_c_base.cc --- a/stage4/generate_c/generate_c_base.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage4/generate_c/generate_c_base.cc Sun Nov 16 12:54:10 2014 +0000 @@ -26,6 +26,30 @@ +/* This file cotains two main classes: + * - generate_c_base_c + * - generate_c_base_and_typeid_c + * + * generate_c_base_c + * ----------------- + * This class generates C code for all literals and varables. In short, all the basic stuff + * that will probably be needed in all other code generating classes. + * It does not however handle derived datatypes. + * + * generate_c_base_and_typeid_c + * ---------------------------- + * This is similar to the generate_c_base_c (from which it inherits), but it also handles + * all the derived datatypes. Note that it does not generate C code for the declaration of + * those datatypes (that is what generate_c_typedecl_c is for), but rather it merely + * generates the name/id of a derived datatype. + * Note too that not all derived datatypes in the IEC 61131-3 have a name (for example, + * VAR a: ARRAY [3..5] of INT END_VAR), in which case an alias for this datatype should + * have been previously generated by either generate_c_typedecl_c or generate_implicit_typedecl_c. + */ + + + + typedef struct { @@ -61,6 +85,12 @@ param_list.clear(); +/* generate_c_base_c + * ----------------- + * This class generates C code for all literals and varables. In short, all the basic stuff + * that will probably be needed in all other code generating classes. + * It does not however handle derived datatypes. + */ class generate_c_base_c: public iterator_visitor_c { protected: @@ -298,6 +328,10 @@ /* B 1.1 - Letters, digits and identifiers */ /*******************************************/ void *visit(identifier_c *symbol) {return print_token(symbol);} + /* If you need the derived_datatype_identifier_c visitor, then you should probably be + * inheriting from generate_c_base_and_typeid_c and not generate_c_base_c !! + */ + void *visit(derived_datatype_identifier_c *symbol) {ERROR; return NULL;} /*********************/ /* B 1.2 - Constants */ @@ -594,12 +628,11 @@ /* Currently only used in REF_TO ANY, which is mapped onto (void *) */ void *visit(generic_type_any_c *symbol) {s4o.print("void"); return NULL;} + /********************************/ /* B 1.3.3 - Derived data types */ /********************************/ - /* leave for derived classes... */ - - + /* enumerated_type_name '#' identifier */ void *visit(enumerated_value_c *symbol) { if (NULL == symbol->datatype) { @@ -619,97 +652,6 @@ } -/* identifier ':' array_spec_init */ -void *visit(array_type_declaration_c *symbol) {ERROR;/* Should never get called! */ return NULL;} - -/* array_specification [ASSIGN array_initialization] */ -/* array_initialization may be NULL ! */ -void *visit(array_spec_init_c *symbol) { - int implicit_id_count = symbol->anotations_map.count("generate_c_annotaton__implicit_type_id"); - if (implicit_id_count != 1) ERROR; - /* this is part of an implicitly declared datatype (i.e. inside a variable decaration), for which an equivalent C datatype - * has already been defined. So, we simly print out the id of that C datatpe... - */ - return symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(*this); -} - -/* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */ -void *visit(array_specification_c *symbol) { - int implicit_id_count = symbol->anotations_map.count("generate_c_annotaton__implicit_type_id"); - if (implicit_id_count != 1) ERROR; - /* this is part of an implicitly declared datatype (i.e. inside a variable decaration), for which an equivalent C datatype - * has already been defined. So, we simly print out the id of that C datatpe... - */ - return symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(*this); -} - - -/* ref_spec: REF_TO (non_generic_type_name | function_block_type_name) */ -void *visit(ref_spec_c *symbol) { - int implicit_id_count = symbol->anotations_map.count("generate_c_annotaton__implicit_type_id"); - if (implicit_id_count != 1) ERROR; - /* this is part of an implicitly declared datatype (i.e. inside a variable decaration), for which an equivalent C datatype - * has already been defined. So, we simly print out the id of that C datatpe... - */ - return symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(*this); -} - -/* For the moment, we do not support initialising reference data types */ -/* ref_spec_init: ref_spec [ ASSIGN ref_initialization ] */ -/* NOTE: ref_initialization may be NULL!! */ -// SYM_REF2(ref_spec_init_c, ref_spec, ref_initialization) -void *visit(ref_spec_init_c *symbol) { - int implicit_id_count = symbol->anotations_map.count("generate_c_annotaton__implicit_type_id"); - if (implicit_id_count != 1) ERROR; - /* this is part of an implicitly declared datatype (i.e. inside a variable decaration), for which an equivalent C datatype - * has already been defined. So, we simly print out the id of that C datatpe... - */ - return symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(*this); -} - -/* ref_type_decl: identifier ':' ref_spec_init */ -void *visit(ref_type_decl_c *symbol) {ERROR;/* Should never get called! */ 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; -} - - -/* NOTE: Why is this here? This visit() method should not be here!! - * TODO: Figure out who is dependent on this method, and move it to its correct location! - */ -/* 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 */ /*********************/ @@ -720,6 +662,7 @@ return NULL; } + /********************************************/ /* B.1.4.1 Directly Represented Variables */ /********************************************/ @@ -730,15 +673,12 @@ } - /*************************************/ /* B.1.4.2 Multi-element Variables */ /*************************************/ -#if 0 /* subscripted_variable '[' subscript_list ']' */ -SYM_REF2(array_variable_c, subscripted_variable, subscript_list) - -#endif +//SYM_REF2(array_variable_c, subscripted_variable, subscript_list) + /* record_variable '.' field_selector */ /* WARNING: input and/or output variables of function blocks @@ -845,10 +785,205 @@ - - - - - - - +/************************************************************************************************/ +/************************************************************************************************/ +/************************************************************************************************/ +/************************************************************************************************/ +/************************************************************************************************/ +/************************************************************************************************/ +/************************************************************************************************/ +/************************************************************************************************/ +/************************************************************************************************/ +/************************************************************************************************/ + + + +/* generate_c_base_and_typeid_c + * ---------------------------- + * This is similar to the generate_c_base_c (from which it inherits), but it also handles + * all the derived datatypes. Note that it does not generate C code for the declaration of + * those datatypes (that is what generate_c_typedecl_c is for), but rather it merely + * generates the name/id of a derived datatype. + * Note too that not all derived datatypes in the IEC 61131-3 have a name (for example, + * VAR a: ARRAY [3..5] of INT END_VAR), in which case an alias for this datatype should + * have been previously generated by either generate_c_typedecl_c or generate_implicit_typedecl_c. + */ +class generate_c_base_and_typeid_c: public generate_c_base_c { + + public: + generate_c_base_and_typeid_c(stage4out_c *s4o_ptr): generate_c_base_c(s4o_ptr) {} + ~generate_c_base_and_typeid_c(void) {} + + +/*************************/ +/* B.1 - Common elements */ +/*************************/ +/*******************************************/ +/* B 1.1 - Letters, digits and identifiers */ +/*******************************************/ + void *visit(derived_datatype_identifier_c *symbol) { + if (get_datatype_info_c::is_array(symbol->datatype)) { + return symbol->datatype->accept(*this); + } + return print_token(symbol); + } + +/*********************/ +/* B 1.2 - Constants */ +/*********************/ +/**********************/ +/* B.1.3 - Data types */ +/**********************/ +/***********************************/ +/* B 1.3.1 - Elementary Data Types */ +/***********************************/ +/********************************/ +/* B.1.3.2 - Generic data types */ +/********************************/ + /* Currently only used in REF_TO ANY, which is mapped onto (void *) */ + void *visit(generic_type_any_c *symbol) {s4o.print("void"); return NULL;} + +/********************************/ +/* B 1.3.3 - Derived data types */ +/********************************/ + +/* subrange_type_name ':' subrange_spec_init */ +void *visit(subrange_type_declaration_c *symbol) {return symbol->subrange_type_name->accept(*this);} + +/* subrange_specification ASSIGN signed_integer */ +void *visit(subrange_spec_init_c *symbol) {return symbol->subrange_specification->accept(*this);} + +/* integer_type_name '(' subrange')' */ +void *visit(subrange_specification_c *symbol) {return symbol->integer_type_name->accept(*this);} + +/* enumerated_type_name ':' enumerated_spec_init */ +void *visit(enumerated_type_declaration_c *symbol) {return symbol->enumerated_type_name->accept(*this);} + +/* enumerated_specification ASSIGN enumerated_value */ +void *visit(enumerated_spec_init_c *symbol) {return symbol->enumerated_specification->accept(*this);} + + +/* enumerated_type_name '#' identifier */ +/* Handled by generate_c_base_c class!! +void *visit(enumerated_value_c *symbol) {} +*/ + +/* identifier ':' array_spec_init */ +void *visit(array_type_declaration_c *symbol) { + int implicit_id_count = symbol->anotations_map.count("generate_c_annotaton__implicit_type_id"); + if (1 != implicit_id_count) ERROR; + return symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(*this); +} + + + +/* array_specification [ASSIGN array_initialization] */ +/* array_initialization may be NULL ! */ +void *visit(array_spec_init_c *symbol) { + int implicit_id_count = symbol->anotations_map.count("generate_c_annotaton__implicit_type_id"); + if (1 == implicit_id_count) return symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(*this); + if (0 == implicit_id_count) return symbol->datatype->accept(*this); + return NULL; +} + +/* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */ +void *visit(array_specification_c *symbol) { + int implicit_id_count = symbol->anotations_map.count("generate_c_annotaton__implicit_type_id"); + if (1 != implicit_id_count) ERROR; + return symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(*this); +} + + + +/* simple_type_name ':' simple_spec_init */ +void *visit(simple_type_declaration_c *symbol) {return symbol->simple_type_name->accept(*this);} + +/* simple_specification [ASSIGN constant] */ +//SYM_REF2(simple_spec_init_c, simple_specification, constant) +// may be NULL +void *visit(simple_spec_init_c *symbol) {return symbol->simple_specification->accept(*this);} + +/* structure_type_name ':' structure_specification */ +//SYM_REF2(structure_type_declaration_c, structure_type_name, structure_specification) +void *visit(structure_type_declaration_c *symbol) {return symbol->structure_type_name->accept(*this);} + +/* structure_type_name ASSIGN structure_initialization */ +/* structure_initialization may be NULL ! */ +//SYM_REF2(initialized_structure_c, structure_type_name, structure_initialization) +void *visit(initialized_structure_c *symbol) {return symbol->structure_type_name->accept(*this);} + + + +/* ref_spec: REF_TO (non_generic_type_name | function_block_type_name) */ +// SYM_REF1(ref_spec_c, type_name) +void *visit(ref_spec_c *symbol) { + int implicit_id_count = symbol->anotations_map.count("generate_c_annotaton__implicit_type_id"); + if (implicit_id_count > 1) ERROR; + if (implicit_id_count == 1) { + /* this is part of an implicitly declared datatype (i.e. inside a variable decaration), for which an equivalent C datatype + * has already been defined. So, we simly print out the id of that C datatpe... + */ + return symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(*this); + } + /* This is NOT part of an implicitly declared datatype (i.e. we are being called from an visit(ref_type_decl_c *), + * through the visit(ref_spec_init_c*)), so we need to simply print out the name of the datatype we reference to. + */ + //debug_c::print(symbol); ERROR; + symbol->type_name->accept(*this); + s4o.print("*"); + return NULL; +} + +/* For the moment, we do not support initialising reference data types */ +/* ref_spec_init: ref_spec [ ASSIGN ref_initialization ] */ +/* NOTE: ref_initialization may be NULL!! */ +// SYM_REF2(ref_spec_init_c, ref_spec, ref_initialization) +void *visit(ref_spec_init_c *symbol) { + /* NOTE An ref_type_decl_c will be created in stage4 for each implicitly defined REF_TO datatype, + * and this generate_c_typedecl_c will be called to define that REF_TO datatype in C. + * However, every implictly defined REF_TO datatype with the exact same parameters will be mapped + * to the same identifier (e.g: __REF_TO_INT). + * In order for the C compiler not to find the same datatype being defined two or more times, + * we will keep track of the datatypes that have already been declared, and henceforth + * only declare the datatypes that have not been previously defined. + */ + int implicit_id_count = symbol->anotations_map.count("generate_c_annotaton__implicit_type_id"); + if (1 < implicit_id_count) ERROR; + if (1 == implicit_id_count) + return symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(*this); + return symbol->ref_spec->accept(*this); // this is probably pointing to an identifier_c !! +} + +/* ref_type_decl: identifier ':' ref_spec_init */ +// SYM_REF2(ref_type_decl_c, ref_type_name, ref_spec_init) +void *visit(ref_type_decl_c *symbol) { + TRACE("ref_type_decl_c"); + /* NOTE An ref_type_decl_c will be created in stage4 for each implicitly defined REF_TO datatype, + * and this generate_c_typedecl_c will be called to define that REF_TO datatype in C. + * However, every implictly defined REF_TO datatype with the exact same parameters will be mapped + * to the same identifier (e.g: __REF_TO_INT). + * In order for the C compiler not to find the same datatype being defined two or more times, + * we will keep track of the datatypes that have already been declared, and henceforth + * only declare the datatypes that have not been previously defined. + */ + int implicit_id_count = symbol->anotations_map.count("generate_c_annotaton__implicit_type_id"); + if (0 != implicit_id_count) ERROR; + //symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(generate_c_base); + return symbol->ref_type_name->accept(*this); +} + + +}; /* class generate_c_base_and_typeid_c */ + + + + + + + + + + + + + diff -r 566414d7ba1f -r 477393b00f95 stage4/generate_c/generate_c_configbody.cc --- a/stage4/generate_c/generate_c_configbody.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage4/generate_c/generate_c_configbody.cc Sun Nov 16 12:54:10 2014 +0000 @@ -22,11 +22,11 @@ * used in safety-critical situations without a full and competent review. */ -class generate_c_configbody_c: public generate_c_base_c { +class generate_c_configbody_c: public generate_c_base_and_typeid_c { public: generate_c_configbody_c(stage4out_c *s4o_ptr) - : generate_c_base_c(s4o_ptr) { + : generate_c_base_and_typeid_c(s4o_ptr) { current_resource_name = NULL; } diff -r 566414d7ba1f -r 477393b00f95 stage4/generate_c/generate_c_il.cc --- a/stage4/generate_c/generate_c_il.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage4/generate_c/generate_c_il.cc Sun Nov 16 12:54:10 2014 +0000 @@ -126,7 +126,7 @@ -class generate_c_il_c: public generate_c_base_c, il_default_variable_visitor_c { +class generate_c_il_c: public generate_c_base_and_typeid_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_base_c(s4o_ptr), + : generate_c_base_and_typeid_c(s4o_ptr), implicit_variable_current (IL_DEFVAR, NULL), implicit_variable_result (IL_DEFVAR, NULL), implicit_variable_result_back(IL_DEFVAR_BACK, NULL) diff -r 566414d7ba1f -r 477393b00f95 stage4/generate_c/generate_c_inlinefcall.cc --- a/stage4/generate_c/generate_c_inlinefcall.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage4/generate_c/generate_c_inlinefcall.cc Sun Nov 16 12:54:10 2014 +0000 @@ -26,7 +26,7 @@ #define INLINE_RESULT_TEMP_VAR "__res" #define INLINE_PARAM_COUNT "__PARAM_COUNT" -class generate_c_inlinefcall_c: public generate_c_base_c { +class generate_c_inlinefcall_c: public generate_c_base_and_typeid_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_base_c(s4o_ptr), + : generate_c_base_and_typeid_c(s4o_ptr), implicit_variable_current(IL_DEFVAR, NULL) { search_varfb_instance_type = new search_varfb_instance_type_c(scope); diff -r 566414d7ba1f -r 477393b00f95 stage4/generate_c/generate_c_sfc.cc --- a/stage4/generate_c/generate_c_sfc.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage4/generate_c/generate_c_sfc.cc Sun Nov 16 12:54:10 2014 +0000 @@ -34,7 +34,7 @@ /***********************************************************************/ /***********************************************************************/ -class generate_c_sfc_elements_c: public generate_c_base_c { +class generate_c_sfc_elements_c: public generate_c_base_and_typeid_c { public: typedef enum { @@ -63,7 +63,7 @@ public: generate_c_sfc_elements_c(stage4out_c *s4o_ptr, symbol_c *name, symbol_c *scope, const char *variable_prefix = NULL) - : generate_c_base_c(s4o_ptr) { + : generate_c_base_and_typeid_c(s4o_ptr) { generate_c_il = new generate_c_il_c(s4o_ptr, name, scope, variable_prefix); generate_c_st = new generate_c_st_c(s4o_ptr, name, scope, variable_prefix); generate_c_code = new generate_c_SFC_IL_ST_c(s4o_ptr, name, scope, variable_prefix); @@ -655,7 +655,7 @@ /***********************************************************************/ /***********************************************************************/ -class generate_c_sfc_c: public generate_c_base_c { +class generate_c_sfc_c: public generate_c_base_and_typeid_c { private: std::list variable_list; @@ -665,7 +665,7 @@ public: generate_c_sfc_c(stage4out_c *s4o_ptr, symbol_c *name, symbol_c *scope, const char *variable_prefix = NULL) - : generate_c_base_c(s4o_ptr) { + : generate_c_base_and_typeid_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); diff -r 566414d7ba1f -r 477393b00f95 stage4/generate_c/generate_c_sfcdecl.cc --- a/stage4/generate_c/generate_c_sfcdecl.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage4/generate_c/generate_c_sfcdecl.cc Sun Nov 16 12:54:10 2014 +0000 @@ -32,7 +32,7 @@ /***********************************************************************/ /***********************************************************************/ -class generate_c_sfcdecl_c: protected generate_c_base_c { +class generate_c_sfcdecl_c: protected generate_c_base_and_typeid_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_base_c(s4o_ptr) { + : generate_c_base_and_typeid_c(s4o_ptr) { this->set_variable_prefix(variable_prefix); search_var_instance_decl = new search_var_instance_decl_c(scope); } diff -r 566414d7ba1f -r 477393b00f95 stage4/generate_c/generate_c_st.cc --- a/stage4/generate_c/generate_c_st.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage4/generate_c/generate_c_st.cc Sun Nov 16 12:54:10 2014 +0000 @@ -44,7 +44,7 @@ /***********************************************************************/ -class generate_c_st_c: public generate_c_base_c { +class generate_c_st_c: public generate_c_base_and_typeid_c { public: typedef enum { @@ -93,7 +93,7 @@ public: generate_c_st_c(stage4out_c *s4o_ptr, symbol_c *name, symbol_c *scope, const char *variable_prefix = NULL) - : generate_c_base_c(s4o_ptr) { + : generate_c_base_and_typeid_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); diff -r 566414d7ba1f -r 477393b00f95 stage4/generate_c/generate_c_typedecl.cc --- a/stage4/generate_c/generate_c_typedecl.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage4/generate_c/generate_c_typedecl.cc Sun Nov 16 12:54:10 2014 +0000 @@ -23,6 +23,221 @@ */ #include + +/* Ths class contains two main classes: + * - generate_c_typedecl_c + * - generate_c_implicit_typedecl_c + * + * and an auxiliary class + * - generate_datatypes_aliasid_c + * + * + * Both the generate_c_typedecl_c and the generate_c_implicit_typedecl_c may set a stage4 + * annotation (in the stage4 annotation map of each symbol_c) named + * "generate_c_annotaton__implicit_type_id" + * If this annotation is set, the generate_c_base_c will print out this value instead of + * the datatype's name! + * + * + * + * generate_c_typedecl_c + * --------------------- + * Given a datatype object (i.e. an object in the AST that is also used to define a datatype, + * typically one that may be returned by search_basetype_c), this class will generate the + * C code to declare an equivakent datatype in C. + * Note that array datatypes are handled in a special way; instead of using the name given + * to it in the IEC 61131-3 source code, and new alias is created for the datatype name in C. + * Eplanations why we do this may be found further on... + * + * + * generate_c_implicit_typedecl_c + * ------------------------------ + * Given a POU or a derived datatype declaration, it will search for any implicitly defined + * datatypes in that POU/datatype declaration. Implicit datatypes are datatypes that are not + * explicitly declared and given a name. Example: + * VAR a: ARRAY [9..11] of INT; END_VAR + * Here, the array is implictly delcared. + * For eac implicitly defined datatype, an alias for that datatype is created (by calling + * generate_datatypes_aliasid_c), and a C declaration is generated in C source code (by + * calling generate_c_typedecl_c). + * + * + * generate_datatypes_aliasid_c + * ---------------------------- + * Given a datatype object (i.e. an object in the AST that defines a datatype), it will create + * an alias name for that datatype. + * This class is used by both the generate_c_implicit_typedecl_c, and the generate_c_typedecl_c + * classes! + */ + + + + + + +/* generate an alias/name (identifier) for array and REF_TO datatypes */ +/* + * The generated alias is created based on the structure of the datatype itself, in order to + * guarantee that any two datatypes that have the same internal format will result in the same + * alias. + * examples: + * ARRAY [9..11] of INT --> __ARRAY_9_11_OF_INT + * REF_TO INT --> __REF_TO_INT + * ARRAY [9..11] of REF_TO INT --> __ARRAY_9_11_OF___REF_TO_INT + */ +class generate_datatypes_aliasid_c: fcall_visitor_c { + + private: + //std::map inline_array_defined; + std::string current_array_name; + static generate_datatypes_aliasid_c *singleton_; + + public: + generate_datatypes_aliasid_c(void) {}; + + virtual ~generate_datatypes_aliasid_c(void) { + //inline_array_defined.clear(); // Not really necessary... + } + + /* implement the virtual member function declared in fcall_visitor_c */ + // by default generate an ERROR if a visit method is called, unless it is explicitly handled in generate_datatypes_aliasid_c + void fcall(symbol_c *symbol) {ERROR;} + + static identifier_c *create_id(symbol_c *symbol) { + if (NULL == singleton_) singleton_ = new generate_datatypes_aliasid_c(); + if (NULL == singleton_) ERROR; + singleton_->current_array_name = ""; + symbol->accept(*singleton_); + const char *str1 = singleton_->current_array_name.c_str(); + char *str2 = (char *)malloc(strlen(str1)+1); + if (NULL == str2) ERROR; + strcpy(str2, str1); + identifier_c *id = new identifier_c(str2); + /* Copy all the anotations in the symbol_c object 'symbol' to the newly created 'id' object + * This includes the location (in the IEC 61131-3 source file) annotations set in stage1_2, + * the symbol->datatype set in stage3, and any other anotaions that may be created in the future! + */ + *(dynamic_cast(id)) = *(dynamic_cast(symbol)); + return id; + } + + /*************************/ + /* B.1 - Common elements */ + /*************************/ + /**********************/ + /* B.1.3 - Data types */ + /**********************/ + /***********************************/ + /* B 1.3.1 - Elementary Data Types */ + /***********************************/ + /***********************************/ + /* B 1.3.2 - Generic Data Types */ + /***********************************/ + /********************************/ + /* B 1.3.3 - Derived data types */ + /********************************/ + /* ref_spec: REF_TO (non_generic_type_name | function_block_type_name) */ + void *visit(ref_spec_c *symbol) { + current_array_name = "__REF_TO_"; + current_array_name += get_datatype_info_c::get_id_str(symbol->type_name); + return NULL; + } + + /******************************************/ + /* B 1.4.3 - Declaration & Initialization */ + /******************************************/ + /* array_specification [ASSIGN array_initialization] */ + /* array_initialization may be NULL ! */ + void *visit(array_spec_init_c *symbol) { + if (NULL == symbol->datatype) ERROR; + symbol->datatype->accept(*this); // the base datatype should be an array_specification_c !! + return NULL; + } + + /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */ + void *visit(array_specification_c *symbol) { + current_array_name = "__ARRAY_OF_"; + if ( get_datatype_info_c::is_ref_to(symbol->non_generic_type_name) + && (get_datatype_info_c::get_ref_to(symbol->non_generic_type_name) != NULL)) { + /* handle situations where we have 2 impliclitly defined datatype, namely a REF_TO inside an ARRAY + * e.g. TYPE array_of_ref_to_sint : ARRAY [1..3] OF REF_TO SINT; END_TYPE + * The second condition (get_datatype_info_c::get_ref_to(symbol->non_generic_type_name) != NULL) + * in the above if() is to make sure we use the standard algorithm if the array is of a previously + * defined REF_TO type, in which case symbol->non_generic_type_name will reference an identifier_c! + * e.g. TYPE array_of_ref_to_sint : ARRAY [1..3] OF REF_TO SINT; END_TYPE + */ + current_array_name += "__REF_TO_"; + current_array_name += get_datatype_info_c::get_id_str(get_datatype_info_c::get_ref_to(symbol->non_generic_type_name)); + } else { + current_array_name += get_datatype_info_c::get_id_str(symbol->non_generic_type_name); + } + symbol->array_subrange_list->accept(*this); + return NULL; + } + + /* helper symbol for array_specification */ + /* array_subrange_list ',' subrange */ + void *visit(array_subrange_list_c *symbol) { + for(int i = 0; i < symbol->n; i++) {symbol->elements[i]->accept(*this);} + return NULL; + } + + /* signed_integer DOTDOT signed_integer */ + //SYM_REF2(subrange_c, lower_limit, upper_limit) + void *visit(subrange_c *symbol) { + current_array_name += "_"; + std::stringstream ss; + ss << symbol->dimension; + current_array_name += ss.str(); + return NULL; + } + + +}; + + +generate_datatypes_aliasid_c *generate_datatypes_aliasid_c::singleton_ = NULL; + + + + + + + +/***************************************************************************************/ +/***************************************************************************************/ +/***************************************************************************************/ +/***************************************************************************************/ + +/* Given an object in the AST that defines a datatype, generate the C source code that declares an + * equivalent dataype in C. + * WARNING: This class maintains internal state in the datatypes_already_defined map. + * Using multiple isntances of this class may result in different C source code + * compared to when a single instance of this class is used for all datatype declarations! + * + * Except for arrays, the C datatype will have the same name as the name of the datatype in the + * IEC 61131-3 source code. + * For arrays an alias is created for each datatype. This alias has the property of being equal + * for arrays with the same internal structure. + * + * Example: + * TYPE + * array1: ARRAY [9..11] of INT; + * array2: ARRAY [9..11] of INT; + * END_TYPE + * + * will result in both arrays having the same name (__ARRAY_9_11_OF_INT) in the C source code. + * + * A single C datatype declaration will be generated for both arrays + * (the datatypes_already_defined keeps track of which datatypes have already been declared in C) + * This method of handling arrays is needed when the relaxed datatype model is used + * (see get_datatype_info_c for explanation on the relaxed datatype model). + */ +/* Notice that this class inherits from generate_c_base_c, and not from generate_c_base_and_typeid_c. + * This is intentional! + * Whenever this class needs to print out the id of a datatype, it will explicitly use a private instance + * (generate_c_typeid) of generate_c_base_and_typeid_c! + */ class generate_c_typedecl_c: public generate_c_base_c { protected: @@ -30,18 +245,18 @@ private: symbol_c* current_type_name; - bool array_is_derived; - generate_c_base_c *basedecl; - + generate_c_base_and_typeid_c *generate_c_typeid; + std::map datatypes_already_defined; + public: - generate_c_typedecl_c(stage4out_c *s4o_ptr): generate_c_base_c(s4o_ptr), s4o_incl(*s4o_ptr) { + generate_c_typedecl_c(stage4out_c *s4o_ptr): generate_c_base_c(s4o_ptr), s4o_incl(*s4o_ptr) /*, generate_c_print_typename(s4o_ptr) */{ current_typedefinition = none_td; current_basetypedeclaration = none_bd; current_type_name = NULL; - basedecl = new generate_c_base_c(&s4o_incl); + generate_c_typeid = new generate_c_base_and_typeid_c(&s4o_incl); } ~generate_c_typedecl_c(void) { - delete basedecl; + delete generate_c_typeid; } typedef enum { @@ -71,13 +286,11 @@ if (visitor == NULL) visitor = this; if (list->n > 0) { -//std::cout << "generate_c_base_c::print_list(n = " << list->n << ") 000\n"; s4o_incl.print(pre_elem_str); list->elements[0]->accept(*visitor); } for(int i = 1; i < list->n; i++) { -//std::cout << "generate_c_base_c::print_list " << i << "\n"; s4o_incl.print(inter_elem_str); list->elements[i]->accept(*visitor); } @@ -100,8 +313,6 @@ /*******************************************/ /* B 1.1 - Letters, digits and identifiers */ /*******************************************/ - /* done in base class(es) */ - /*********************/ /* B 1.2 - Constants */ /*********************/ @@ -154,7 +365,7 @@ current_type_name = symbol->subrange_type_name; s4o_incl.print("__DECLARE_DERIVED_TYPE("); - current_type_name->accept(*basedecl); + current_type_name->accept(*generate_c_typeid); s4o_incl.print(","); current_basetypedeclaration = subrangebasetype_bd; symbol->subrange_spec_init->accept(*this); @@ -184,16 +395,16 @@ if (current_typedefinition == subrange_td) { switch (current_basetypedeclaration) { case subrangebasetype_bd: - symbol->integer_type_name->accept(*basedecl); + symbol->integer_type_name->accept(*generate_c_typeid); break; case subrangetest_bd: if (symbol->subrange != NULL) { s4o_incl.print("static inline "); - current_type_name->accept(*basedecl); + current_type_name->accept(*generate_c_typeid); s4o_incl.print(" __CHECK_"); - current_type_name->accept(*basedecl); + current_type_name->accept(*generate_c_typeid); s4o_incl.print("("); - current_type_name->accept(*basedecl); + current_type_name->accept(*generate_c_typeid); s4o_incl.print(" value) {\n"); s4o_incl.indent_right(); @@ -217,9 +428,9 @@ } else { s4o_incl.print("#define __CHECK_"); - current_type_name->accept(*basedecl); + current_type_name->accept(*generate_c_typeid); s4o_incl.print(" __CHECK_"); - symbol->integer_type_name->accept(*basedecl); + symbol->integer_type_name->accept(*generate_c_typeid); s4o_incl.print("\n"); } break; @@ -247,19 +458,19 @@ break; case subrange_td: s4o_incl.print(s4o_incl.indent_spaces + "if (value < "); - symbol->lower_limit->accept(*basedecl); + symbol->lower_limit->accept(*generate_c_typeid); s4o_incl.print(")\n"); s4o_incl.indent_right(); s4o_incl.print(s4o_incl.indent_spaces + "return "); - symbol->lower_limit->accept(*basedecl); + symbol->lower_limit->accept(*generate_c_typeid); s4o_incl.print(";\n"); s4o_incl.indent_left(); s4o_incl.print(s4o_incl.indent_spaces + "else if (value > "); - symbol->upper_limit->accept(*basedecl); + symbol->upper_limit->accept(*generate_c_typeid); s4o_incl.print(")\n"); s4o_incl.indent_right(); s4o_incl.print(s4o_incl.indent_spaces + "return "); - symbol->upper_limit->accept(*basedecl); + symbol->upper_limit->accept(*generate_c_typeid); s4o_incl.print(";\n"); s4o_incl.indent_left(); s4o_incl.print(s4o_incl.indent_spaces + "else\n"); @@ -280,7 +491,7 @@ current_type_name = symbol->enumerated_type_name; s4o_incl.print("__DECLARE_ENUMERATED_TYPE("); - current_type_name->accept(*basedecl); + current_type_name->accept(*generate_c_typeid); s4o_incl.print(",\n"); s4o_incl.indent_right(); symbol->enumerated_spec_init->accept(*this); @@ -299,7 +510,7 @@ if (current_typedefinition == enumerated_td) symbol->enumerated_specification->accept(*this); else - symbol->enumerated_specification->accept(*basedecl); + symbol->enumerated_specification->accept(*generate_c_typeid); return NULL; } @@ -319,22 +530,40 @@ /* identifier ':' array_spec_init */ void *visit(array_type_declaration_c *symbol) { TRACE("array_type_declaration_c"); + + // NOTE: remeber that symbol->array_spec_init may point to an identifier_c, which is why we use symbol->array_spec_init->datatype instead! + if (NULL == symbol->array_spec_init->datatype) ERROR; + identifier_c *id = generate_datatypes_aliasid_c::create_id(symbol->array_spec_init->datatype); + + /* NOTE An array_type_declaration_c will be created in stage4 for each implicitly defined array, + * and this generate_c_typedecl_c will be called to define that array in C. + * However, every implictly defined array with the exact same parameters will be mapped + * to the same identifier (e.g: __ARRAY_OF_INT_33 where 33 is the number of elements in the array). + * In order for the C compiler not to find the same datatype being defined two or more times, + * we will keep track of the array datatypes that have already been declared, and henceforth + * only declare arrays that have not been previously defined. + */ + if (datatypes_already_defined.find(id->value) != datatypes_already_defined.end()) + goto end; // already defined. No need to define it again!! + datatypes_already_defined[id->value] = 1; // insert this datatype into the list of already defined arrays! + current_typedefinition = array_td; - current_type_name = symbol->identifier; - - int implicit_id_count = symbol->array_spec_init->anotations_map.count("generate_c_annotaton__implicit_type_id"); - if (implicit_id_count > 1) ERROR; - if (implicit_id_count == 1) - s4o_incl.print("__DECLARE_DERIVED_TYPE("); - else - s4o_incl.print("__DECLARE_ARRAY_TYPE("); - current_type_name->accept(*basedecl); + current_type_name = id; + + s4o_incl.print("__DECLARE_ARRAY_TYPE("); + current_type_name->accept(*generate_c_typeid); s4o_incl.print(","); symbol->array_spec_init->accept(*this); s4o_incl.print(")\n"); current_type_name = NULL; current_typedefinition = none_td; + +end: + symbol ->anotations_map["generate_c_annotaton__implicit_type_id"] = id; + symbol->datatype ->anotations_map["generate_c_annotaton__implicit_type_id"] = id; + symbol->array_spec_init->anotations_map["generate_c_annotaton__implicit_type_id"] = id; // probably not needed, bu let's play safe. + return NULL; } @@ -344,16 +573,6 @@ /* array_initialization may be NULL ! */ void *visit(array_spec_init_c *symbol) { TRACE("array_spec_init_c"); - int implicit_id_count = symbol->anotations_map.count("generate_c_annotaton__implicit_type_id"); - if (implicit_id_count > 1) ERROR; - if (implicit_id_count == 1) { - /* this is part of an implicitly declared datatype (i.e. inside a variable decaration), for which an equivalent C datatype - * has already been defined. So, we simly print out the id of that C datatpe... - */ - symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(*basedecl); - return NULL; - } -// if (current_typedefinition != array_td) {debug_c::print(symbol); ERROR;} symbol->array_specification->accept(*this); return NULL; } @@ -361,17 +580,8 @@ /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */ void *visit(array_specification_c *symbol) { TRACE("array_specification_c"); - int implicit_id_count = symbol->anotations_map.count("generate_c_annotaton__implicit_type_id"); - if (implicit_id_count > 1) ERROR; - if (implicit_id_count == 1) { - /* this is part of an implicitly declared datatype (i.e. inside a variable decaration), for which an equivalent C datatype - * has already been defined. So, we simly print out the id of that C datatpe... - */ - symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(*basedecl); - return NULL; - } // The 2nd and 3rd argument of a call to the __DECLARE_ARRAY_TYPE macro! - symbol->non_generic_type_name->accept(*this); + symbol->non_generic_type_name->accept(/*generate_c_print_typename*/*generate_c_typeid); s4o_incl.print(","); current_basetypedeclaration = arraysubrange_bd; symbol->array_subrange_list->accept(*this); @@ -399,14 +609,14 @@ TRACE("simple_type_declaration_c"); s4o_incl.print("__DECLARE_DERIVED_TYPE("); - symbol->simple_type_name->accept(*basedecl); + symbol->simple_type_name->accept(*generate_c_typeid); s4o_incl.print(","); symbol->simple_spec_init->accept(*this); s4o_incl.print(")\n"); if (get_datatype_info_c::is_subrange(symbol->simple_type_name)) { s4o_incl.print("#define __CHECK_"); - current_type_name->accept(*basedecl); + current_type_name->accept(*generate_c_typeid); s4o_incl.print(" __CHECK_"); symbol->simple_spec_init->accept(*this); s4o_incl.print("\n"); @@ -420,7 +630,7 @@ // may be NULL void *visit(simple_spec_init_c *symbol) { TRACE("simple_spec_init_c"); - symbol->simple_specification->accept(*basedecl); + symbol->simple_specification->accept(*generate_c_typeid); return NULL; } @@ -482,7 +692,7 @@ current_typedefinition = struct_td; s4o_incl.print("__DECLARE_STRUCT_TYPE("); - symbol->structure_type_name->accept(*basedecl); + symbol->structure_type_name->accept(*generate_c_typeid); s4o_incl.print(","); symbol->structure_specification->accept(*this); s4o_incl.print(")\n"); @@ -497,9 +707,7 @@ //SYM_REF2(initialized_structure_c, structure_type_name, structure_initialization) void *visit(initialized_structure_c *symbol) { TRACE("initialized_structure_c"); - - symbol->structure_type_name->accept(*basedecl); - + symbol->structure_type_name->accept(*generate_c_typeid); return NULL; } @@ -525,9 +733,9 @@ void *visit(structure_element_declaration_c *symbol) { TRACE("structure_element_declaration_c"); - symbol->spec_init->accept(*this); + symbol->spec_init->accept(/*generate_c_print_typename*/*generate_c_typeid); s4o_incl.print(" "); - symbol->structure_element_name->accept(*basedecl); + symbol->structure_element_name->accept(*generate_c_typeid); s4o_incl.print(";\n"); s4o_incl.print(s4o_incl.indent_spaces); @@ -628,20 +836,8 @@ /* ref_spec: REF_TO (non_generic_type_name | function_block_type_name) */ // SYM_REF1(ref_spec_c, type_name) -void *visit(ref_spec_c *symbol) { - int implicit_id_count = symbol->anotations_map.count("generate_c_annotaton__implicit_type_id"); - if (implicit_id_count > 1) ERROR; - if (implicit_id_count == 1) { - /* this is part of an implicitly declared datatype (i.e. inside a variable decaration), for which an equivalent C datatype - * has already been defined. So, we simly print out the id of that C datatpe... - */ - symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(*basedecl); - return NULL; - } - /* This is NOT part of an implicitly declared datatype (i.e. we are being called from an visit(ref_type_decl_c *), - * through the visit(ref_spec_init_c*)), so we need to simply print out the name of the datatype we reference to. - */ - symbol->type_name->accept(*this); +void *visit(ref_spec_c *symbol) { + symbol->type_name->accept(/*generate_c_print_typename*/*generate_c_typeid); s4o_incl.print("*"); return NULL; } @@ -651,31 +847,31 @@ /* NOTE: ref_initialization may be NULL!! */ // SYM_REF2(ref_spec_init_c, ref_spec, ref_initialization) void *visit(ref_spec_init_c *symbol) { - int implicit_id_count = symbol->anotations_map.count("generate_c_annotaton__implicit_type_id"); - if (implicit_id_count > 1) ERROR; - if (implicit_id_count == 1) { - /* this is part of an implicitly declared datatype (i.e. inside a variable decaration), for which an equivalent C datatype - * has already been defined. So, we simly print out the id of that C datatpe... - */ - symbol->anotations_map["generate_c_annotaton__implicit_type_id"]->accept(*basedecl); - return NULL; - } - /* This is NOT part of an implicitly declared datatype (i.e. we are being called from an visit(ref_type_decl_c *)), - * so we need to simply print out the name of the datatype we reference to. - */ - return symbol->ref_spec->accept(*this); + return symbol->ref_spec->accept(*generate_c_typeid); } /* ref_type_decl: identifier ':' ref_spec_init */ // SYM_REF2(ref_type_decl_c, ref_type_name, ref_spec_init) void *visit(ref_type_decl_c *symbol) { TRACE("ref_type_decl_c"); + + /* NOTE An ref_type_decl_c will be created in stage4 for each implicitly defined REF_TO datatype, + * and this generate_c_typedecl_c will be called to define that REF_TO datatype in C. + * However, every implictly defined REF_TO datatype with the exact same parameters will be mapped + * to the same identifier (e.g: __REF_TO_INT). + * In order for the C compiler not to find the same datatype being defined two or more times, + * we will keep track of the datatypes that have already been declared, and henceforth + * only declare the datatypes that have not been previously defined. + */ + if (datatypes_already_defined.find(((identifier_c *)(symbol->ref_type_name))->value) != datatypes_already_defined.end()) + return NULL; // already defined. No need to define it again!! + datatypes_already_defined[((identifier_c *)(symbol->ref_type_name))->value] = 1; // insert this datatype into the list of already defined arrays! current_type_name = NULL; current_typedefinition = none_td; s4o_incl.print("__DECLARE_REFTO_TYPE("); - symbol->ref_type_name->accept(*basedecl); + symbol->ref_type_name->accept(*generate_c_typeid); s4o_incl.print(", "); symbol->ref_spec_init->accept(*this); s4o_incl.print(")\n"); @@ -688,10 +884,6 @@ - - - - /*********************/ /* B 1.4 - Variables */ /*********************/ @@ -793,10 +985,176 @@ /********************************/ /* leave for derived classes... */ - - - }; /* generate_c_typedecl_c */ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ + + +/* This class will generate a new datatype for each implicitly declared array datatype + * (i.e. arrays declared in a variable declaration, or a struct datatype declaration...) + * It will do the same for implicitly declared REF_TO datatypes. + * + * Each new implicitly datatype will be atributed an alias, and a C datatype will be declared for that alias. + * The alias itself will be stored (annotated) in the datatype object in the AST, using the annotation + * map reserved for stage4 anotations. The alias is stored under the "generate_c_annotaton__implicit_type_id" + * entry, and this entry will then be used whenever the name of the datatype is needed (to declare a varable, + * for example). + * + * The class will be called once for each POU declaration, and once for each derived datatype declaration. + * + * e.g.: + * VAR x: ARRAY [1..3] OF INT; END_VAR <---- ARRAY datatype is implicitly declared inside the variable declaration + * VAR y: REF_TO INT; END_VAR <---- REF_TO datatype is implicitly declared inside the variable declaration + * TYPE STRUCT + * a: ARRAY [1..3] OF INT; <---- ARRAY datatype is implicitly declared inside the struct type declaration + * b: REF_TO INT; <---- REF_TO datatype is implicitly declared inside the struct type declaration + * c: INT; + * END_STRUCT + * END_TYPE + */ +class generate_c_implicit_typedecl_c: public iterator_visitor_c { + private: + generate_c_typedecl_c *generate_c_typedecl_; + generate_c_typedecl_c generate_c_typedecl_local; + symbol_c *prefix; + public: + generate_c_implicit_typedecl_c(stage4out_c *s4o, generate_c_typedecl_c *generate_c_typedecl=NULL) + : generate_c_typedecl_local(s4o) { + generate_c_typedecl_ = generate_c_typedecl; + if (NULL == generate_c_typedecl_) + generate_c_typedecl_ = &generate_c_typedecl_local; + prefix = NULL; + }; + virtual ~generate_c_implicit_typedecl_c(void) { + } + + /*************************/ + /* B.1 - Common elements */ + /*************************/ + /**********************/ + /* B.1.3 - Data types */ + /**********************/ + /********************************/ + /* B 1.3.3 - Derived data types */ + /********************************/ + /* identifier ':' array_spec_init */ + void *visit(array_type_declaration_c *symbol) {return NULL;} // This is not an implicitly defined array! + + /* ref_spec: REF_TO (non_generic_type_name | function_block_type_name) */ + void *visit(ref_spec_c *symbol) { + identifier_c *id = generate_datatypes_aliasid_c::create_id(symbol); + /* Warning: The following is dangerous... + * We are asking the generate_c_typedecl_c visitor to visit a newly created ref_spec_init_c object + * that has not been through stage 3, and therefore does not have stage 3 annotations filled in. + * This will only work if generate_c_typedecl_c does ot depend on the stage 3 annotations! + */ + ref_spec_init_c ref_spec(symbol, NULL); + ref_type_decl_c ref_decl(id, &ref_spec); + ref_decl.accept(*generate_c_typedecl_); + symbol->anotations_map["generate_c_annotaton__implicit_type_id"] = id; + return NULL; + } + + /* For the moment, we do not support initialising reference data types */ + /* ref_spec_init: ref_spec [ ASSIGN ref_initialization ] */ + /* NOTE: ref_initialization may be NULL!! */ + // SYM_REF2(ref_spec_init_c, ref_spec, ref_initialization) + void *visit(ref_spec_init_c *symbol) { + symbol->ref_spec->accept(*this); + int implicit_id_count = symbol->ref_spec->anotations_map.count("generate_c_annotaton__implicit_type_id"); + if (implicit_id_count > 1) ERROR; + if (implicit_id_count == 1) + symbol->anotations_map["generate_c_annotaton__implicit_type_id"] = symbol->ref_spec->anotations_map["generate_c_annotaton__implicit_type_id"]; + return NULL; + } + + /* ref_type_decl: identifier ':' ref_spec_init */ + void *visit(ref_type_decl_c *symbol) {return NULL;} // This is not an implicitly defined REF_TO! + + /******************************************/ + /* B 1.4.3 - Declaration & Initialization */ + /******************************************/ + void *visit(edge_declaration_c *symbol) {return NULL;} + void *visit(en_param_declaration_c *symbol) {return NULL;} + void *visit(eno_param_declaration_c *symbol) {return NULL;} + + /* array_specification [ASSIGN array_initialization] */ + /* array_initialization may be NULL ! */ + void *visit(array_spec_init_c *symbol) { + symbol->array_specification->accept(*this); + int implicit_id_count = symbol->array_specification->anotations_map.count("generate_c_annotaton__implicit_type_id"); + if (implicit_id_count > 1) ERROR; + if (implicit_id_count == 1) + symbol->anotations_map["generate_c_annotaton__implicit_type_id"] = symbol->array_specification->anotations_map["generate_c_annotaton__implicit_type_id"]; + return NULL; + } + + /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */ + void *visit(array_specification_c *symbol) { + identifier_c *id = generate_datatypes_aliasid_c::create_id(symbol); + /* Warning: The following is dangerous... + * We are asking the generate_c_typedecl_c visitor to visit a newly created array_type_declaration_c object + * that has not been through stage 3, and therefore does not have stage 3 annotations filled in. + * This will only work if generate_c_typedecl_c does ot depend on the stage 3 annotations! + */ + array_spec_init_c array_spec(symbol, NULL); + array_type_declaration_c array_decl(id, &array_spec); + array_decl.datatype = symbol->datatype; + array_spec.datatype = symbol->datatype; + array_decl.accept(*generate_c_typedecl_); + symbol->anotations_map["generate_c_annotaton__implicit_type_id"] = id; + return NULL; + } + + /* var1_list ':' initialized_structure */ + // SYM_REF2(structured_var_init_decl_c, var1_list, initialized_structure) + void *visit(structured_var_init_decl_c *symbol) {return NULL;} + + /* fb_name_list ':' function_block_type_name ASSIGN structure_initialization */ + /* structure_initialization -> may be NULL ! */ + void *visit(fb_name_decl_c *symbol) {return NULL;} + + /* var1_list ':' structure_type_name */ + //SYM_REF2(structured_var_declaration_c, var1_list, structure_type_name) + void *visit(structured_var_declaration_c *symbol) {return NULL;} + + + /***********************/ + /* B 1.5.1 - Functions */ + /***********************/ + void *visit(function_declaration_c *symbol) { + prefix = symbol->derived_function_name; + symbol->var_declarations_list->accept(*this); + prefix = NULL; + return NULL; + } + /*****************************/ + /* B 1.5.2 - Function Blocks */ + /*****************************/ + void *visit(function_block_declaration_c *symbol) { + prefix = symbol->fblock_name; + symbol->var_declarations->accept(*this); + prefix = NULL; + return NULL; + } + /**********************/ + /* B 1.5.3 - Programs */ + /**********************/ + void *visit(program_declaration_c *symbol) { + prefix = symbol->program_type_name; + symbol->var_declarations->accept(*this); + prefix = NULL; + return NULL; + } +}; + + + + + diff -r 566414d7ba1f -r 477393b00f95 stage4/generate_c/generate_c_vardecl.cc --- a/stage4/generate_c/generate_c_vardecl.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage4/generate_c/generate_c_vardecl.cc Sun Nov 16 12:54:10 2014 +0000 @@ -60,7 +60,7 @@ // Does this class really need to derive from generate_c_typedecl_c ??? -class generate_c_array_initialization_c: public generate_c_typedecl_c { +class generate_c_array_initialization_c: public generate_c_base_and_typeid_c { public: typedef enum { @@ -83,7 +83,7 @@ unsigned long long int current_initialization_count; public: - generate_c_array_initialization_c(stage4out_c *s4o_ptr): generate_c_typedecl_c(s4o_ptr) {} + generate_c_array_initialization_c(stage4out_c *s4o_ptr): generate_c_base_and_typeid_c(s4o_ptr) {} ~generate_c_array_initialization_c(void) {} void init_array_size(symbol_c *array_specification) { @@ -149,9 +149,7 @@ case arraysize_am: /* look up the type declaration... */ type_decl = type_symtable.find_value(type_name); - if (type_decl == type_symtable.end_value()) - /* Type declaration not found!! */ - ERROR; + if (type_decl == type_symtable.end_value()) ERROR; // Type declaration not found!! type_decl->accept(*this); break; default: @@ -495,7 +493,12 @@ } }; -class generate_c_structure_initialization_c: public generate_c_typedecl_c { + + + + + +class generate_c_structure_initialization_c: public generate_c_base_and_typeid_c { public: typedef enum { @@ -513,7 +516,7 @@ symbol_c* current_element_default_value; public: - generate_c_structure_initialization_c(stage4out_c *s4o_ptr): generate_c_typedecl_c(s4o_ptr) {} + generate_c_structure_initialization_c(stage4out_c *s4o_ptr): generate_c_base_and_typeid_c(s4o_ptr) {} ~generate_c_structure_initialization_c(void) {} void init_structure_default(symbol_c *structure_type_name) { @@ -572,6 +575,24 @@ return NULL; } + void *visit(derived_datatype_identifier_c *type_name) { + symbol_c *type_decl; + switch (current_mode) { + case initdefault_sm: + /* look up the type declaration... */ + type_decl = type_symtable.find_value(type_name); + if (type_decl == type_symtable.end_value()) + /* Type declaration not found!! */ + ERROR; + type_decl->accept(*this); + break; + default: + print_token(type_name); + break; + } + return NULL; + } + void *visit(var1_list_c *symbol) { int i, j; @@ -689,7 +710,7 @@ -class generate_c_vardecl_c: protected generate_c_base_c { +class generate_c_vardecl_c: protected generate_c_base_and_typeid_c { /* A Helper class to the main class... */ /* print a string, except the first time it is called */ @@ -890,8 +911,11 @@ void update_type_init(symbol_c *symbol /* a spec_init_c, subrange_spec_init_c, etc... */ ) { this->current_var_type_symbol = spec_init_sperator_c::get_spec(symbol); this->current_var_init_symbol = spec_init_sperator_c::get_init(symbol); - if (NULL == this->current_var_type_symbol) - ERROR; + if (NULL == this->current_var_type_symbol) ERROR; + if (NULL == this->current_var_type_symbol->datatype) {debug_c::print(this->current_var_type_symbol); ERROR;} + if (get_datatype_info_c::is_array(this->current_var_type_symbol)) + this->current_var_type_symbol = this->current_var_type_symbol->datatype; + if (NULL == this->current_var_type_symbol) ERROR; if (NULL == this->current_var_init_symbol) { /* We try to find the data type's default value... */ this->current_var_init_symbol = type_initial_value_c::get(this->current_var_type_symbol); @@ -1097,7 +1121,7 @@ public: generate_c_vardecl_c(stage4out_c *s4o_ptr, varformat_t varformat, unsigned int vartype, symbol_c* res_name = NULL) - : generate_c_base_c(s4o_ptr) { + : generate_c_base_and_typeid_c(s4o_ptr) { wanted_varformat = varformat; wanted_vartype = vartype; current_vartype = none_vt; @@ -1408,7 +1432,8 @@ /* Start off by setting the current_var_type_symbol and * current_var_init_symbol private variables... */ - update_type_init(symbol->array_spec_init); + if (NULL == symbol->array_spec_init->datatype) ERROR; + update_type_init(symbol->array_spec_init->datatype); // we want to print the name of the base datatype, and nt the derived datatype, so we use '->datatype'! /* now to produce the c equivalent... */ if (wanted_varformat == constructorinit_vf) { @@ -1550,7 +1575,8 @@ /* Start off by setting the current_var_type_symbol and * current_var_init_symbol private variables... */ - update_type_init(symbol->array_specification); + if (symbol->array_specification->datatype == NULL) {debug_c::print(symbol->array_specification); ERROR;} + update_type_init(symbol->array_specification->datatype); // we want to print the name of the base datatype, and nt the derived datatype, so we use '->datatype'! /* now to produce the c equivalent... */ if (wanted_varformat == constructorinit_vf) { @@ -1839,8 +1865,9 @@ /* Start off by setting the current_var_type_symbol and * current_var_init_symbol private variables... */ - this->current_var_type_symbol = symbol->specification; - this->current_var_init_symbol = NULL; + update_type_init(symbol->specification); + this->current_var_init_symbol = NULL; // We do NOt want to initialize external variables. + 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); diff -r 566414d7ba1f -r 477393b00f95 stage4/generate_c/generate_var_list.cc --- a/stage4/generate_c/generate_var_list.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage4/generate_c/generate_var_list.cc Sun Nov 16 12:54:10 2014 +0000 @@ -184,7 +184,7 @@ /***********************************************************************/ /***********************************************************************/ -class generate_var_list_c: protected generate_c_typedecl_c { +class generate_var_list_c: protected generate_c_base_and_typeid_c { public: typedef struct { @@ -222,7 +222,7 @@ public: generate_var_list_c(stage4out_c *s4o_ptr, symbol_c *scope) - : generate_c_typedecl_c(s4o_ptr) { + : generate_c_base_and_typeid_c(s4o_ptr) { search_type_symbol = new search_type_symbol_c(scope); current_var_number = 0; current_var_type_symbol = NULL; diff -r 566414d7ba1f -r 477393b00f95 stage4/generate_iec/generate_iec.cc --- a/stage4/generate_iec/generate_iec.cc Sat Oct 25 13:20:10 2014 +0100 +++ b/stage4/generate_iec/generate_iec.cc Sun Nov 16 12:54:10 2014 +0000 @@ -253,7 +253,8 @@ /*******************************************/ /* B 1.1 - Letters, digits and identifiers */ /*******************************************/ -void *visit(identifier_c *symbol) {return print_token(symbol);} +void *visit( identifier_c *symbol) {return print_token(symbol);} +void *visit(derived_datatype_identifier_c *symbol) {return print_token(symbol);} /*********************/ /* B 1.2 - Constants */