diff --git a/.DS_Store b/.DS_Store index 68b1d11..7a8c886 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..b4269a9 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,19 @@ +{ + "configurations": [ + { + "name": "Mac", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "macFrameworkPath": [ + "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks" + ], + "compilerPath": "/usr/bin/clang", + "cStandard": "c17", + "cppStandard": "c++17", + "intelliSenseMode": "macos-clang-x64" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9ddf6b2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.ignoreCMakeListsMissing": true +} \ No newline at end of file diff --git a/utils/.DS_Store b/utils/.DS_Store new file mode 100644 index 0000000..d8536e1 Binary files /dev/null and b/utils/.DS_Store differ diff --git a/utils/matiec_src/.DS_Store b/utils/matiec_src/.DS_Store new file mode 100644 index 0000000..5a7ddd1 Binary files /dev/null and b/utils/matiec_src/.DS_Store differ diff --git a/utils/matiec_src/absyntax/absyntax.cc b/utils/matiec_src/absyntax/absyntax.cc old mode 100755 new mode 100644 index 774cfbc..5bfc3e4 --- a/utils/matiec_src/absyntax/absyntax.cc +++ b/utils/matiec_src/absyntax/absyntax.cc @@ -58,6 +58,7 @@ symbol_c::symbol_c( this->last_column = last_column; this->last_order = last_order; this->parent = NULL; + this->token = NULL; this->datatype = NULL; this->scope = NULL; } @@ -69,6 +70,7 @@ token_c::token_c(const char *value, int ll, int lc, const char *lfile, long int lorder) :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { this->value = value; + this->token = this; // every token is its own reference token. // printf("New token: %s\n", value); } @@ -83,7 +85,7 @@ list_c::list_c( int ll, int lc, const char *lfile, long int lorder) :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder),c(LIST_CAP_INIT) { n = 0; - elements = (symbol_c**)malloc(LIST_CAP_INIT*sizeof(symbol_c*)); + elements = (element_entry_t*)malloc(LIST_CAP_INIT*sizeof(element_entry_t)); if (NULL == elements) ERROR_MSG("out of memory"); } @@ -93,20 +95,59 @@ list_c::list_c(symbol_c *elem, int ll, int lc, const char *lfile, long int lorder) :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder),c(LIST_CAP_INIT) { n = 0; - elements = (symbol_c**)malloc(LIST_CAP_INIT*sizeof(symbol_c*)); + elements = (element_entry_t*)malloc(LIST_CAP_INIT*sizeof(element_entry_t)); if (NULL == elements) ERROR_MSG("out of memory"); add_element(elem); } +/*******************************************/ +/* get element in position pos of the list */ +/*******************************************/ +symbol_c *list_c::get_element(int pos) {return elements[pos].symbol;} + + + +/******************************************/ +/* find element associated to token value */ +/******************************************/ +symbol_c *list_c::find_element(symbol_c *token) { + token_c *t = dynamic_cast(token); + if (t == NULL) ERROR; + return find_element((const char *)t->value); +} + +symbol_c *list_c::find_element(const char *token_value) { + // We could use strcasecmp(), but it's best to always use the same + // method of string comparison throughout matiec + nocasecmp_c ncc; + for (int i = 0; i < n; i++) + if (!ncc(elements[i].token_value, token_value)) + return elements[i].symbol; + + return NULL; // not found +} + + +/***********************************************/ /* append a new element to the end of the list */ -void list_c::add_element(symbol_c *elem) { - // printf("list_c::add_element()\n"); +/***********************************************/ +void list_c::add_element(symbol_c *elem) {add_element(elem, elem);} + +void list_c::add_element(symbol_c *elem, symbol_c *token) { + token_c *t = (token == NULL)? NULL : token->token; + add_element(elem, (t == NULL)? NULL : t->value); +} + +void list_c::add_element(symbol_c *elem, const char *token_value) { if (c <= n) - if (!(elements=(symbol_c**)realloc(elements,(c+=LIST_CAP_INCR)*sizeof(symbol_c *)))) + if (!(elements=(element_entry_t*)realloc(elements,(c+=LIST_CAP_INCR)*sizeof(element_entry_t)))) ERROR_MSG("out of memory"); - elements[n++] = elem; - + //elements[n++] = {token_value, elem}; // only available from C++11 onwards, best not use it for now. + elements[n].symbol = elem; + elements[n].token_value = token_value; + n++; + if (NULL == elem) return; /* Sometimes add_element() is called in stage3 or stage4 to temporarily add an AST symbol to the list. * Since this symbol already belongs in some other place in the aST, it will have the 'parent' pointer set, @@ -143,10 +184,21 @@ void list_c::add_element(symbol_c *elem) { } } + +/*********************************************/ /* insert a new element before position pos. */ +/*********************************************/ /* To insert into the begining of list, call with pos=0 */ /* To insert into the end of list, call with pos=list->n */ -void list_c::insert_element(symbol_c *elem, int pos) { + +void list_c::insert_element(symbol_c *elem, int pos) {insert_element(elem, elem, pos);} + +void list_c::insert_element(symbol_c *elem, symbol_c *token, int pos) { + token_c *t = (token == NULL)? NULL : token->token; + insert_element(elem, (t == NULL)? NULL : t->value, pos); +} + +void list_c::insert_element(symbol_c *elem, const char *token_value, int pos) { if((pos<0) || (n=pos ; --i) elements[i+1] = elements[i]; - elements[pos] = elem; + elements[pos].symbol = elem; + elements[pos].token_value = token_value; } } +/***********************************/ /* remove element at position pos. */ +/***********************************/ void list_c::remove_element(int pos) { if((pos<0) || (n<=pos)) ERROR; @@ -168,12 +223,14 @@ void list_c::remove_element(int pos) { for (int i = pos; i < n-1; i++) elements[i] = elements[i+1]; /* corrent the new size */ n--; - /* elements = (symbol_c **)realloc(elements, n * sizeof(symbol_c *)); */ + /* elements = (symbol_c **)realloc(elements, n * sizeof(element_entry_t)); */ /* TODO: adjust the location parameters, taking into account the removed element. */ } -/* remove element at position pos. */ +/**********************************/ +/* Remove all elements from list. */ +/**********************************/ void list_c::clear(void) { n = 0; /* TODO: adjust the location parameters, taking into account the removed element. */ diff --git a/utils/matiec_src/absyntax/absyntax.def b/utils/matiec_src/absyntax/absyntax.def index cfe9900..59efc56 100644 --- a/utils/matiec_src/absyntax/absyntax.def +++ b/utils/matiec_src/absyntax/absyntax.def @@ -267,6 +267,7 @@ SYM_REF0(dword_type_name_c) SYM_REF0(lword_type_name_c) SYM_REF0(string_type_name_c) SYM_REF0(wstring_type_name_c) +SYM_REF0(void_type_name_c) /* a non-standard extension! */ /*****************************************************************/ /* Keywords defined in "Safety Software Technical Specification" */ @@ -1287,4 +1288,5 @@ SYM_REF2(repeat_statement_c, statement_list, expression) /* EXIT */ SYM_REF0(exit_statement_c) - +/* continue */ +SYM_REF0(continue_statement_c) diff --git a/utils/matiec_src/absyntax/absyntax.hh b/utils/matiec_src/absyntax/absyntax.hh old mode 100755 new mode 100644 index 706d0e1..983feee --- a/utils/matiec_src/absyntax/absyntax.hh +++ b/utils/matiec_src/absyntax/absyntax.hh @@ -154,7 +154,8 @@ class const_value_c { {return (_int64.is_valid() || _uint64.is_valid() || _real64.is_valid() || _bool.is_valid());} }; - +// A forward declaration +class token_c; /* The base class of all symbols */ class symbol_c { @@ -167,7 +168,18 @@ class symbol_c { * Annotations produced during stage 1_2 */ /* Points to the parent symbol in the AST, i.e. the symbol in the AST that will contain the current symbol */ - symbol_c *parent; + symbol_c *parent; + /* Some symbols may not be tokens, but may be clearly identified by a token. + * For e.g., a FUNCTION declaration is not itself a token, but may be clearly identified by the + * token_c object that contains it's name. Another example is an element in a STRUCT declaration, + * where the structure_element_declaration_c is not itself a token, but can be clearly identified + * by the structure_element_name + * To make it easier to find these tokens from the top level object, we will have the stage1_2 populate this + * token_c *token wherever it makes sense. + * NOTE: This was a late addition to the AST. Not all objects may be currently so populated. + * If you need this please make sure the bison code is populating it correctly for your use case. + */ + token_c *token; /* Line number for the purposes of error checking. */ int first_line; @@ -260,7 +272,14 @@ class list_c: public symbol_c { virtual const char *absyntax_cname(void) {return "list_c";}; int c,n; /* c: current capacity of list (malloc'd memory); n: current number of elements in list */ - symbol_c **elements; + private: +// symbol_c **elements; + typedef struct { + const char *token_value; + symbol_c *symbol; + } element_entry_t; + element_entry_t *elements; + public: list_c(int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, /* order in which it is read by lexcial analyser */ @@ -271,12 +290,22 @@ class list_c: public symbol_c { int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, /* order in which it is read by lexcial analyser */ int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0 /* order in which it is read by lexcial analyser */ ); + /* get element in position pos of the list */ + virtual symbol_c *get_element(int pos); + /* find element associated to token value */ + virtual symbol_c *find_element(symbol_c *token); + virtual symbol_c *find_element(const char *token_value); /* append a new element to the end of the list */ virtual void add_element(symbol_c *elem); + virtual void add_element(symbol_c *elem, symbol_c *token); + virtual void add_element(symbol_c *elem, const char *token_value); /* insert a new element before position pos. */ /* To insert into the begining of list, call with pos=0 */ /* To insert into the end of list, call with pos=list->n */ - virtual void insert_element(symbol_c *elem, int pos = 0); + virtual void insert_element(symbol_c *elem, const char *token_value, int pos = 0); + virtual void insert_element(symbol_c *elem, symbol_c *token, int pos = 0); + virtual void insert_element(symbol_c *elem, int pos = 0); + //virtual void insert_element(symbol_c *elem, int pos, std::string map_ref); /* remove element at position pos. */ virtual void remove_element(int pos = 0); /* remove all elements from list. Does not delete the elements in the list! */ @@ -342,7 +371,7 @@ class class_name_c: public symbol_c { \ symbol_c *ref1; \ __VA_ARGS__ \ public: \ - class_name_c(symbol_c *ref1, \ + class_name_c(symbol_c *ref1 = NULL, \ int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ virtual void *accept(visitor_c &visitor); \ @@ -358,7 +387,7 @@ class class_name_c: public symbol_c { \ symbol_c *ref2; \ __VA_ARGS__ \ public: \ - class_name_c(symbol_c *ref1, \ + class_name_c(symbol_c *ref1 = NULL, \ symbol_c *ref2 = NULL, \ int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ @@ -376,9 +405,9 @@ class class_name_c: public symbol_c { \ symbol_c *ref3; \ __VA_ARGS__ \ public: \ - class_name_c(symbol_c *ref1, \ - symbol_c *ref2, \ - symbol_c *ref3, \ + class_name_c(symbol_c *ref1 = NULL, \ + symbol_c *ref2 = NULL, \ + symbol_c *ref3 = NULL, \ int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ virtual void *accept(visitor_c &visitor); \ @@ -396,9 +425,9 @@ class class_name_c: public symbol_c { \ symbol_c *ref4; \ __VA_ARGS__ \ public: \ - class_name_c(symbol_c *ref1, \ - symbol_c *ref2, \ - symbol_c *ref3, \ + class_name_c(symbol_c *ref1 = NULL, \ + symbol_c *ref2 = NULL, \ + symbol_c *ref3 = NULL, \ symbol_c *ref4 = NULL, \ int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ @@ -418,11 +447,11 @@ class class_name_c: public symbol_c { \ symbol_c *ref5; \ __VA_ARGS__ \ public: \ - class_name_c(symbol_c *ref1, \ - symbol_c *ref2, \ - symbol_c *ref3, \ - symbol_c *ref4, \ - symbol_c *ref5, \ + class_name_c(symbol_c *ref1 = NULL, \ + symbol_c *ref2 = NULL, \ + symbol_c *ref3 = NULL, \ + symbol_c *ref4 = NULL, \ + symbol_c *ref5 = NULL, \ int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ virtual void *accept(visitor_c &visitor); \ @@ -442,11 +471,11 @@ class class_name_c: public symbol_c { \ symbol_c *ref6; \ __VA_ARGS__ \ public: \ - class_name_c(symbol_c *ref1, \ - symbol_c *ref2, \ - symbol_c *ref3, \ - symbol_c *ref4, \ - symbol_c *ref5, \ + class_name_c(symbol_c *ref1 = NULL, \ + symbol_c *ref2 = NULL, \ + symbol_c *ref3 = NULL, \ + symbol_c *ref4 = NULL, \ + symbol_c *ref5 = NULL, \ symbol_c *ref6 = NULL, \ int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ diff --git a/utils/matiec_src/absyntax/visitor.cc b/utils/matiec_src/absyntax/visitor.cc old mode 100755 new mode 100644 index b70a83d..baa0704 --- a/utils/matiec_src/absyntax/visitor.cc +++ b/utils/matiec_src/absyntax/visitor.cc @@ -168,7 +168,7 @@ iterator_visitor_c::~iterator_visitor_c(void) {return;} void *iterator_visitor_c::visit_list(list_c *list) { for(int i = 0; i < list->n; i++) { - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); } return NULL; } @@ -310,7 +310,7 @@ search_visitor_c::~search_visitor_c(void) {return;} void *search_visitor_c::visit_list(list_c *list) { for(int i = 0; i < list->n; i++) { - void *res = list->elements[i]->accept(*this); + void *res = list->get_element(i)->accept(*this); if (res != NULL) return res; } diff --git a/utils/matiec_src/absyntax/visitor.hh b/utils/matiec_src/absyntax/visitor.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/add_en_eno_param_decl.cc b/utils/matiec_src/absyntax_utils/add_en_eno_param_decl.cc old mode 100755 new mode 100644 index d68d23c..1c1a983 --- a/utils/matiec_src/absyntax_utils/add_en_eno_param_decl.cc +++ b/utils/matiec_src/absyntax_utils/add_en_eno_param_decl.cc @@ -84,7 +84,7 @@ add_en_eno_param_decl_c::~add_en_eno_param_decl_c(void) { void* add_en_eno_param_decl_c::iterate_list(list_c *list) { for (int i = 0; i < list->n; i++) { - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); } return NULL; } diff --git a/utils/matiec_src/absyntax_utils/add_en_eno_param_decl.hh b/utils/matiec_src/absyntax_utils/add_en_eno_param_decl.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/array_dimension_iterator.cc b/utils/matiec_src/absyntax_utils/array_dimension_iterator.cc old mode 100755 new mode 100644 index 8065cd8..fe3e779 --- a/utils/matiec_src/absyntax_utils/array_dimension_iterator.cc +++ b/utils/matiec_src/absyntax_utils/array_dimension_iterator.cc @@ -64,7 +64,7 @@ void* array_dimension_iterator_c::iterate_list(list_c *list) { void *res; for (int i = 0; i < list->n; i++) { - res = list->elements[i]->accept(*this); + res = list->get_element(i)->accept(*this); if (res != NULL) return res; } diff --git a/utils/matiec_src/absyntax_utils/array_dimension_iterator.hh b/utils/matiec_src/absyntax_utils/array_dimension_iterator.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/case_element_iterator.cc b/utils/matiec_src/absyntax_utils/case_element_iterator.cc old mode 100755 new mode 100644 index bcd952b..86a4f09 --- a/utils/matiec_src/absyntax_utils/case_element_iterator.cc +++ b/utils/matiec_src/absyntax_utils/case_element_iterator.cc @@ -78,7 +78,7 @@ void* case_element_iterator_c::handle_case_element(symbol_c *case_element) { void* case_element_iterator_c::iterate_list(list_c *list) { void *res; for (int i = 0; i < list->n; i++) { - res = list->elements[i]->accept(*this); + res = list->get_element(i)->accept(*this); if (res != NULL) return res; } diff --git a/utils/matiec_src/absyntax_utils/case_element_iterator.hh b/utils/matiec_src/absyntax_utils/case_element_iterator.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/debug_ast.cc b/utils/matiec_src/absyntax_utils/debug_ast.cc index e7c97c5..c92a3af 100644 --- a/utils/matiec_src/absyntax_utils/debug_ast.cc +++ b/utils/matiec_src/absyntax_utils/debug_ast.cc @@ -56,12 +56,12 @@ static void dump_cvalue(const_value_c const_value) { else if (const_value._real64.is_nonconst()) fprintf(stderr, "nc"); else fprintf(stderr, "?"); fprintf(stderr, ", i="); - if (const_value. _int64.is_valid ()) fprintf(stderr, "%"PRId64"", const_value. _int64.get()); + if (const_value. _int64.is_valid ()) fprintf(stderr, "%" PRId64 "", const_value. _int64.get()); else if (const_value. _int64.is_overflow()) fprintf(stderr, "ov"); else if (const_value. _int64.is_nonconst()) fprintf(stderr, "nc"); else fprintf(stderr, "?"); fprintf(stderr, ", u="); - if (const_value._uint64.is_valid ()) fprintf(stderr, "%"PRIu64"", const_value._uint64.get()); + if (const_value._uint64.is_valid ()) fprintf(stderr, "%" PRIu64 "", const_value._uint64.get()); else if (const_value._uint64.is_overflow()) fprintf(stderr, "ov"); else if (const_value._uint64.is_nonconst()) fprintf(stderr, "nc"); else fprintf(stderr, "?"); @@ -120,13 +120,16 @@ void print_symbol_c::fcall(symbol_c* symbol) { void print_symbol_c::dump_symbol(symbol_c* symbol) { - fprintf(stderr, "(%s->%03d:%03d..%03d:%03d) \t%s\t", symbol->first_file, symbol->first_line, symbol->first_column, symbol->last_line, symbol->last_column, symbol->absyntax_cname()); + fprintf(stderr, "(%s->%03d:%03d..%03d:%03d) \t%s", symbol->first_file, symbol->first_line, symbol->first_column, symbol->last_line, symbol->last_column, symbol->absyntax_cname()); - fprintf(stderr, " datatype="); + if ((NULL != symbol->token) && (NULL != symbol->token->value)) + fprintf(stderr, "(%s)", symbol->token->value); + + fprintf(stderr, "\t datatype="); if (NULL == symbol->datatype) fprintf(stderr, "NULL\t\t"); else { - fprintf(stderr, "%s", symbol->datatype->absyntax_cname()); + fprintf(stderr, "%s", symbol->datatype->absyntax_cname()); } fprintf(stderr, "\t<-{"); if (symbol->candidate_datatypes.size() == 0) { @@ -153,26 +156,25 @@ void *print_symbol_c::visit(il_instruction_c *symbol) { dump_symbol(symbol); /* NOTE: std::map.size() returns a size_type, whose type is dependent on compiler/platform. To be portable, we need to do an explicit type cast. */ - fprintf(stderr, " next_il_=%lu ", (unsigned long int)symbol->next_il_instruction.size()); fprintf(stderr, " prev_il_=%lu ", (unsigned long int)symbol->prev_il_instruction.size()); - if (symbol->prev_il_instruction.size() == 0) - fprintf(stderr, "(----,"); + fprintf(stderr, "(----)"); else if (symbol->prev_il_instruction[0]->datatype == NULL) - fprintf(stderr, "(NULL,"); + fprintf(stderr, "(NULL)"); else if (!get_datatype_info_c::is_type_valid(symbol->prev_il_instruction[0]->datatype)) - fprintf(stderr, "(****,"); + fprintf(stderr, "(****)"); else - fprintf(stderr, "( ,"); - + fprintf(stderr, "( )"); + + fprintf(stderr, " next_il_=%lu ", (unsigned long int)symbol->next_il_instruction.size()); if (symbol->next_il_instruction.size() == 0) - fprintf(stderr, "----)"); + fprintf(stderr, "(----)"); else if (symbol->next_il_instruction[0]->datatype == NULL) - fprintf(stderr, "NULL)"); + fprintf(stderr, "(NULL)"); else if (!get_datatype_info_c::is_type_valid(symbol->next_il_instruction[0]->datatype)) - fprintf(stderr, "****)"); + fprintf(stderr, "(****)"); else - fprintf(stderr, " )"); + fprintf(stderr, "( )"); fprintf(stderr, "\n"); diff --git a/utils/matiec_src/absyntax_utils/decompose_var_instance_name.cc b/utils/matiec_src/absyntax_utils/decompose_var_instance_name.cc old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/decompose_var_instance_name.hh b/utils/matiec_src/absyntax_utils/decompose_var_instance_name.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/function_call_iterator.cc b/utils/matiec_src/absyntax_utils/function_call_iterator.cc old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/function_call_iterator.hh b/utils/matiec_src/absyntax_utils/function_call_iterator.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/function_call_param_iterator.cc b/utils/matiec_src/absyntax_utils/function_call_param_iterator.cc old mode 100755 new mode 100644 index fdb7847..f957507 --- a/utils/matiec_src/absyntax_utils/function_call_param_iterator.cc +++ b/utils/matiec_src/absyntax_utils/function_call_param_iterator.cc @@ -67,7 +67,7 @@ void *function_call_param_iterator_c::search_list(list_c *list) { switch (current_operation) { case iterate_nf_op: for(int i = 0; i < list->n; i++) { - void *res = list->elements[i]->accept(*this); + void *res = list->get_element(i)->accept(*this); if (NULL != res) { /* It went through the handle_parameter_assignment() function, * and is therefore a parameter assignment ( = ), @@ -77,7 +77,7 @@ void *function_call_param_iterator_c::search_list(list_c *list) { } else { param_count++; if (param_count == iterate_nf_next_param) { - return list->elements[i]; + return list->get_element(i); } } } @@ -86,7 +86,7 @@ void *function_call_param_iterator_c::search_list(list_c *list) { case iterate_f_op: for(int i = 0; i < list->n; i++) { - void *res = list->elements[i]->accept(*this); + void *res = list->get_element(i)->accept(*this); if (NULL != res) { /* It went through the handle_parameter_assignment() function, * and is therefore a parameter assignment ( = ), @@ -105,7 +105,7 @@ void *function_call_param_iterator_c::search_list(list_c *list) { case search_f_op: for(int i = 0; i < list->n; i++) { - void *res = list->elements[i]->accept(*this); + void *res = list->get_element(i)->accept(*this); if (res != NULL) return res; } diff --git a/utils/matiec_src/absyntax_utils/function_call_param_iterator.hh b/utils/matiec_src/absyntax_utils/function_call_param_iterator.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/function_param_iterator.cc b/utils/matiec_src/absyntax_utils/function_param_iterator.cc index 4b371e8..e852f30 100644 --- a/utils/matiec_src/absyntax_utils/function_param_iterator.cc +++ b/utils/matiec_src/absyntax_utils/function_param_iterator.cc @@ -167,7 +167,7 @@ void* function_param_iterator_c::handle_param_list(list_c *list) { switch (current_operation) { case iterate_op: if (next_param <= param_count + list->n) - return list->elements[next_param - param_count - 1]; + return list->get_element(next_param - param_count - 1); /* the desired param is not on this list... */ param_count += list->n; @@ -175,7 +175,7 @@ void* function_param_iterator_c::handle_param_list(list_c *list) { case search_op: for(int i = 0; i < list->n; i++) { - symbol_c *sym = list->elements[i]; + symbol_c *sym = list->get_element(i); extensible_input_parameter_c *extensible_parameter = dynamic_cast(sym); if (extensible_parameter != NULL) { sym = extensible_parameter->var_name; @@ -243,7 +243,7 @@ void* function_param_iterator_c::handle_single_param(symbol_c *var_name) { void* function_param_iterator_c::iterate_list(list_c *list) { void *res; for (int i = 0; i < list->n; i++) { - res = list->elements[i]->accept(*this); + res = list->get_element(i)->accept(*this); if (res != NULL) return res; } diff --git a/utils/matiec_src/absyntax_utils/function_param_iterator.hh b/utils/matiec_src/absyntax_utils/function_param_iterator.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/get_datatype_info.cc b/utils/matiec_src/absyntax_utils/get_datatype_info.cc index d0ec9ab..cb8e5d7 100644 --- a/utils/matiec_src/absyntax_utils/get_datatype_info.cc +++ b/utils/matiec_src/absyntax_utils/get_datatype_info.cc @@ -127,6 +127,8 @@ class get_datatype_id_c: null_visitor_c { void *visit(safestring_type_name_c *symbol) {return (void *)symbol;}; void *visit(safewstring_type_name_c *symbol) {return (void *)symbol;}; + void *visit(void_type_name_c *symbol) {return (void *)symbol;}; + /********************************/ /* B 1.3.3 - Derived data types */ /********************************/ @@ -260,6 +262,8 @@ class get_datatype_id_str_c: public null_visitor_c { void *visit(safestring_type_name_c *symbol) {return (void *)"SAFESTRING"; }; void *visit(safewstring_type_name_c *symbol) {return (void *)"SAFEWSTRING"; }; + void *visit(void_type_name_c *symbol) {return (void *)"VOID"; }; + /********************************/ /* B.1.3.2 - Generic data types */ /********************************/ @@ -358,7 +362,7 @@ class get_struct_info_c : null_visitor_c { void *visit(structure_element_declaration_list_c *symbol) { /* now search the structure declaration */ for(int i = 0; i < symbol->n; i++) { - void *tmp = symbol->elements[i]->accept(*this); + void *tmp = symbol->get_element(i)->accept(*this); if (NULL != tmp) return tmp; } return NULL; // not found!! @@ -709,8 +713,8 @@ bool get_datatype_info_c::is_arraytype_equal_relaxed(symbol_c *first_type, symbo // 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]); + subrange_c *subrange_1 = dynamic_cast(subrange_list_1->get_element(i)); + subrange_c *subrange_2 = dynamic_cast(subrange_list_2->get_element(i)); if ((NULL == subrange_1) || (NULL == subrange_2)) ERROR; /* check whether the subranges have the same values, using the result of the constant folding agorithm. @@ -1352,6 +1356,21 @@ bool get_datatype_info_c::is_ANY_STRING_compatible(symbol_c *type_symbol) { + +bool get_datatype_info_c::is_VOID(symbol_c *type_symbol) { + if (type_symbol == NULL) {return false;} + if (typeid(*type_symbol) == typeid(void_type_name_c)) {return true;} + return false; +} + + + + + + + + + /* Can't we do away with this?? */ bool get_datatype_info_c::is_ANY_REAL_literal(symbol_c *type_symbol) { if (type_symbol == NULL) {return true;} /* Please make sure things will work correctly before changing this to false!! */ @@ -1381,6 +1400,7 @@ bool get_datatype_info_c::is_ANY_INT_literal(symbol_c *type_symbol) { invalid_type_name_c get_datatype_info_c::invalid_type_name; +generic_type_any_c get_datatype_info_c::any_type_name; /**********************/ /* B.1.3 - Data types */ diff --git a/utils/matiec_src/absyntax_utils/get_datatype_info.hh b/utils/matiec_src/absyntax_utils/get_datatype_info.hh index 4031432..083193c 100644 --- a/utils/matiec_src/absyntax_utils/get_datatype_info.hh +++ b/utils/matiec_src/absyntax_utils/get_datatype_info.hh @@ -165,6 +165,8 @@ class get_datatype_info_c { static bool is_ANY_SAFESTRING (symbol_c *type_symbol); static bool is_ANY_STRING_compatible (symbol_c *type_symbol); + // A non-standard extension --> data type 'VOID' (used for functions that do not return any data) + static bool is_VOID (symbol_c *type_symbol); @@ -173,6 +175,9 @@ class get_datatype_info_c { /* This is only used from stage3 onwards. Stages 1 and 2 will never create any instances of invalid_type_name_c */ static invalid_type_name_c invalid_type_name; + /* object used to identify ANY datya type */ + static generic_type_any_c any_type_name; + /**********************/ /* B.1.3 - Data types */ /**********************/ diff --git a/utils/matiec_src/absyntax_utils/get_sizeof_datatype.cc b/utils/matiec_src/absyntax_utils/get_sizeof_datatype.cc old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/get_sizeof_datatype.hh b/utils/matiec_src/absyntax_utils/get_sizeof_datatype.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/search_base_type.cc b/utils/matiec_src/absyntax_utils/search_base_type.cc old mode 100755 new mode 100644 index 1c514cb..8f9d445 --- a/utils/matiec_src/absyntax_utils/search_base_type.cc +++ b/utils/matiec_src/absyntax_utils/search_base_type.cc @@ -184,6 +184,8 @@ void *search_base_type_c::visit(lword_type_name_c *symbol) {return (void void *search_base_type_c::visit(string_type_name_c *symbol) {return (void *)symbol;} void *search_base_type_c::visit(wstring_type_name_c *symbol) {return (void *)symbol;} +/* A non standard datatype! */ +void *search_base_type_c::visit(void_type_name_c *symbol) {return (void *)symbol;} /******************************************************/ /* Extensions to the base standard as defined in */ @@ -253,7 +255,7 @@ void *search_base_type_c::visit(subrange_specification_c *symbol) { } /* signed_integer DOTDOT signed_integer */ -void *search_base_type_c::visit(subrange_c *symbol) {ERROR; return NULL;} /* should never get called... */ +void *search_base_type_c::visit(subrange_c *symbol) {ERROR; return NULL;} /* should never get called... */ /* enumerated_type_name ':' enumerated_spec_init */ void *search_base_type_c::visit(enumerated_type_declaration_c *symbol) { @@ -291,7 +293,7 @@ void *search_base_type_c::visit(enumerated_value_list_c *symbol) { /* enumerated_type_name '#' identifier */ // SYM_REF2(enumerated_value_c, type, value) -void *search_base_type_c::visit(enumerated_value_c *symbol) {ERROR; return NULL;} /* should never get called... */ +void *search_base_type_c::visit(enumerated_value_c *symbol) {ERROR; return NULL;} /* should never get called... */ /* identifier ':' array_spec_init */ void *search_base_type_c::visit(array_type_declaration_c *symbol) { @@ -310,20 +312,20 @@ void *search_base_type_c::visit(array_spec_init_c *symbol) { } /* ARRAY '[' array_subrange_list ']' OF non_generic_type_name */ -void *search_base_type_c::visit(array_specification_c *symbol) {return (void *)symbol;} +void *search_base_type_c::visit(array_specification_c *symbol) {return (void *)symbol;} /* helper symbol for array_specification */ /* array_subrange_list ',' subrange */ -void *search_base_type_c::visit(array_subrange_list_c *symbol) {ERROR; return NULL;} /* should never get called... */ +void *search_base_type_c::visit(array_subrange_list_c *symbol) {ERROR; return NULL;} /* should never get called... */ /* array_initialization: '[' array_initial_elements_list ']' */ /* helper symbol for array_initialization */ /* array_initial_elements_list ',' array_initial_elements */ -void *search_base_type_c::visit(array_initial_elements_list_c *symbol) {ERROR; return NULL;} /* should never get called... */ +void *search_base_type_c::visit(array_initial_elements_list_c *symbol) {ERROR; return NULL;} /* should never get called... */ /* integer '(' [array_initial_element] ')' */ /* array_initial_element may be NULL ! */ -void *search_base_type_c::visit(array_initial_elements_c *symbol) {ERROR; return NULL;} /* should never get called... */ +void *search_base_type_c::visit(array_initial_elements_c *symbol) {ERROR; return NULL;} /* should never get called... */ /* structure_type_name ':' structure_specification */ /* NOTE: structure_specification will point to either a @@ -337,31 +339,27 @@ void *search_base_type_c::visit(structure_type_declaration_c *symbol) { } /* var1_list ':' structure_type_name */ -void *search_base_type_c::visit(structured_var_declaration_c *symbol) { - return symbol; -} +void *search_base_type_c::visit(structured_var_declaration_c *symbol) {return symbol;} /* structure_type_name ASSIGN structure_initialization */ /* structure_initialization may be NULL ! */ -void *search_base_type_c::visit(initialized_structure_c *symbol) { - return symbol->structure_type_name->accept(*this); -} +void *search_base_type_c::visit(initialized_structure_c *symbol) {return symbol->structure_type_name->accept(*this);} /* helper symbol for structure_declaration */ /* structure_declaration: STRUCT structure_element_declaration_list END_STRUCT */ /* structure_element_declaration_list structure_element_declaration ';' */ -void *search_base_type_c::visit(structure_element_declaration_list_c *symbol) {return (void *)symbol;} +void *search_base_type_c::visit(structure_element_declaration_list_c *symbol) {return (void *)symbol;} /* structure_element_name ':' *_spec_init */ -void *search_base_type_c::visit(structure_element_declaration_c *symbol) {ERROR; return NULL;} /* should never get called... */ +void *search_base_type_c::visit(structure_element_declaration_c *symbol) {return symbol->spec_init->accept(*this);} /* helper symbol for structure_initialization */ /* structure_initialization: '(' structure_element_initialization_list ')' */ /* structure_element_initialization_list ',' structure_element_initialization */ -void *search_base_type_c::visit(structure_element_initialization_list_c *symbol) {ERROR; return NULL;} /* should never get called... */ +void *search_base_type_c::visit(structure_element_initialization_list_c *symbol) {ERROR; return NULL;} /* should never get called... */ /* structure_element_name ASSIGN value */ -void *search_base_type_c::visit(structure_element_initialization_c *symbol) {ERROR; return NULL;} /* should never get called... */ +void *search_base_type_c::visit(structure_element_initialization_c *symbol) {ERROR; return NULL;} /* should never get called... */ /* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */ /* @@ -370,7 +368,7 @@ SYM_REF4(string_type_declaration_c, string_type_name, string_type_declaration_size, string_type_declaration_init) // may be == NULL! */ -void *search_base_type_c::visit(string_type_declaration_c *symbol) {return (void *)symbol;} +void *search_base_type_c::visit(string_type_declaration_c *symbol) {return (void *)symbol;} /* function_block_type_name ASSIGN structure_initialization */ @@ -384,15 +382,13 @@ void *search_base_type_c::visit(fb_spec_init_c *symbol) { /* ref_spec: REF_TO (non_generic_type_name | function_block_type_name) */ // SYM_REF1(ref_spec_c, type_name) -void *search_base_type_c::visit(ref_spec_c *symbol) {return (void *)symbol;} +void *search_base_type_c::visit(ref_spec_c *symbol) {return (void *)symbol;} /* 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 *search_base_type_c::visit(ref_spec_init_c *symbol) { - return symbol->ref_spec->accept(*this); -} +void *search_base_type_c::visit(ref_spec_init_c *symbol) {return symbol->ref_spec->accept(*this);} /* ref_type_decl: identifier ':' ref_spec_init */ // SYM_REF2(ref_type_decl_c, ref_type_name, ref_spec_init) @@ -408,9 +404,7 @@ void *search_base_type_c::visit(ref_type_decl_c *symbol) { /*****************************/ /* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */ // SYM_REF3(function_block_declaration_c, fblock_name, var_declarations, fblock_body) -void *search_base_type_c::visit(function_block_declaration_c *symbol) { - return (void *)symbol; -} +void *search_base_type_c::visit(function_block_declaration_c *symbol) {return (void *)symbol;} diff --git a/utils/matiec_src/absyntax_utils/search_base_type.hh b/utils/matiec_src/absyntax_utils/search_base_type.hh old mode 100755 new mode 100644 index 6dca91a..f803c1b --- a/utils/matiec_src/absyntax_utils/search_base_type.hh +++ b/utils/matiec_src/absyntax_utils/search_base_type.hh @@ -141,6 +141,7 @@ class search_base_type_c: public null_visitor_c { void *visit(lword_type_name_c *symbol); void *visit(string_type_name_c *symbol); void *visit(wstring_type_name_c *symbol); + void *visit(void_type_name_c *symbol); /* A non standard datatype! */ /******************************************************/ /* Extensions to the base standard as defined in */ diff --git a/utils/matiec_src/absyntax_utils/search_fb_instance_decl.cc b/utils/matiec_src/absyntax_utils/search_fb_instance_decl.cc old mode 100755 new mode 100644 index 3d75fb8..4fe68cc --- a/utils/matiec_src/absyntax_utils/search_fb_instance_decl.cc +++ b/utils/matiec_src/absyntax_utils/search_fb_instance_decl.cc @@ -95,7 +95,7 @@ void *search_fb_instance_decl_c::visit(fb_name_decl_c *symbol) { void *search_fb_instance_decl_c::visit(fb_name_list_c *symbol) { list_c *list = symbol; for(int i = 0; i < list->n; i++) { - if (compare_identifiers(list->elements[i], search_name) == 0) + if (compare_identifiers(list->get_element(i), search_name) == 0) /* by now, current_fb_declaration should be != NULL */ return current_fb_type_name; } diff --git a/utils/matiec_src/absyntax_utils/search_fb_instance_decl.hh b/utils/matiec_src/absyntax_utils/search_fb_instance_decl.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/search_fb_typedecl.cc b/utils/matiec_src/absyntax_utils/search_fb_typedecl.cc old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/search_fb_typedecl.hh b/utils/matiec_src/absyntax_utils/search_fb_typedecl.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/search_var_instance_decl.cc b/utils/matiec_src/absyntax_utils/search_var_instance_decl.cc index 1bb8674..128a678 100644 --- a/utils/matiec_src/absyntax_utils/search_var_instance_decl.cc +++ b/utils/matiec_src/absyntax_utils/search_var_instance_decl.cc @@ -313,7 +313,7 @@ void *search_var_instance_decl_c::visit(var1_init_decl_c *symbol) { void *search_var_instance_decl_c::visit(var1_list_c *symbol) { list_c *list = symbol; for(int i = 0; i < list->n; i++) { - if (compare_identifiers(list->elements[i], search_name) == 0) + if (compare_identifiers(list->get_element(i), search_name) == 0) /* by now, current_type_decl should be != NULL */ return current_type_decl; } @@ -335,7 +335,7 @@ void *search_var_instance_decl_c::visit(fb_name_decl_c *symbol) { void *search_var_instance_decl_c::visit(fb_name_list_c *symbol) { list_c *list = symbol; for(int i = 0; i < list->n; i++) { - if (compare_identifiers(list->elements[i], search_name) == 0) + if (compare_identifiers(list->get_element(i), search_name) == 0) /* by now, current_fb_declaration should be != NULL */ return current_type_decl; } @@ -409,7 +409,7 @@ void *search_var_instance_decl_c::visit(global_var_spec_c *symbol) { void *search_var_instance_decl_c::visit(global_var_list_c *symbol) { list_c *list = symbol; for(int i = 0; i < list->n; i++) { - if (compare_identifiers(list->elements[i], search_name) == 0) + if (compare_identifiers(list->get_element(i), search_name) == 0) /* by now, current_type_decl should be != NULL */ return current_type_decl; } diff --git a/utils/matiec_src/absyntax_utils/search_varfb_instance_type.cc b/utils/matiec_src/absyntax_utils/search_varfb_instance_type.cc old mode 100755 new mode 100644 index 5eadec9..8cd678c --- a/utils/matiec_src/absyntax_utils/search_varfb_instance_type.cc +++ b/utils/matiec_src/absyntax_utils/search_varfb_instance_type.cc @@ -244,7 +244,7 @@ void *search_varfb_instance_type_c::visit(structure_element_declaration_list_c * /* now search the structure declaration */ for(int i = 0; i < symbol->n; i++) { - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); } return NULL; diff --git a/utils/matiec_src/absyntax_utils/search_varfb_instance_type.hh b/utils/matiec_src/absyntax_utils/search_varfb_instance_type.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/spec_init_separator.cc b/utils/matiec_src/absyntax_utils/spec_init_separator.cc old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/spec_init_separator.hh b/utils/matiec_src/absyntax_utils/spec_init_separator.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/absyntax_utils/type_initial_value.cc b/utils/matiec_src/absyntax_utils/type_initial_value.cc index 28762d5..40e26d8 100644 --- a/utils/matiec_src/absyntax_utils/type_initial_value.cc +++ b/utils/matiec_src/absyntax_utils/type_initial_value.cc @@ -224,7 +224,7 @@ void *type_initial_value_c::visit(enumerated_value_list_c *symbol) { /* stage1_2 never creates an enumerated_value_list_c with no entries. If this occurs, then something must have changed! */ if (symbol->n <= 0) ERROR; /* if no initial value explicitly given, then use the lowest value of the subrange */ - return (void *)symbol->elements[0]; + return (void *)symbol->get_element(0); } /* enumerated_type_name '#' identifier */ // SYM_REF2(enumerated_value_c, type, value) diff --git a/utils/matiec_src/absyntax_utils/type_initial_value.hh b/utils/matiec_src/absyntax_utils/type_initial_value.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/configure.ac b/utils/matiec_src/configure.ac index d61b3cf..47c7d8f 100644 --- a/utils/matiec_src/configure.ac +++ b/utils/matiec_src/configure.ac @@ -28,8 +28,7 @@ AC_PROG_RANLIB AC_PROG_AWK # Check bison version, we need a version great or equal than 2.4 to build matiec. -version_bison="$(bison --version | sed q | cut -d' ' -f4)" -version_bison=${version_bison:0:3} +version_bison="$(bison --version | sed q | cut -d' ' -f4 | cut -d'.' -f1,2 )" AS_IF([awk -v ver="$version_bison" 'BEGIN { if (ver < 2.4) exit 1; }'], [have_bison_correct=yes], [have_bison_correct=no]) @@ -42,6 +41,10 @@ if test "x${have_bison_correct}" = xno; then (exit 1); exit 1; fi +if test "x$LEX" == "x:"; then + AC_MSG_ERROR("flex/lex is missing") +fi + # Checks for header files. AC_CHECK_HEADERS([float.h limits.h stdint.h stdlib.h string.h strings.h sys/timeb.h unistd.h]) diff --git a/utils/matiec_src/main.cc b/utils/matiec_src/main.cc old mode 100755 new mode 100644 index 582b408..6f7efba --- a/utils/matiec_src/main.cc +++ b/utils/matiec_src/main.cc @@ -122,6 +122,7 @@ static void printusage(const char *cmd) { printf(" as well as REF_TO in ARRAYs and STRUCTs (a non-standard extension!)\n"); printf(" -a : allow use of non-literals in array size limits (a non-standard extension!)\n"); printf(" -i : allow POUs with no in out and inout parameters (a non-standard extension!)\n"); + printf(" -b : allow functions returning VOID (a non-standard extension!)\n"); printf(" -e : disable generation of implicit EN and ENO parameters.\n"); printf(" -c : create conversion functions for enumerated data types\n"); printf(" -O : options for output (code generation) stage. Available options for %s are...\n", cmd); @@ -145,6 +146,7 @@ int main(int argc, char **argv) { int path_len; /* Default values for the command line options... */ + runtime_options.allow_void_datatype = false; /* disable: allow declaration of functions returning VOID */ runtime_options.allow_missing_var_in = false; /* disable: allow definition and invocation of POUs with no input, output and in_out parameters! */ runtime_options.disable_implicit_en_eno = false; /* disable: do not generate EN and ENO parameters */ runtime_options.pre_parsing = false; /* disable: allow use of forward references (run pre-parsing phase before the definitive parsing phase that builds the AST) */ @@ -163,7 +165,7 @@ int main(int argc, char **argv) { /******************************************/ /* Parse command line options... */ /******************************************/ - while ((optres = getopt(argc, argv, ":nehvfplsrRaicI:T:O:")) != -1) { + while ((optres = getopt(argc, argv, ":nehvfplsrRabicI:T:O:")) != -1) { switch(optres) { case 'h': printusage(argv[0]); @@ -179,6 +181,7 @@ int main(int argc, char **argv) { runtime_options.ref_nonstand_extensions = true; break; case 'r': runtime_options.ref_standard_extensions = true; break; case 'a': runtime_options.nonliteral_in_array_size = true; break; + case 'b': runtime_options.allow_void_datatype = true; break; case 'i': runtime_options.allow_missing_var_in = true; break; case 'c': runtime_options.conversion_functions = true; break; case 'n': runtime_options.nested_comments = true; break; diff --git a/utils/matiec_src/main.hh b/utils/matiec_src/main.hh index 6d2d879..0411712 100644 --- a/utils/matiec_src/main.hh +++ b/utils/matiec_src/main.hh @@ -40,6 +40,7 @@ typedef struct { /* options specific to stage1_2 */ + bool allow_void_datatype; /* Allow declaration of functions returning VOID */ bool allow_missing_var_in; /* Allow definition and invocation of POUs with no input, output and in_out parameters! */ bool disable_implicit_en_eno; /* Disable the generation of implicit EN and ENO parameters on functions and Function Blocks */ bool pre_parsing; /* Support forward references (Run a pre-parsing phase before the defintive parsing phase that builds the AST) */ diff --git a/utils/matiec_src/stage1_2/Makefile.am b/utils/matiec_src/stage1_2/Makefile.am index 0b58249..b70b902 100644 --- a/utils/matiec_src/stage1_2/Makefile.am +++ b/utils/matiec_src/stage1_2/Makefile.am @@ -1,7 +1,9 @@ include ../common.mk +## Flags for yacc syntax parser generator (bison) AM_YFLAGS = -d -AM_LFLAGS = -o$(LEX_OUTPUT_ROOT).c +## Flags for lex lexer generator (flex) +AM_LFLAGS = --warn -o$(LEX_OUTPUT_ROOT).c # Make sure this header file is generated first (by bison), as it is included # by other C++ code that will also be compiled. diff --git a/utils/matiec_src/stage1_2/create_enumtype_conversion_functions.cc b/utils/matiec_src/stage1_2/create_enumtype_conversion_functions.cc index 4b1aad1..3253e38 100644 --- a/utils/matiec_src/stage1_2/create_enumtype_conversion_functions.cc +++ b/utils/matiec_src/stage1_2/create_enumtype_conversion_functions.cc @@ -119,7 +119,7 @@ void *create_enumtype_conversion_functions_c::visit(enumerated_value_list_c *sym currentTokenList.clear(); list = (list_c *)symbol; for (int i = 0; i < list->n; i++) { - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); currentTokenList.push_back(currentToken); } diff --git a/utils/matiec_src/stage1_2/iec_bison.yy b/utils/matiec_src/stage1_2/iec_bison.yy index 2b03fb2..43fa661 100644 --- a/utils/matiec_src/stage1_2/iec_bison.yy +++ b/utils/matiec_src/stage1_2/iec_bison.yy @@ -119,7 +119,7 @@ void yyerror (const char *error_msg); #define FOR_EACH_ELEMENT(elem, list, code) { \ symbol_c *elem; \ for(int i = 0; i < list->n; i++) { \ - elem = list->elements[i]; \ + elem = list->get_element(i); \ code; \ } \ } @@ -373,6 +373,32 @@ typedef struct YYLTYPE { %type prev_declared_derived_function_block_name %type prev_declared_program_type_name +/* Tokens used to help resolve a reduce/reduce conflict */ +/* The mentioned conflict only arises due to a non-standard feature added to matiec. + * Namely, the permission to call functions returning VOID as an ST statement. + * e.g.: FUNCTION foo: VOID + * VAR_INPUT i: INT; END_VAR; + * ... + * END_FUNCTION + * + * FUNCTION BAR: BOOL + * VAR b: bool; END_VAR + * foo(i:=42); <--- Calling foo outside an expression. Function invocation is considered an ST statement!! + * END_FUNCTION + * + * The above function invocation may also be reduced to a formal IL function invocation, so we get a + * reduce/reduce conflict to st_statement_list/instruction_list (or something equivalent). + * + * We solve this by having flex determine if it is ST or IL invocation (ST ends with a ';' !!). + * At the start of a function/FB/program body, flex will tell bison whether to expect ST or IL code! + * This is why we need the following two tokens! + * + * NOTE: flex was already determing whther it was parsing ST or IL code as it can only send + * EOL tokens when parsing IL. However, did this silently without telling bison about this. + * Now, it does + */ +%token start_ST_body_token +%token start_IL_body_token @@ -650,6 +676,9 @@ typedef struct YYLTYPE { %token TIME_OF_DAY %token TOD +/* A non-standard extension! */ +%token VOID + /******************************************************/ /* Symbols defined in */ /* "Safety Software Technical Specification, */ @@ -1425,6 +1454,7 @@ typedef struct YYLTYPE { %type while_statement %type repeat_statement %type exit_statement +%type continue_statement /* Integrated directly into for_statement */ // %type for_list @@ -1444,6 +1474,7 @@ typedef struct YYLTYPE { %token END_REPEAT %token EXIT +%token CONTINUE %% @@ -3184,15 +3215,15 @@ structure_element_declaration_list: structure_element_declaration: structure_element_name ':' simple_spec_init - {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} + {$$ = new structure_element_declaration_c($1, $3, locloc(@$)); $$->token = $1->token;} | structure_element_name ':' subrange_spec_init - {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} + {$$ = new structure_element_declaration_c($1, $3, locloc(@$)); $$->token = $1->token;} | structure_element_name ':' enumerated_spec_init - {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} + {$$ = new structure_element_declaration_c($1, $3, locloc(@$)); $$->token = $1->token;} | structure_element_name ':' array_spec_init - {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} + {$$ = new structure_element_declaration_c($1, $3, locloc(@$)); $$->token = $1->token;} | structure_element_name ':' initialized_structure - {$$ = new structure_element_declaration_c($1, $3, locloc(@$));} + {$$ = new structure_element_declaration_c($1, $3, locloc(@$)); $$->token = $1->token;} | structure_element_name ':' ref_spec_init /* non standard extension: Allow use of struct elements storing REF_TO datatypes (either using REF_TO or a previosuly declared ref type) */ { $$ = new structure_element_declaration_c($1, $3, locloc(@$)); if (!allow_ref_to_in_derived_datatypes) { @@ -3506,7 +3537,7 @@ variable: symbolic_variable | prev_declared_direct_variable | eno_identifier - {$$ = new symbolic_variable_c($1, locloc(@$));} + {$$ = new symbolic_variable_c($1, locloc(@$)); $$->token = $1->token;} ; @@ -3515,15 +3546,15 @@ symbolic_variable: * prev_declared_variable_name | prev_declared_fb_name | prev_declared_global_var_name */ prev_declared_fb_name - {$$ = new symbolic_variable_c($1, locloc(@$));} + {$$ = new symbolic_variable_c($1, locloc(@$)); $$->token = $1->token;} | prev_declared_global_var_name - {$$ = new symbolic_variable_c($1, locloc(@$));} + {$$ = new symbolic_variable_c($1, locloc(@$)); $$->token = $1->token;} | prev_declared_variable_name - {$$ = new symbolic_variable_c($1, locloc(@$));} + {$$ = new symbolic_variable_c($1, locloc(@$)); $$->token = $1->token;} | multi_element_variable /* | identifier - {$$ = new symbolic_variable_c($1, locloc(@$));} + {$$ = new symbolic_variable_c($1, locloc(@$)); $$->token = $1->token;} */ | symbolic_variable '^' /* Dereferencing operator defined in IEC 61131-3 v3. However, implemented here differently then how it is defined in the standard! See following note for explanation! */ @@ -3565,7 +3596,7 @@ symbolic_variable: any_symbolic_variable: // variable_name -> replaced by any_identifier any_identifier - {$$ = new symbolic_variable_c($1, locloc(@$));} + {$$ = new symbolic_variable_c($1, locloc(@$)); $$->token = $1->token;} | any_multi_element_variable ; @@ -5008,6 +5039,14 @@ function_declaration: direct_variable_symtable.pop(); library_element_symtable.insert($1, prev_declared_derived_function_name_token); } +/* | FUNCTION derived_function_name ':' VOID io_OR_function_var_declarations_list function_body END_FUNCTION */ +| function_name_declaration ':' VOID io_OR_function_var_declarations_list function_body END_FUNCTION + {$$ = new function_declaration_c($1, new void_type_name_c(locloc(@3)), $4, $5, locloc(@$)); + if (!runtime_options.disable_implicit_en_eno) add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ + variable_name_symtable.pop(); + direct_variable_symtable.pop(); + library_element_symtable.insert($1, prev_declared_derived_function_name_token); + } /* ERROR_CHECK_BEGIN */ | function_name_declaration elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing after function name in function declaration."); yynerrs++;} @@ -5172,8 +5211,8 @@ var2_init_decl_list: function_body: - statement_list {$$ = $1;} /* if we leave it for the default action we get a type clash! */ -| instruction_list {$$ = $1;} /* if we leave it for the default action we get a type clash! */ + start_ST_body_token statement_list {$$ = $2;} +| start_IL_body_token instruction_list {$$ = $2;} /* | ladder_diagram | function_block_diagram @@ -5246,7 +5285,7 @@ function_block_declaration: {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared and body defined in function block declaration."); yynerrs++;} */ | FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_OF_INPUT - {$$ = NULL; print_err_msg(locf(@1), locl(@2), "no variable(s) declared and body defined in function block declaration."); yynerrs++;} + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "expecting END_FUNCTION_BLOCK before end of file."); yynerrs++;} | FUNCTION_BLOCK error END_FUNCTION_BLOCK {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in function block declaration."); yyerrok;} /* ERROR_CHECK_END */ @@ -5355,9 +5394,21 @@ non_retentive_var_decls: function_block_body: - statement_list {$$ = $1;} -| instruction_list {$$ = $1;} -| sequential_function_chart {$$ = $1;} + /* NOTE: start_ST_body_token is a dummy token generated by flex when it determines it is starting to parse a POU body in ST + * start_IL_body_token is a dummy token generated by flex when it determines it is starting to parse a POU body in IL + * These tokens help remove a reduce/reduce conflict in bison, between a formal function invocation in IL, and a + * function invocation used as a statement (a non-standard extension added to matiec) + * e.g: FUNCTION_BLOCK foo + * VAR ... END_VAR + * func_returning_void(in1 := 3 + * ); --> only the presence or absence of ';' will determine whether this is a IL or ST + * function invocation. (In standard ST this would be ilegal, in matiec we allow it + * when activated by a command line option) + * END_FUNCTION + */ + start_ST_body_token statement_list {$$ = $2;} +| start_IL_body_token instruction_list {$$ = $2;} +| sequential_function_chart {$$ = $1;} /* | ladder_diagram | function_block_diagram @@ -5797,17 +5848,17 @@ transition_priority: transition_condition: - ':' eol_list simple_instr_list - {$$ = new transition_condition_c($3, NULL, locloc(@$));} + start_IL_body_token ':' eol_list simple_instr_list + {$$ = new transition_condition_c($4, NULL, locloc(@$));} | ASSIGN expression ';' {$$ = new transition_condition_c(NULL, $2, locloc(@$));} /* ERROR_CHECK_BEGIN */ -| eol_list simple_instr_list - {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing before IL condition in transition declaration."); yynerrs++;} -| ':' eol_list error +| start_IL_body_token eol_list simple_instr_list + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "':' missing before IL condition in transition declaration."); yynerrs++;} +| start_IL_body_token ':' eol_list error {$$ = NULL; - if (is_current_syntax_token()) {print_err_msg(locl(@2), locf(@3), "no instructions defined in IL condition of transition declaration.");} - else {print_err_msg(locf(@3), locl(@3), "invalid instructions in IL condition of transition declaration."); yyclearin;} + if (is_current_syntax_token()) {print_err_msg(locl(@3), locf(@4), "no instructions defined in IL condition of transition declaration.");} + else {print_err_msg(locf(@4), locl(@4), "invalid instructions in IL condition of transition declaration."); yyclearin;} yyerrok; } | ASSIGN ';' @@ -7856,6 +7907,15 @@ statement: | subprogram_control_statement | selection_statement | iteration_statement +| function_invocation + { /* This is a non-standard extension (calling a function outside an ST expression!) */ + /* Only allow this if command line option has been selected... */ + $$ = $1; + if (!runtime_options.allow_void_datatype) { + print_err_msg(locf(@1), locl(@1), "Function invocation in ST code is not allowed outside an expression. To allow this non-standard syntax, activate the apropriate command line option."); + yynerrs++; + } + } ; @@ -8248,6 +8308,7 @@ iteration_statement: | while_statement | repeat_statement | exit_statement +| continue_statement ; @@ -8330,7 +8391,7 @@ for_statement: */ control_variable: prev_declared_variable_name - {$$ = new symbolic_variable_c($1,locloc(@$));}; + {$$ = new symbolic_variable_c($1,locloc(@$)); $$->token = $1->token;}; // control_variable: identifier {$$ = $1;}; /* Integrated directly into for_statement */ @@ -8391,7 +8452,9 @@ exit_statement: EXIT {$$ = new exit_statement_c(locloc(@$));} ; - +continue_statement: + CONTINUE {$$ = new continue_statement_c(locloc(@$));} +; diff --git a/utils/matiec_src/stage1_2/iec_flex.ll b/utils/matiec_src/stage1_2/iec_flex.ll index f816903..be612ef 100644 --- a/utils/matiec_src/stage1_2/iec_flex.ll +++ b/utils/matiec_src/stage1_2/iec_flex.ll @@ -96,6 +96,11 @@ %option nounput */ +/* The '%option debug' makes the generated scanner run in + * debug mode. +%option debug + */ + /**************************************************/ /* External Variable and Function declarations... */ /**************************************************/ @@ -173,20 +178,24 @@ b*/ * back to the bison parser... */ #define YY_USER_ACTION {\ - yylloc.first_line = current_tracking->lineNumber; \ - yylloc.first_column = current_tracking->currentTokenStart; \ - yylloc.first_file = current_filename; \ - yylloc.first_order = current_order; \ - yylloc.last_line = current_tracking->lineNumber; \ - yylloc.last_column = current_tracking->currentChar - 1; \ - yylloc.last_file = current_filename; \ - yylloc.last_order = current_order; \ + previous_tracking =*current_tracking; \ + yylloc.first_line = current_tracking->lineNumber; \ + yylloc.first_column = current_tracking->currentChar; \ + yylloc.first_file = current_filename; \ + yylloc.first_order = current_order; \ + \ + UpdateTracking(yytext); \ + \ + yylloc.last_line = current_tracking->lineNumber; \ + yylloc.last_column = current_tracking->currentChar - 1; \ + yylloc.last_file = current_filename; \ + yylloc.last_order = current_order; \ + \ current_tracking->currentTokenStart = current_tracking->currentChar; \ current_order++; \ } - /* Since this lexical parser we defined only works in ASCII based * systems, we might as well make sure it is being compiled on * one... @@ -217,15 +226,30 @@ int get_identifier_token(const char *identifier_str); /***************************************************/ %{ +void UpdateTracking(const char *text); +/* return the character back to the input stream. */ +void unput_char(const char c); /* return all the text in the current token back to the input stream. */ -void unput_text(unsigned int n); +void unput_text(int n); /* return all the text in the current token back to the input stream, * but first return to the stream an additional character to mark the end of the token. */ -void unput_and_mark(const char c); +void unput_and_mark(const char mark_char); void include_file(const char *include_filename); +/* The body_state tries to find a ';' before a END_PROGRAM, END_FUNCTION or END_FUNCTION_BLOCK or END_ACTION + * and ignores ';' inside comments and pragmas. This means that we cannot do this in a signle lex rule. + * Body_state therefore stores ALL text we consume in every rule, so we can push it back into the buffer + * once we have decided if we are parsing ST or IL code. The following functions manage that buffer used by + * the body_state. + */ +void append_bodystate_buffer(const char *text, int is_whitespace = 0); +void unput_bodystate_buffer(void); +int isempty_bodystate_buffer(void); +void del_bodystate_buffer(void); + + int GetNextChar(char *b, int maxBuffer); %} @@ -542,7 +566,6 @@ typedef struct { int currentChar; int lineLength; int currentTokenStart; - char *buffer; FILE *in_file; } tracking_t; @@ -558,7 +581,8 @@ typedef struct { const char *filename; } include_stack_t; -tracking_t *current_tracking = NULL; +tracking_t * current_tracking = NULL; +tracking_t previous_tracking; include_stack_t include_stack[MAX_INCLUDE_DEPTH]; int include_stack_ptr = 0; @@ -664,9 +688,13 @@ comment "(*"({comment_text}*)({asterisk}+)")" * In our implementation we therefore have two definitions of whitespace * - one for ST, that includes the newline character * - one for IL without the newline character. - * Additionally, when parsing IL, the newline character is treated as the EOL token. - * This requires the use of a state machine in the lexical parser that needs at least - * some knowledge of the syntax itself. + * + * IL whitespace is only active while parsing IL code, whereas ST whitespace + * is used in all other circumstances. Additionally, when parsing IL, the newline + * character is treated as the EOL token. + * The above requires the use of a state machine in the lexical parser to track which + * language is being parsed. This requires that the lexical parser (i.e. flex) + * have some knowledge of the syntax itself. * * NOTE: Our definition of whitespace will only work in ASCII! * @@ -680,6 +708,9 @@ comment "(*"({comment_text}*)({asterisk}+)")" * We use this alternative just to stop the flex utility from * generating the invalid (in this case) warning... */ +/* NOTE: il_whitespace_char is not currenty used, be we include it for completeness */ +st_whitespace_char [ \f\n\r\t\v] +il_whitespace_char [ \f\r\t\v] st_whitespace [ \f\n\r\t\v]* il_whitespace [ \f\r\t\v]* @@ -958,20 +989,29 @@ incompl_location %[IQM]\* {file_include_pragma} unput_text(0); yy_push_state(include_beg); /* Pragmas sent to syntax analyser (bison) */ -{disable_code_generation_pragma} return disable_code_generation_pragma_token; -{enable_code_generation_pragma} return enable_code_generation_pragma_token; -{disable_code_generation_pragma} return disable_code_generation_pragma_token; -{enable_code_generation_pragma} return enable_code_generation_pragma_token; - + /* NOTE: In the vardecl_list_state we only process the pragmas between two consecutive VAR .. END_VAR blocks. + * We do not process any pragmas trailing after the last END_VAR. We leave that to the body_state. + * This is because the pragmas are stored in a statement_list or instruction_list (in bison), + * but these lists must start with the special tokens start_IL_body_token/start_ST_body_token. + * This means that these special tokens must be generated (by the body_state) before processing + * the pragme => we cannot process the trailing pragmas in the vardecl_list_state state. + */ +{disable_code_generation_pragma} return disable_code_generation_pragma_token; +{enable_code_generation_pragma} return enable_code_generation_pragma_token; +{disable_code_generation_pragma}/(VAR) return disable_code_generation_pragma_token; +{enable_code_generation_pragma}/(VAR) return enable_code_generation_pragma_token; +{disable_code_generation_pragma} append_bodystate_buffer(yytext); /* in body state we do not process any tokens, we simply store them for later processing! */ +{enable_code_generation_pragma} append_bodystate_buffer(yytext); /* in body state we do not process any tokens, we simply store them for later processing! */ /* Any other pragma we find, we just pass it up to the syntax parser... */ /* Note that the state is exclusive, so we have to include it here too. */ +{pragma} append_bodystate_buffer(yytext); /* in body state we do not process any tokens, we simply store them for later processing! */ {pragma} {/* return the pragmma without the enclosing '{' and '}' */ int cut = yytext[1]=='{'?2:1; yytext[strlen(yytext)-cut] = '\0'; yylval.ID=strdup(yytext+cut); return pragma_token; } -{pragma} {/* return the pragmma without the enclosing '{' and '}' */ +{pragma}/(VAR) {/* return the pragmma without the enclosing '{' and '}' */ int cut = yytext[1]=='{'?2:1; yytext[strlen(yytext)-cut] = '\0'; yylval.ID=strdup(yytext+cut); @@ -1059,28 +1099,10 @@ incompl_location %[IQM]\* /* INITIAL -> header_state */ { - /* NOTE: how about functions that do not declare variables, and go directly to the body_state??? - * - According to Section 2.5.1.3 (Function Declaration), item 2 in the list, a FUNCTION - * must have at least one input argument, so a correct declaration will have at least - * one VAR_INPUT ... VAR_END construct! - * - According to Section 2.5.2.2 (Function Block Declaration), a FUNCTION_BLOCK - * must have at least one input argument, so a correct declaration will have at least - * one VAR_INPUT ... VAR_END construct! - * - According to Section 2.5.3 (Programs), a PROGRAM must have at least one input - * argument, so a correct declaration will have at least one VAR_INPUT ... VAR_END - * construct! - * - * All the above means that we needn't worry about PROGRAMs, FUNCTIONs or - * FUNCTION_BLOCKs that do not have at least one VAR_END before the body_state. - * If the code has an error, and no VAR_END before the body, we will simply - * continue in the state, untill the end of the FUNCTION, FUNCTION_BLOCK - * or PROGAM. - */ - -FUNCTION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return FUNCTION; -FUNCTION_BLOCK{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return FUNCTION_BLOCK; -PROGRAM{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return PROGRAM; -CONFIGURATION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(config_state); return CONFIGURATION; +FUNCTION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else {BEGIN(header_state);/* printf("\nChanging to header_state\n"); */} return FUNCTION; +FUNCTION_BLOCK{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else {BEGIN(header_state);/* printf("\nChanging to header_state\n"); */} return FUNCTION_BLOCK; +PROGRAM{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else {BEGIN(header_state);/* printf("\nChanging to header_state\n"); */} return PROGRAM; +CONFIGURATION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else {BEGIN(config_state);/* printf("\nChanging to config_state\n"); */} return CONFIGURATION; } { @@ -1096,21 +1118,36 @@ END_CONFIGURATION unput_text(0); BEGIN(INITIAL); .|\n {}/* Ignore text inside POU! (including the '\n' character!)) */ } - /* INITIAL -> body_state */ - /* required if the function, program, etc.. has no VAR block! */ - /* We comment it out since the standard does not allow this. */ - /* NOTE: Even if we were to include the following code, it */ - /* would have no effect whatsoever since the above */ - /* rules will take precendence! */ - /* -{ -FUNCTION BEGIN(body_state); return FUNCTION; -FUNCTION_BLOCK BEGIN(body_state); return FUNCTION_BLOCK; -PROGRAM BEGIN(body_state); return PROGRAM; -} - */ /* header_state -> (vardecl_list_state) */ + /* NOTE: This transition assumes that all POUs with code (Function, FB, and Program) will always contain + * at least one VAR_XXX block. + * How about functions that do not declare variables, and go directly to the body_state??? + * - According to Section 2.5.1.3 (Function Declaration), item 2 in the list, a FUNCTION + * must have at least one input argument, so a correct declaration will have at least + * one VAR_INPUT ... VAR_END construct! + * - According to Section 2.5.2.2 (Function Block Declaration), a FUNCTION_BLOCK + * must have at least one input argument, so a correct declaration will have at least + * one VAR_INPUT ... VAR_END construct! + * - According to Section 2.5.3 (Programs), a PROGRAM must have at least one input + * argument, so a correct declaration will have at least one VAR_INPUT ... VAR_END + * construct! + * + * All the above means that we needn't worry about PROGRAMs, FUNCTIONs or + * FUNCTION_BLOCKs that do not have at least one VAR_END before the body_state. + * If the code has an error, and no VAR_END before the body, we will simply + * continue in the state, until the end of the FUNCTION, FUNCTION_BLOCK + * or PROGAM. + * + * WARNING: From 2016-05 (May 2016) onwards, matiec supports a non-standard option in which a Function + * may be declared with no Input, Output or IN_OUT variables. This means that the above + * assumption is no longer valid. + * + * NOTE: Some code being parsed may be erroneous and not contain any VAR END_VAR block. + * To generate error messages that make sense, the flex state machine should not get lost + * in these situations. We therefore consider the possibility of finding + * END_FUNCTION, END_FUNCTION_BLOCK or END_PROGRAM when inside the header_state. + */ { VAR | /* execute the next rule's action, i.e. fall-through! */ VAR_INPUT | @@ -1121,26 +1158,53 @@ VAR_GLOBAL | VAR_TEMP | VAR_CONFIG | VAR_ACCESS unput_text(0); BEGIN(vardecl_list_state); + +END_FUNCTION | /* execute the next rule's action, i.e. fall-through! */ +END_FUNCTION_BLOCK | +END_PROGRAM unput_text(0); BEGIN(vardecl_list_state); + /* Notice that we do NOT go directly to body_state, as that requires a push(). + * If we were to puch to body_state here, then the corresponding pop() at the + *end of body_state would return to header_state. + * After this pop() header_state would not return to INITIAL as it should, but + * would instead enter an infitie loop push()ing again to body_state + */ } /* vardecl_list_state -> (vardecl_state | body_state | INITIAL) */ { -VAR_INPUT | /* execute the next rule's action, i.e. fall-through! */ -VAR_OUTPUT | -VAR_IN_OUT | -VAR_EXTERNAL | -VAR_GLOBAL | -VAR_TEMP | -VAR_CONFIG | -VAR_ACCESS | -VAR unput_text(0); yy_push_state(vardecl_state); + /* NOTE: vardecl_list_state is an exclusive state, i.e. when in this state + * default rules do not apply! This means that when in this state identifiers + * are not recognised! + * NOTE: Notice that we only change to vardecl_state if the VAR*** is followed by + * at least one whitespace. This is to dintinguish the VAR declaration + * from identifiers starting with 'var' (e.g. a variable named 'varint') + * NOTE: Notice that we cannot use st_whitespace here, as it can legally be empty. + * We therefore use st_whitespace_char instead. + */ +VAR_INPUT{st_whitespace_char} | /* execute the next rule's action, i.e. fall-through! */ +VAR_OUTPUT{st_whitespace_char} | +VAR_IN_OUT{st_whitespace_char} | +VAR_EXTERNAL{st_whitespace_char} | +VAR_GLOBAL{st_whitespace_char} | +VAR_TEMP{st_whitespace_char} | +VAR_CONFIG{st_whitespace_char} | +VAR_ACCESS{st_whitespace_char} | +VAR{st_whitespace_char} unput_text(0); yy_push_state(vardecl_state); //printf("\nChanging to vardecl_state\n"); -END_FUNCTION unput_text(0); BEGIN(INITIAL); -END_FUNCTION_BLOCK unput_text(0); BEGIN(INITIAL); -END_PROGRAM unput_text(0); BEGIN(INITIAL); +END_FUNCTION{st_whitespace} unput_text(0); BEGIN(INITIAL); +END_FUNCTION_BLOCK{st_whitespace} unput_text(0); BEGIN(INITIAL); +END_PROGRAM{st_whitespace} unput_text(0); BEGIN(INITIAL); -. unput_text(0); yy_push_state(body_state); /* anything else, just change to body_state! */ + /* NOTE: Handling of whitespace... + * - Must come __before__ the next rule for any single character '.' + * - If the rules were reversed, any whitespace with a single space (' ') + * would be handled by the '.' rule instead of the {whitespace} rule! + */ +{st_whitespace} /* Eat any whitespace */ + + /* anything else, just change to body_state! */ +. unput_text(0); yy_push_state(body_state); //printf("\nChanging to body_state\n"); } @@ -1152,41 +1216,56 @@ END_VAR yy_pop_state(); return END_VAR; /* pop back to vardecl_list_state */ /* body_state -> (il_state | st_state | sfc_state) */ { -INITIAL_STEP unput_text(0); BEGIN(sfc_state); +{st_whitespace} {/* In body state we do not process any tokens, + * we simply store them for later processing! + * NOTE: we must return ALL text when in body_state, including + * all comments and whitespace, so as not + * to lose track of the line_number and column number + * used when printing debugging messages. + * NOTE: some of the following rules depend on the fact that + * the body state buffer is either empty or only contains white space up to + * that point. Since the vardecl_list_state will eat up all + * whitespace before entering the body_state, the contents of the bodystate_buffer + * will _never_ start with whitespace if the previous state was vardecl_list_state. + * However, it is possible to enter the body_state from other states (e.g. when + * parsing SFC code, that contains transitions or actions in other languages) + */ + append_bodystate_buffer(yytext, 1 /* is whitespace */); + } + /* 'INITIAL_STEP' always used in beginning of SFCs !! */ +INITIAL_STEP { if (isempty_bodystate_buffer()) {unput_text(0); del_bodystate_buffer(); BEGIN(sfc_state);} + else {append_bodystate_buffer(yytext);} + } + + /* ':=', at the very beginning of a 'body', occurs only in transitions and not Function, FB, or Program bodies! */ +:= { if (isempty_bodystate_buffer()) {unput_text(0); del_bodystate_buffer(); BEGIN(st_state);} /* We do _not_ return a start_ST_body_token here, as bison does not expect it! */ + else {append_bodystate_buffer(yytext);} + } + + /* check if ';' occurs before an END_FUNCTION, END_FUNCTION_BLOCK, END_PROGRAM, END_ACTION or END_TRANSITION. (If true => we are parsing ST; If false => parsing IL). */ +END_ACTION | /* execute the next rule's action, i.e. fall-through! */ +END_FUNCTION | +END_FUNCTION_BLOCK | +END_TRANSITION | +END_PROGRAM { append_bodystate_buffer(yytext); unput_bodystate_buffer(); BEGIN(il_state); /*printf("returning start_IL_body_token\n");*/ return start_IL_body_token;} +.|\n { append_bodystate_buffer(yytext); + if (strcmp(yytext, ";") == 0) + {unput_bodystate_buffer(); BEGIN(st_state); /*printf("returning start_ST_body_token\n");*/ return start_ST_body_token;} + } + /* The following rules are not really necessary. They just make compilation faster in case the ST Statement List starts with one fot he following... */ +RETURN | /* execute the next rule's action, i.e. fall-through! */ +IF | +CASE | +FOR | +WHILE | +EXIT | +REPEAT { if (isempty_bodystate_buffer()) {unput_text(0); del_bodystate_buffer(); BEGIN(st_state); return start_ST_body_token;} + else {append_bodystate_buffer(yytext);} + } -{qualified_identifier} unput_text(0); BEGIN(st_state); /* will always be followed by '[' for an array access, or ':=' as the left hand of an assignment statement */ -{direct_variable_standard} unput_text(0); BEGIN(st_state); /* will always be followed by ':=' as the left hand of an assignment statement */ - -RETURN unput_text(0); BEGIN(st_state); -IF unput_text(0); BEGIN(st_state); -CASE unput_text(0); BEGIN(st_state); -FOR unput_text(0); BEGIN(st_state); -WHILE unput_text(0); BEGIN(st_state); -EXIT unput_text(0); BEGIN(st_state); -REPEAT unput_text(0); BEGIN(st_state); - - /* ':=' occurs only in transitions, and not Function or FB bodies! */ -:= unput_text(0); BEGIN(st_state); - -{identifier} {int token = get_identifier_token(yytext); - if ((token == prev_declared_fb_name_token) || (token == prev_declared_variable_name_token)) { - /* the code has a call to a function block OR has an assingment with a variable as the lvalue */ - unput_text(0); BEGIN(st_state); - } else - if (token == prev_declared_derived_function_name_token) { - /* the code has a call to a function - must be IL */ - unput_text(0); BEGIN(il_state); - } else { - /* Might be a lable in IL, or a bug in ST/IL code. We jump to IL */ - unput_text(0); BEGIN(il_state); - } - } - -. unput_text(0); BEGIN(il_state); /* Don't know what it could be. This is most likely a bug. Let's just to a random state... */ } /* end of body_state lexical parser */ - /* (il_state | st_state) -> pop to $previous_state (vardecl_list_state or sfc_state) */ { END_FUNCTION yy_pop_state(); unput_text(0); @@ -1214,8 +1293,12 @@ END_CONFIGURATION BEGIN(INITIAL); return END_CONFIGURATION; /* NOTE: pragmas are handled right at the beginning... */ /* The whitespace */ -{st_whitespace} /* Eat any whitespace */ +{st_whitespace} /* Eat any whitespace */ {il_whitespace} /* Eat any whitespace */ + /* NOTE: Due to the need of having the following rule have higher priority, + * the following rule was moved to an earlier position in this file. +{st_whitespace} {...} + */ /* The comments */ {comment_beg} yy_push_state(comment_state); @@ -1254,6 +1337,14 @@ END_CONFIGURATION BEGIN(INITIAL); return END_CONFIGURATION; * We solve this by NOT testing for function names here, and * handling this function and keyword clash in bison! */ + /* NOTE: The following code has been commented out as most users do not want matiec + * to allow the use of 'R1', 'IN' ... IL operators as identifiers, + * even though a literal reading of the standard allows this. + * We could add this as a commadnd line option, but it is not yet done. + * For now we just comment out the code, but leave it the commented code + * in so we can re-activate quickly (without having to go through old commits + * in the mercurial repository to figure out the missing code! + */ /* {identifier} {int token = get_identifier_token(yytext); // fprintf(stderr, "flex: analysing identifier '%s'...", yytext); @@ -1367,6 +1458,10 @@ TOD return TOD; /* Keyword (Data Type) */ DATE_AND_TIME return DATE_AND_TIME; /* Keyword (Data Type) */ TIME_OF_DAY return TIME_OF_DAY; /* Keyword (Data Type) */ + /* A non-standard extension! */ +VOID {if (runtime_options.allow_void_datatype) {return VOID;} else {REJECT;}} + + /*****************************************************************/ /* Keywords defined in "Safety Software Technical Specification" */ /*****************************************************************/ @@ -1470,7 +1565,7 @@ AT return AT; /* Keyword */ /* B 1.5.1 - Functions */ /***********************/ /* Note: The following END_FUNCTION rule includes a BEGIN(INITIAL); command. - * This is necessary in case the input program being pased has syntax errors that force + * This is necessary in case the input program being parsed has syntax errors that force * flex's main state machine to never change to the il_state or the st_state * after changing to the body_state. * Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with @@ -1486,7 +1581,7 @@ CONSTANT return CONSTANT; /* Keyword */ /* B 1.5.2 - Function Blocks */ /*****************************/ /* Note: The following END_FUNCTION_BLOCK rule includes a BEGIN(INITIAL); command. - * This is necessary in case the input program being pased has syntax errors that force + * This is necessary in case the input program being parsed has syntax errors that force * flex's main state machine to never change to the il_state or the st_state * after changing to the body_state. * Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with @@ -1504,7 +1599,7 @@ END_VAR return END_VAR; /* Keyword */ /* B 1.5.3 - Programs */ /**********************/ /* Note: The following END_PROGRAM rule includes a BEGIN(INITIAL); command. - * This is necessary in case the input program being pased has syntax errors that force + * This is necessary in case the input program being parsed has syntax errors that force * flex's main state machine to never change to the il_state or the st_state * after changing to the body_state. * Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with @@ -1737,6 +1832,7 @@ END_REPEAT return END_REPEAT; /* Keyword */ EXIT return EXIT; /* Keyword */ +CONTINUE return CONTINUE; /* Keyword */ @@ -1852,62 +1948,43 @@ _ /* do nothing - eat it up!*/ tracking_t *GetNewTracking(FILE* in_file) { tracking_t* new_env = new tracking_t; - new_env->eof = 0; - new_env->lineNumber = 0; + new_env->eof = 0; + new_env->lineNumber = 1; new_env->currentChar = 0; - new_env->lineLength = 0; + new_env->lineLength = 0; new_env->currentTokenStart = 0; - new_env->buffer = (char*)malloc(MAX_LINE_LENGTH); new_env->in_file = in_file; return new_env; } void FreeTracking(tracking_t *tracking) { - free(tracking->buffer); delete tracking; } +void UpdateTracking(const char *text) { + const char *newline, *token = text; + while ((newline = strchr(token, '\n')) != NULL) { + token = newline + 1; + current_tracking->lineNumber++; + current_tracking->currentChar = 1; + } + current_tracking->currentChar += strlen(token); +} + + /* GetNextChar: reads a character from input */ int GetNextChar(char *b, int maxBuffer) { - char *p; - - if ( current_tracking->eof ) + int res = fgetc(current_tracking->in_file); + if ( res == EOF ) return 0; - - while ( current_tracking->currentChar >= current_tracking->lineLength ) { - current_tracking->currentChar = 0; - current_tracking->currentTokenStart = 1; - current_tracking->eof = false; - - p = fgets(current_tracking->buffer, MAX_LINE_LENGTH, current_tracking->in_file); - if ( p == NULL ) { - if ( ferror(current_tracking->in_file) ) - return 0; - current_tracking->eof = true; - return 0; - } - - current_tracking->lineLength = strlen(current_tracking->buffer); - - /* only increment line number if the buffer was big enough to read the whole line! */ - char last_char = current_tracking->buffer[current_tracking->lineLength - 1]; - if (('\n' == last_char) || ('\r' == last_char)) // '\r' ---> CR, '\n' ---> LF - current_tracking->lineNumber++; - } - - b[0] = current_tracking->buffer[current_tracking->currentChar]; - if (b[0] == ' ' || b[0] == '\t') - current_tracking->currentTokenStart++; - current_tracking->currentChar++; - - return b[0]==0?0:1; + *b = (char)res; + return 1; } - /***********************************/ /* Utility function definitions... */ /***********************************/ @@ -1994,42 +2071,133 @@ void include_file(const char *filename) { +/* return the specified character to the input stream */ +/* WARNING: this function destroys the contents of yytext */ +void unput_char(const char c) { + /* NOTE: The following uncomented code is not necessary as we currently use a different algorithm: + * - make a backup/snapshot of the current tracking data (in previous_tracking variable) + * (done in YY_USER_ACTION) + * - restore the previous tracking state when we unput any text... + * (in unput_text() and unput_and_mark() ) + */ +// /* We will later be processing this same character again when it is read from the input strem, +// * and therefore we will be incrementing the line number and character column acordingly. +// * We must therefore try to 'undo' the changes to the line number and character column +// * so this character is not counted twice! +// */ +// if (c == '\n') { +// current_tracking->lineNumber--; +// /* We should now set the current_tracking->currentChar to the length of the previous line +// * But we currently have no way of knowing it, so we simply set it to 0. +// * I (msousa) don't think this is currently an issue because I don't believe the code +// * ever calls unput_char() with a '\n', so we leave it for now +// */ +// current_tracking->currentChar = 0; +// } else if (current_tracking->currentChar > 0) { +// current_tracking->currentChar--; +// } + + unput(c); // unput() destroys the contents of yytext !! +} /* return all the text in the current token back to the input stream, except the first n chars. */ -void unput_text(unsigned int n) { - /* it seems that flex has a bug in that it will not correctly count the line numbers - * if we return newlines back to the input stream. These newlines will be re-counted - * a second time when they are processed again by flex. - * We therefore determine how many newlines are in the text we are returning, - * and decrement the line counter acordingly... - */ - /* - unsigned int i; +void unput_text(int n) { + if (n < 0) ERROR; + signed int i; // must be signed! The iterartion may end with -1 when this function is called with n=0 !! + + char *yycopy = strdup( yytext ); /* unput_char() destroys yytext, so we copy it first */ + for (int i = yyleng-1; i >= n; i--) + unput_char(yycopy[i]); + + *current_tracking = previous_tracking; + yycopy[n] = '\0'; + UpdateTracking(yycopy); - for (i = n; i < strlen(yytext); i++) - if (yytext[i] == '\n') - current_tracking->lineNumber--; - */ - /* now return all the text back to the input stream... */ - yyless(n); + free(yycopy); } + /* return all the text in the current token back to the input stream, * but first return to the stream an additional character to mark the end of the token. */ -void unput_and_mark(const char c) { - char *yycopy = strdup( yytext ); /* unput() destroys yytext, so we copy it first */ - unput(c); +void unput_and_mark(const char mark_char) { + char *yycopy = strdup( yytext ); /* unput_char() destroys yytext, so we copy it first */ + unput_char(mark_char); for (int i = yyleng-1; i >= 0; i--) - unput(yycopy[i]); + unput_char(yycopy[i]); free(yycopy); + *current_tracking = previous_tracking; } +/* The body_state tries to find a ';' before a END_PROGRAM, END_FUNCTION or END_FUNCTION_BLOCK or END_ACTION + * and ignores ';' inside comments and pragmas. This means that we cannot do this in a signle lex rule. + * Body_state therefore stores ALL text we consume in every rule, so we can push it back into the buffer + * once we have decided if we are parsing ST or IL code. The following functions manage that buffer used by + * the body_state. + */ +/* The buffer used by the body_state state */ +char *bodystate_buffer = NULL; +bool bodystate_is_whitespace = 1; // TRUE (1) if buffer is empty, or only contains whitespace. +tracking_t bodystate_init_tracking; + +/* append text to bodystate_buffer */ +void append_bodystate_buffer(const char *text, int is_whitespace) { + // printf("<<>> %d <%s><%s>\n", bodystate_buffer, text, (NULL != bodystate_buffer)?bodystate_buffer:"NULL"); + long int old_len = 0; + // make backup of tracking if we are starting off a new body_state_buffer + if (NULL == bodystate_buffer) bodystate_init_tracking = *current_tracking; + // set bodystate_is_whitespace flag if we are starting a new buffer + if (NULL == bodystate_buffer) bodystate_is_whitespace = 1; + // set bodystate_is_whitespace flag to FALSE if we are adding non white space to buffer + if (!is_whitespace) bodystate_is_whitespace = 0; + + if (NULL != bodystate_buffer) old_len = strlen(bodystate_buffer); + bodystate_buffer = (char *)realloc(bodystate_buffer, old_len + strlen(text) + 1); + if (NULL == bodystate_buffer) ERROR; + strcpy(bodystate_buffer + old_len, text); + //printf("=<%s> %d %d\n", (NULL != bodystate_buffer)?bodystate_buffer:NULL, old_len + strlen(text) + 1, bodystate_buffer); +} + +/* Return all data in bodystate_buffer back to flex, and empty bodystate_buffer. */ +void unput_bodystate_buffer(void) { + if (NULL == bodystate_buffer) ERROR; + // printf("<<>>\n%s\n", bodystate_buffer); + + for (long int i = strlen(bodystate_buffer)-1; i >= 0; i--) + unput_char(bodystate_buffer[i]); + + free(bodystate_buffer); + bodystate_buffer = NULL; + bodystate_is_whitespace = 1; + *current_tracking = bodystate_init_tracking; +} + + +/* Return true if bodystate_buffer is empty or ony contains whitespace!! */ +int isempty_bodystate_buffer(void) { + if (NULL == bodystate_buffer) return 1; + if (bodystate_is_whitespace) return 1; + return 0; +} + + +/* Delete all data in bodystate. */ +/* Will be used to delete ST whitespace when not needed. If not deleted this whitespace + * will be prepended to the next text block of code being appended to bodystate_buffer, + * which may cause trouble if it is IL code + */ +void del_bodystate_buffer(void) { + free(bodystate_buffer); + bodystate_buffer = NULL; + bodystate_is_whitespace = 1; +} + + /* Called by flex when it reaches the end-of-file */ int yywrap(void) { diff --git a/utils/matiec_src/stage1_2/stage1_2.cc b/utils/matiec_src/stage1_2/stage1_2.cc old mode 100755 new mode 100644 diff --git a/utils/matiec_src/stage1_2/stage1_2.hh b/utils/matiec_src/stage1_2/stage1_2.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/stage1_2/stage1_2_priv.hh b/utils/matiec_src/stage1_2/stage1_2_priv.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/stage3/array_range_check.cc b/utils/matiec_src/stage3/array_range_check.cc index 172a784..e0c50e1 100644 --- a/utils/matiec_src/stage3/array_range_check.cc +++ b/utils/matiec_src/stage3/array_range_check.cc @@ -133,38 +133,38 @@ void array_range_check_c::check_bounds(array_variable_c *symbol) { return; /* Check lower limit */ - if ( VALID_CVALUE( int64, l->elements[i]) && VALID_CVALUE( int64, dimension->lower_limit)) - if ( GET_CVALUE( int64, l->elements[i]) < GET_CVALUE( int64, dimension->lower_limit) ) - {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %"PRId64", should be >= %"PRId64").", GET_CVALUE( int64, l->elements[i]), GET_CVALUE( int64, dimension->lower_limit)); continue;} + if ( VALID_CVALUE( int64, l->get_element(i)) && VALID_CVALUE( int64, dimension->lower_limit)) + if ( GET_CVALUE( int64, l->get_element(i)) < GET_CVALUE( int64, dimension->lower_limit) ) + {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %" PRId64 ", should be >= %" PRId64 ").", GET_CVALUE( int64, l->get_element(i)), GET_CVALUE( int64, dimension->lower_limit)); continue;} - if ( VALID_CVALUE( int64, l->elements[i]) && VALID_CVALUE(uint64, dimension->lower_limit)) - if ( cmp_unsigned_signed( GET_CVALUE(uint64, dimension->lower_limit), GET_CVALUE( int64, l->elements[i])) > 0 ) - {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %"PRId64", should be >= %"PRIu64").", GET_CVALUE( int64, l->elements[i]), GET_CVALUE(uint64, dimension->lower_limit)); continue;} + if ( VALID_CVALUE( int64, l->get_element(i)) && VALID_CVALUE(uint64, dimension->lower_limit)) + if ( cmp_unsigned_signed( GET_CVALUE(uint64, dimension->lower_limit), GET_CVALUE( int64, l->get_element(i))) > 0 ) + {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %" PRId64 ", should be >= %" PRIu64 ").", GET_CVALUE( int64, l->get_element(i)), GET_CVALUE(uint64, dimension->lower_limit)); continue;} - if ( VALID_CVALUE(uint64, l->elements[i]) && VALID_CVALUE(uint64, dimension->lower_limit)) - if ( GET_CVALUE(uint64, l->elements[i]) < GET_CVALUE(uint64, dimension->lower_limit)) - {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %"PRIu64", should be >= %"PRIu64").", GET_CVALUE(uint64, l->elements[i]), GET_CVALUE(uint64, dimension->lower_limit)); continue;} + if ( VALID_CVALUE(uint64, l->get_element(i)) && VALID_CVALUE(uint64, dimension->lower_limit)) + if ( GET_CVALUE(uint64, l->get_element(i)) < GET_CVALUE(uint64, dimension->lower_limit)) + {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %" PRIu64 ", should be >= %" PRIu64 ").", GET_CVALUE(uint64, l->get_element(i)), GET_CVALUE(uint64, dimension->lower_limit)); continue;} - if ( VALID_CVALUE(uint64, l->elements[i]) && VALID_CVALUE( int64, dimension->lower_limit)) - if ( cmp_unsigned_signed(GET_CVALUE(uint64, l->elements[i]), GET_CVALUE( int64, dimension->lower_limit)) < 0 ) - {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %"PRIu64", should be >= %"PRId64").", GET_CVALUE(uint64, l->elements[i]), GET_CVALUE( int64, dimension->lower_limit)); continue;} + if ( VALID_CVALUE(uint64, l->get_element(i)) && VALID_CVALUE( int64, dimension->lower_limit)) + if ( cmp_unsigned_signed(GET_CVALUE(uint64, l->get_element(i)), GET_CVALUE( int64, dimension->lower_limit)) < 0 ) + {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %" PRIu64 ", should be >= %" PRId64 ").", GET_CVALUE(uint64, l->get_element(i)), GET_CVALUE( int64, dimension->lower_limit)); continue;} /* Repeat the same check, now for upper limit */ - if ( VALID_CVALUE( int64, l->elements[i]) && VALID_CVALUE( int64, dimension->upper_limit)) - if ( GET_CVALUE( int64, l->elements[i]) > GET_CVALUE( int64, dimension->upper_limit)) - {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %"PRId64", should be <= %"PRId64").", GET_CVALUE( int64, l->elements[i]), GET_CVALUE( int64, dimension->upper_limit)); continue;} + if ( VALID_CVALUE( int64, l->get_element(i)) && VALID_CVALUE( int64, dimension->upper_limit)) + if ( GET_CVALUE( int64, l->get_element(i)) > GET_CVALUE( int64, dimension->upper_limit)) + {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %" PRId64 ", should be <= %" PRId64 ").", GET_CVALUE( int64, l->get_element(i)), GET_CVALUE( int64, dimension->upper_limit)); continue;} - if ( VALID_CVALUE( int64, l->elements[i]) && VALID_CVALUE(uint64, dimension->upper_limit)) - if ( cmp_unsigned_signed( GET_CVALUE(uint64, dimension->upper_limit), GET_CVALUE( int64, l->elements[i])) < 0 ) - {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %"PRId64", should be <= %"PRIu64").", GET_CVALUE( int64, l->elements[i]), GET_CVALUE(uint64, dimension->upper_limit)); continue;} + if ( VALID_CVALUE( int64, l->get_element(i)) && VALID_CVALUE(uint64, dimension->upper_limit)) + if ( cmp_unsigned_signed( GET_CVALUE(uint64, dimension->upper_limit), GET_CVALUE( int64, l->get_element(i))) < 0 ) + {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %" PRId64 ", should be <= %" PRIu64 ").", GET_CVALUE( int64, l->get_element(i)), GET_CVALUE(uint64, dimension->upper_limit)); continue;} - if ( VALID_CVALUE(uint64, l->elements[i]) && VALID_CVALUE(uint64, dimension->upper_limit)) - if ( GET_CVALUE(uint64, l->elements[i]) > GET_CVALUE(uint64, dimension->upper_limit)) - {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %"PRIu64", should be <= %"PRIu64").", GET_CVALUE(uint64, l->elements[i]), GET_CVALUE(uint64, dimension->upper_limit)); continue;} + if ( VALID_CVALUE(uint64, l->get_element(i)) && VALID_CVALUE(uint64, dimension->upper_limit)) + if ( GET_CVALUE(uint64, l->get_element(i)) > GET_CVALUE(uint64, dimension->upper_limit)) + {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %" PRIu64 ", should be <= %" PRIu64 ").", GET_CVALUE(uint64, l->get_element(i)), GET_CVALUE(uint64, dimension->upper_limit)); continue;} - if ( VALID_CVALUE(uint64, l->elements[i]) && VALID_CVALUE( int64, dimension->upper_limit)) - if ( cmp_unsigned_signed(GET_CVALUE(uint64, l->elements[i]), GET_CVALUE( int64, dimension->upper_limit)) > 0 ) - {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %"PRIu64", should be <= %"PRId64").", GET_CVALUE(uint64, l->elements[i]), GET_CVALUE( int64, dimension->upper_limit)); continue;} + if ( VALID_CVALUE(uint64, l->get_element(i)) && VALID_CVALUE( int64, dimension->upper_limit)) + if ( cmp_unsigned_signed(GET_CVALUE(uint64, l->get_element(i)), GET_CVALUE( int64, dimension->upper_limit)) > 0 ) + {STAGE3_ERROR(0, symbol, symbol, "Array access out of bounds (using constant value of %" PRIu64 ", should be <= %" PRId64 ").", GET_CVALUE(uint64, l->get_element(i)), GET_CVALUE( int64, dimension->upper_limit)); continue;} } } @@ -199,7 +199,7 @@ void *array_range_check_c::visit(subrange_c *symbol) { // remember that the result (dimension) is unsigned, while the operands are signed!! // dimension = GET_CVALUE( int64, symbol->upper_limit) - VALID_CVALUE( int64, symbol->lower_limit); if (GET_CVALUE( int64, symbol->lower_limit) > GET_CVALUE( int64, symbol->upper_limit)) { - STAGE3_ERROR(0, symbol, symbol, "Subrange has lower limit (%"PRId64") larger than upper limit (%"PRId64").", GET_CVALUE( int64, symbol->lower_limit), GET_CVALUE( int64, symbol->upper_limit)); + STAGE3_ERROR(0, symbol, symbol, "Subrange has lower limit (%" PRId64 ") larger than upper limit (%" PRId64 ").", GET_CVALUE( int64, symbol->lower_limit), GET_CVALUE( int64, symbol->upper_limit)); dimension = std::numeric_limits< unsigned long long int >::max() - 1; // -1 because it will be incremented at the end of this function!! } else if (GET_CVALUE( int64, symbol->lower_limit) >= 0) { dimension = GET_CVALUE( int64, symbol->upper_limit) - GET_CVALUE( int64, symbol->lower_limit); @@ -209,7 +209,7 @@ void *array_range_check_c::visit(subrange_c *symbol) { } } else if (VALID_CVALUE(uint64, symbol->upper_limit) && VALID_CVALUE(uint64, symbol->lower_limit)) { if (GET_CVALUE(uint64, symbol->lower_limit) > GET_CVALUE(uint64, symbol->upper_limit)) { - STAGE3_ERROR(0, symbol, symbol, "Subrange has lower limit (%"PRIu64") larger than upper limit (%"PRIu64").", GET_CVALUE(uint64, symbol->lower_limit), GET_CVALUE(uint64, symbol->upper_limit)); + STAGE3_ERROR(0, symbol, symbol, "Subrange has lower limit (%" PRIu64 ") larger than upper limit (%" PRIu64 ").", GET_CVALUE(uint64, symbol->lower_limit), GET_CVALUE(uint64, symbol->upper_limit)); dimension = std::numeric_limits< unsigned long long int >::max() - 1; // -1 because it will be incremented at the end of this function!! } else dimension = GET_CVALUE(uint64, symbol->upper_limit) - GET_CVALUE(uint64, symbol->lower_limit); diff --git a/utils/matiec_src/stage3/case_elements_check.cc b/utils/matiec_src/stage3/case_elements_check.cc index 6ed3753..aa5fb49 100644 --- a/utils/matiec_src/stage3/case_elements_check.cc +++ b/utils/matiec_src/stage3/case_elements_check.cc @@ -242,7 +242,7 @@ void *case_elements_check_c::visit(case_statement_c *symbol) { // SYM_LIST(case_list_c) void *case_elements_check_c::visit(case_list_c *symbol) { for (int i = 0; i < symbol->n; i++) - case_elements_list.push_back(symbol->elements[i]); + case_elements_list.push_back(symbol->get_element(i)); return NULL; } diff --git a/utils/matiec_src/stage3/constant_folding.cc b/utils/matiec_src/stage3/constant_folding.cc index 37684a4..5b57288 100644 --- a/utils/matiec_src/stage3/constant_folding.cc +++ b/utils/matiec_src/stage3/constant_folding.cc @@ -1038,7 +1038,7 @@ void *constant_folding_c::visit(il_expression_c *symbol) { */ if ((NULL != symbol->il_operand) && ((NULL == symbol->simple_instr_list) || (0 == ((list_c *)symbol->simple_instr_list)->n))) ERROR; // stage2 is not behaving as we expect it to! if (NULL != symbol->il_operand) - symbol->il_operand->const_value = ((list_c *)symbol->simple_instr_list)->elements[0]->const_value; + symbol->il_operand->const_value = ((list_c *)symbol->simple_instr_list)->get_element(0)->const_value; return NULL; } @@ -1089,10 +1089,10 @@ void *constant_folding_c::visit(simple_instr_list_c *symbol) { return NULL; /* List is empty! Nothing to do. */ for(int i = 0; i < symbol->n; i++) - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); /* This object has (inherits) the same cvalues as the il_jump_operator */ - symbol->const_value = symbol->elements[symbol->n-1]->const_value; + symbol->const_value = symbol->get_element(symbol->n-1)->const_value; return NULL; } @@ -1367,8 +1367,8 @@ void *constant_propagation_c::visit(library_c *symbol) { for (i = 0; i < symbol->n; i++) { // first analyse the configurations - if (NULL != dynamic_cast(symbol->elements[i])) - symbol->elements[i]->accept(*this); + if (NULL != dynamic_cast(symbol->get_element(i))) + symbol->get_element(i)->accept(*this); } for (i = 0; i < symbol->n; i++) { @@ -1377,8 +1377,8 @@ void *constant_propagation_c::visit(library_c *symbol) { * loop. However, this is OK as the only difference would be how the VAR_EXTERN are handled, * and that is taken care of in the visit(external_declaration_c) visitor! */ - if (NULL == dynamic_cast(symbol->elements[i])) - symbol->elements[i]->accept(*this); + if (NULL == dynamic_cast(symbol->get_element(i))) + symbol->get_element(i)->accept(*this); } return NULL; @@ -1465,14 +1465,14 @@ void *constant_propagation_c::handle_var_list_decl(symbol_c *var_list, symbol_c list_c *list = dynamic_cast(var_list); if (NULL == list) ERROR; for (int i = 0; i < list->n; i++) { - token_c *var_name = dynamic_cast(list->elements[i]); + token_c *var_name = dynamic_cast(list->get_element(i)); if (NULL == var_name) { - if (NULL != dynamic_cast(list->elements[i])) + if (NULL != dynamic_cast(list->get_element(i))) continue; // this is an extensible standard function. Ignore this variable, and continue! - // debug_c::print(list->elements[i]); + // debug_c::print(list->get_element(i)); ERROR; } - list->elements[i]->const_value = init_value->const_value; + list->get_element(i)->const_value = init_value->const_value; if (fixed_init_value_) { (*values)[var_name->value] = init_value->const_value; if (is_global_var) diff --git a/utils/matiec_src/stage3/fill_candidate_datatypes.cc b/utils/matiec_src/stage3/fill_candidate_datatypes.cc old mode 100755 new mode 100644 index 5ba6fad..3f36515 --- a/utils/matiec_src/stage3/fill_candidate_datatypes.cc +++ b/utils/matiec_src/stage3/fill_candidate_datatypes.cc @@ -958,7 +958,15 @@ void *fill_candidate_datatypes_c::fill_spec_init(symbol_c *symbol, symbol_c *typ type_spec->accept(*this); // use bottom->up algorithm!! - if (NULL != init_value) init_value->accept(*this); + /* NOTE: In special cases we will run a modified bottom->up algorithm, i.e. with a top->down indication of + * tentative candidate_datatypes... + * (e.g. structure_element_initialization_list_c). The tentative candidate_datatypes (a list of + * candidate_datatypes to consider while running the bottom->up algorithm) will actually be the + * datatypes in symbol->parent->candidate_datatpes + * This implies that we can only run this bottom->up algorithm on the initial values _after_ + * having set the symbol->candidate_datatpes of the type specification (i.e. the symbol parameter) + */ + if (NULL != init_value) init_value->accept(*this); /* NOTE: Even if the constant and the type are of incompatible data types, we let the * ***_spec_init_c object inherit the data type of the type declaration (simple_specification) * This will let us produce more informative error messages when checking data type compatibility @@ -1036,7 +1044,7 @@ void *fill_candidate_datatypes_c::visit(enumerated_value_list_c *symbol) { /* We already know the datatype of the enumerated_value(s) in the list, so we set them directly instead of recursively calling the enumerated_value_c visit method! */ for(int i = 0; i < symbol->n; i++) - add_datatype_to_candidate_list(symbol->elements[i], current_enumerated_spec_type); // top->down algorithm!! + add_datatype_to_candidate_list(symbol->get_element(i), current_enumerated_spec_type); // top->down algorithm!! return NULL; } @@ -1163,9 +1171,56 @@ void *fill_candidate_datatypes_c::visit(initialized_structure_c *symbol) {return /* structure_initialization: '(' structure_element_initialization_list ')' */ /* structure_element_initialization_list ',' structure_element_initialization */ // SYM_LIST(structure_element_initialization_list_c) +void *fill_candidate_datatypes_c::visit(structure_element_initialization_list_c *symbol) { + // use bottom->up algorithm -> first let all elements determine their candidate_datatypes + iterator_visitor_c::visit(symbol); // call visit(structure_element_initialization_c *) on all elements + + for (unsigned int i = 0; i < symbol->parent->candidate_datatypes.size(); i++) { // size() should always be 1 here -> a single structure or FB type! + // assume symbol->parent->candidate_datatypes[i] is a FB type + search_varfb_instance_type_c search_varfb_instance_type(symbol->parent->candidate_datatypes[i]); + // assume symbol->parent->candidate_datatypes[i] is a STRUCT data type + structure_element_declaration_list_c *struct_decl = dynamic_cast(symbol->parent->candidate_datatypes[i]); + // flag indicating all struct_elem->structure_element_name are structure elements found in the symbol->parent->candidate_datatypes[i] datatype + int flag_all_elem_ok = 1; // assume all found + for (int k = 0; k < symbol->n; k++) { + structure_element_initialization_c *struct_elem = dynamic_cast(symbol->get_element(k)); + if (struct_elem == NULL) ERROR; + + // assume symbol->parent is a FB type... + symbol_c *type = NULL; + if (struct_decl != NULL) { + // search in the struct!! + type = search_base_type_c::get_basetype_decl(struct_decl->find_element(struct_elem->structure_element_name)); + } else { + // parent is a FB type. Lets search there!! + type = search_varfb_instance_type.get_basetype_decl(struct_elem->structure_element_name); + } + if (!get_datatype_info_c::is_ANY_ELEMENTARY(type) && get_datatype_info_c::is_type_valid(type)) { + // for non-elementary datatypes, we must use a top->down algorithm!! + add_datatype_to_candidate_list(struct_elem, type); + struct_elem->accept(*this); + } + if (search_in_candidate_datatype_list(type, struct_elem->candidate_datatypes) < 0) { + flag_all_elem_ok = 0; // the necessary datatype for structure init element is not a candidate_datatype of that element + } + } + if (flag_all_elem_ok) { + add_datatype_to_candidate_list(symbol, symbol->parent->candidate_datatypes[i]); + } + } + return NULL; +} + /* structure_element_name ASSIGN value */ // SYM_REF2(structure_element_initialization_c, structure_element_name, value) +void *fill_candidate_datatypes_c::visit(structure_element_initialization_c *symbol) { + symbol->value->accept(*this); + symbol->candidate_datatypes = symbol->value->candidate_datatypes; + // Note that candidate_datatypes of symbol->structure_element_name are left empty! + return NULL; +} + /* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */ // SYM_REF4(string_type_declaration_c, string_type_name, elementary_string_type_name, string_type_declaration_size, string_type_declaration_init/* may be == NULL! */) @@ -1235,7 +1290,7 @@ void *fill_candidate_datatypes_c::visit(direct_variable_c *symbol) { case 'd': case 'D': /* dword - 32 bits */ add_datatype_to_candidate_list(symbol, &get_datatype_info_c::dword_type_name); break; case 'l': case 'L': /* lword - 64 bits */ add_datatype_to_candidate_list(symbol, &get_datatype_info_c::lword_type_name); break; /* if none of the above, then the empty string was used <=> boolean */ - default: add_datatype_to_candidate_list(symbol, &get_datatype_info_c::bool_type_name); break; + default: add_datatype_to_candidate_list(symbol, &get_datatype_info_c::any_type_name); break; } return NULL; } @@ -1369,7 +1424,7 @@ void *fill_candidate_datatypes_c::visit(incompl_located_var_decl_c *symbol) {r // 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);} + for(int i = 0; i < symbol->n; i++) {symbol->get_element(i)->accept(*this);} return NULL; } @@ -1408,7 +1463,11 @@ void *fill_candidate_datatypes_c::visit(location_c *symbol) { symbol->direct_variable->accept(*this); for (unsigned int i = 0; i < symbol->direct_variable->candidate_datatypes.size(); i++) { - switch (get_sizeof_datatype_c::getsize(symbol->direct_variable->candidate_datatypes[i])) { + symbol_c *candidate_datatype = symbol->direct_variable->candidate_datatypes[i]; + if(get_datatype_info_c::is_ANY_generic_type(candidate_datatype)){ + add_datatype_to_candidate_list(symbol, &get_datatype_info_c::any_type_name); + } else { + switch (get_sizeof_datatype_c::getsize(candidate_datatype)) { case 1: /* bit - 1 bit */ add_datatype_to_candidate_list(symbol, &get_datatype_info_c::bool_type_name); add_datatype_to_candidate_list(symbol, &get_datatype_info_c::safebool_type_name); @@ -1451,7 +1510,8 @@ void *fill_candidate_datatypes_c::visit(location_c *symbol) { break; default: /* if none of the above, then no valid datatype allowed... */ break; - } /* switch() */ + } /* switch() */ + } /* if() */ } /* for */ return NULL; @@ -1648,7 +1708,7 @@ void *fill_candidate_datatypes_c::visit(instruction_list_c *symbol) { */ for(int j = 0; j < 2; j++) { for(int i = 0; i < symbol->n; i++) { - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); } } return NULL; @@ -1763,7 +1823,7 @@ void *fill_candidate_datatypes_c::visit(il_expression_c *symbol) { */ if ((NULL != symbol->il_operand) && ((NULL == symbol->simple_instr_list) || (0 == ((list_c *)symbol->simple_instr_list)->n))) ERROR; // stage2 is not behaving as we expect it to! if (NULL != symbol->il_operand) - symbol->il_operand->candidate_datatypes = ((list_c *)symbol->simple_instr_list)->elements[0]->candidate_datatypes; + symbol->il_operand->candidate_datatypes = ((list_c *)symbol->simple_instr_list)->get_element(0)->candidate_datatypes; /* Now check the if the data type semantics of operation are correct, */ il_operand = symbol->simple_instr_list; @@ -1831,7 +1891,8 @@ void *fill_candidate_datatypes_c::visit(il_fb_call_c *symbol) { /* NOTE: The parameter 'called_function_declaration' is used to pass data between the stage 3 and stage 4. */ // SYM_REF2(il_formal_funct_call_c, function_name, il_param_list, symbol_c *called_function_declaration; int extensible_param_count;) void *fill_candidate_datatypes_c::visit(il_formal_funct_call_c *symbol) { - symbol->il_param_list->accept(*this); + /* non-standard extension allowing functions with no input parameters => il_param_list may be NULL !!! */ + if (NULL != symbol->il_param_list) symbol->il_param_list->accept(*this); generic_function_call_t fcall_param = { /* fcall_param.function_name = */ symbol->function_name, @@ -1859,10 +1920,10 @@ void *fill_candidate_datatypes_c::visit(simple_instr_list_c *symbol) { return NULL; /* List is empty! Nothing to do. */ for(int i = 0; i < symbol->n; i++) - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); /* This object has (inherits) the same candidate datatypes as the last il_instruction */ - symbol->candidate_datatypes = symbol->elements[symbol->n-1]->candidate_datatypes; + symbol->candidate_datatypes = symbol->get_element(symbol->n-1)->candidate_datatypes; if (debug) std::cout << "simple_instr_list_c [" << symbol->candidate_datatypes.size() << "] result.\n"; return NULL; @@ -1955,7 +2016,7 @@ void *fill_candidate_datatypes_c::visit(NOT_operator_c *symbol) { * We do not need to generate an error message. This error will be caught somewhere else! */ if (NULL == prev_il_instruction) return NULL; - if (NULL == il_operand) return NULL; + if (NULL != il_operand) return NULL; for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) { if (get_datatype_info_c::is_ANY_BIT_compatible(prev_il_instruction->candidate_datatypes[i])) add_datatype_to_candidate_list(symbol, prev_il_instruction->candidate_datatypes[i]); diff --git a/utils/matiec_src/stage3/fill_candidate_datatypes.hh b/utils/matiec_src/stage3/fill_candidate_datatypes.hh old mode 100755 new mode 100644 index 2171867..5ba2adb --- a/utils/matiec_src/stage3/fill_candidate_datatypes.hh +++ b/utils/matiec_src/stage3/fill_candidate_datatypes.hh @@ -211,8 +211,8 @@ class fill_candidate_datatypes_c: public iterator_visitor_c { void *visit(initialized_structure_c *symbol); // void *visit(structure_element_declaration_list_c *symbol); // void *visit(structure_element_declaration_c *symbol); -// void *visit(structure_element_initialization_list_c *symbol); -// void *visit(structure_element_initialization_c *symbol); + void *visit(structure_element_initialization_list_c *symbol); + void *visit(structure_element_initialization_c *symbol); // void *visit(string_type_declaration_c *symbol); void *visit(fb_spec_init_c *symbol); diff --git a/utils/matiec_src/stage3/flow_control_analysis.cc b/utils/matiec_src/stage3/flow_control_analysis.cc index 531b9ed..d2542fc 100644 --- a/utils/matiec_src/stage3/flow_control_analysis.cc +++ b/utils/matiec_src/stage3/flow_control_analysis.cc @@ -218,8 +218,8 @@ void *flow_control_analysis_c::visit(instruction_list_c *symbol) { prev_il_instruction_is_JMP_or_RET = false; for(int i = 0; i < symbol->n; i++) { prev_il_instruction = NULL; - if (i > 0) prev_il_instruction = symbol->elements[i-1]; - curr_il_instruction = symbol->elements[i]; + if (i > 0) prev_il_instruction = symbol->get_element(i-1); + curr_il_instruction = symbol->get_element(i); curr_il_instruction->accept(*this); curr_il_instruction = NULL; } @@ -310,8 +310,8 @@ void *flow_control_analysis_c::visit(il_jump_operation_c *symbol) { void *flow_control_analysis_c::visit(simple_instr_list_c *symbol) { for(int i = 0; i < symbol->n; i++) { /* The prev_il_instruction for element[0] was set in visit(il_expression_c *) */ - if (i>0) prev_il_instruction = symbol->elements[i-1]; - symbol->elements[i]->accept(*this); + if (i>0) prev_il_instruction = symbol->get_element(i-1); + symbol->get_element(i)->accept(*this); } return NULL; } diff --git a/utils/matiec_src/stage3/forced_narrow_candidate_datatypes.cc b/utils/matiec_src/stage3/forced_narrow_candidate_datatypes.cc index 371b625..4b1dac7 100644 --- a/utils/matiec_src/stage3/forced_narrow_candidate_datatypes.cc +++ b/utils/matiec_src/stage3/forced_narrow_candidate_datatypes.cc @@ -120,6 +120,30 @@ forced_narrow_candidate_datatypes_c::~forced_narrow_candidate_datatypes_c(void) +void forced_narrow_candidate_datatypes_c::set_datatype_in_prev_il_instructions(symbol_c *datatype, il_instruction_c *symbol) { + if (NULL == symbol) ERROR; + /* In the forced_narrow_candidate_datatypes algorithm, we do NOT set any datatypes to invalid_type_name_c + * Any IL instructions that really are of an invalid_type_name_c (because the IL code is buggy?) have already + * been set by the standard narrow_candidate_datatypes algorithm. + * + * Remember too that valid IL code may also have some IL instructions correctly set to invalid_type_name_c, especially + * in cases where the data in the accumulator will not be used in the current IL instruction + * For example: + * LD bool_var + * JMPC label1 + * LD 34 + * ST int_var + * lable1: <---- This IL instruction_c (with NULL symbol->il_instruction) has invalid_type_name_c datatype!! + * LD T#3s And yet, the code is legal!!! + * ST time_var + */ + if (!get_datatype_info_c::is_type_valid(datatype)) return; + // Call the 'original' version of the set_datatype_in_prev_il_instructions() function, from narrow_candidate_datatypes_c + return narrow_candidate_datatypes_c::set_datatype_in_prev_il_instructions(datatype, symbol); +} + + + void forced_narrow_candidate_datatypes_c::forced_narrow_il_instruction(symbol_c *symbol, std::vector &next_il_instruction) { if (NULL == symbol->datatype) { if (symbol->candidate_datatypes.empty()) { @@ -161,7 +185,7 @@ void forced_narrow_candidate_datatypes_c::forced_narrow_il_instruction(symbol_c void *forced_narrow_candidate_datatypes_c::visit(instruction_list_c *symbol) { for(int j = 0; j < 2; j++) { for(int i = symbol->n-1; i >= 0; i--) { - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); } } @@ -171,7 +195,7 @@ void *forced_narrow_candidate_datatypes_c::visit(instruction_list_c *symbol) { */ /* for(int i = symbol->n-1; i >= 0; i--) { - if (NULL == symbol->elements[i]->datatype) + if (NULL == symbol->get_element(i)->datatype) ERROR; } */ diff --git a/utils/matiec_src/stage3/forced_narrow_candidate_datatypes.hh b/utils/matiec_src/stage3/forced_narrow_candidate_datatypes.hh index 37d571c..48c00c8 100644 --- a/utils/matiec_src/stage3/forced_narrow_candidate_datatypes.hh +++ b/utils/matiec_src/stage3/forced_narrow_candidate_datatypes.hh @@ -48,10 +48,13 @@ class forced_narrow_candidate_datatypes_c: public narrow_candidate_datatypes_c { private: void forced_narrow_il_instruction(symbol_c *symbol, std::vector &next_il_instruction); + protected: + virtual void set_datatype_in_prev_il_instructions(symbol_c *datatype, il_instruction_c *symbol); + public: forced_narrow_candidate_datatypes_c(symbol_c *ignore); virtual ~forced_narrow_candidate_datatypes_c(void); - + /****************************************/ /* B.2 - Language IL (Instruction List) */ /****************************************/ diff --git a/utils/matiec_src/stage3/narrow_candidate_datatypes.cc b/utils/matiec_src/stage3/narrow_candidate_datatypes.cc old mode 100755 new mode 100644 index 690dc59..5806845 --- a/utils/matiec_src/stage3/narrow_candidate_datatypes.cc +++ b/utils/matiec_src/stage3/narrow_candidate_datatypes.cc @@ -107,8 +107,8 @@ static void set_datatype(symbol_c *datatype, symbol_c *symbol) { /* Only set the symbol's desired datatype to 'datatype' if that datatype is in the candidate_datatype list */ -// static void set_datatype_in_prev_il_instructions(symbol_c *datatype, std::vector prev_il_instructions) { -static void set_datatype_in_prev_il_instructions(symbol_c *datatype, il_instruction_c *symbol) { +// NOTE: This function is virtual! The forced_narrow_candidate_datatypes_c has a slightly different version of this fuinction!! +void narrow_candidate_datatypes_c::set_datatype_in_prev_il_instructions(symbol_c *datatype, il_instruction_c *symbol) { if (NULL == symbol) ERROR; for (unsigned int i = 0; i < symbol->prev_il_instruction.size(); i++) set_datatype(datatype, symbol->prev_il_instruction[i]); @@ -609,8 +609,8 @@ void *narrow_candidate_datatypes_c::visit(enumerated_spec_init_c *symbol) {retur // SYM_LIST(enumerated_value_list_c) void *narrow_candidate_datatypes_c::visit(enumerated_value_list_c *symbol) { //if (NULL == symbol->datatype) ERROR; // Comented out-> Reserve this check for the print_datatypes_error_c ??? - for(int i = 0; i < symbol->n; i++) set_datatype(symbol->datatype, symbol->elements[i]); -//for(int i = 0; i < symbol->n; i++) if (NULL == symbol->elements[i]->datatype) ERROR; // Comented out-> Reserve this check for the print_datatypes_error_c ??? + for(int i = 0; i < symbol->n; i++) set_datatype(symbol->datatype, symbol->get_element(i)); +//for(int i = 0; i < symbol->n; i++) if (NULL == symbol->get_element(i)->datatype) ERROR; // Comented out-> Reserve this check for the print_datatypes_error_c ??? return NULL; } @@ -672,11 +672,45 @@ void *narrow_candidate_datatypes_c::visit(initialized_structure_c *symbol) {retu /* structure_initialization: '(' structure_element_initialization_list ')' */ /* structure_element_initialization_list ',' structure_element_initialization */ // SYM_LIST(structure_element_initialization_list_c) -// Not needed ??? +void *narrow_candidate_datatypes_c::visit(structure_element_initialization_list_c *symbol) { + symbol_c *type = NULL; + + // first try to narrow with the correct type, if valid. + if (!get_datatype_info_c::is_type_valid(type)) type = symbol->datatype; + // to reduce number of error messages, we try to narrow with parent's spec_init->datatype + if (!get_datatype_info_c::is_type_valid(type)) type = symbol->parent->datatype; + + if (get_datatype_info_c::is_type_valid(type)) { + // We need to iterate and determine the required datatype of each structure element + // assume type is a FB type + search_varfb_instance_type_c search_varfb_instance_type(type); + // assume type is a STRUCT type + structure_element_declaration_list_c *struct_decl = dynamic_cast(type); + for (int k = 0; k < symbol->n; k++) { + structure_element_initialization_c *struct_elem = (structure_element_initialization_c *)symbol->get_element(k); + symbol_c *type = NULL; + if (struct_decl == NULL) { + // type is not a struct. Must be a FB. + type = search_varfb_instance_type.get_basetype_decl(struct_elem->structure_element_name); + } else { + // type is a struct. + type = search_base_type_c::get_basetype_decl(struct_decl->find_element(struct_elem->structure_element_name)); + } + set_datatype(type, struct_elem); + struct_elem->accept(*this); + /* We do best effort narrowing, even in the presence of errors, to reduce number of error messages + * so the following two assertions are not always met. + */ + // if (!get_datatype_info_c::is_type_valid(type)) ERROR; + // if (struct_elem->datatype == NULL) ERROR; // should never occur. Already checked in fill_candidate_datatypes_c + } + } + return NULL; +} /* structure_element_name ASSIGN value */ // SYM_REF2(structure_element_initialization_c, structure_element_name, value) -// Not needed ??? +void *narrow_candidate_datatypes_c::visit(structure_element_initialization_c *symbol) {set_datatype(symbol->datatype, symbol->value); symbol->value->accept(*this); return NULL;} /* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */ // SYM_REF4(string_type_declaration_c, string_type_name, elementary_string_type_name, string_type_declaration_size, string_type_declaration_init/* may be == NULL! */) @@ -754,11 +788,11 @@ void *narrow_candidate_datatypes_c::visit(array_variable_c *symbol) { // SYM_LIST(subscript_list_c) void *narrow_candidate_datatypes_c::visit(subscript_list_c *symbol) { for (int i = 0; i < symbol->n; i++) { - for (unsigned int k = 0; k < symbol->elements[i]->candidate_datatypes.size(); k++) { - if (get_datatype_info_c::is_ANY_INT(symbol->elements[i]->candidate_datatypes[k])) - symbol->elements[i]->datatype = symbol->elements[i]->candidate_datatypes[k]; + for (unsigned int k = 0; k < symbol->get_element(i)->candidate_datatypes.size(); k++) { + if (get_datatype_info_c::is_ANY_INT(symbol->get_element(i)->candidate_datatypes[k])) + symbol->get_element(i)->datatype = symbol->get_element(i)->candidate_datatypes[k]; } - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); } return NULL; } @@ -828,8 +862,8 @@ void *narrow_candidate_datatypes_c::visit(incompl_located_var_decl_c *symbol) 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++) { - if (symbol->elements[i]->candidate_datatypes.size() == 1) - symbol->elements[i]->datatype = symbol->elements[i]->candidate_datatypes[0]; + if (symbol->get_element(i)->candidate_datatypes.size() == 1) + symbol->get_element(i)->datatype = symbol->get_element(i)->candidate_datatypes[0]; } #endif return NULL; @@ -930,6 +964,20 @@ void *narrow_candidate_datatypes_c::visit(transition_condition_c *symbol) { return NULL; } + +void *narrow_candidate_datatypes_c::visit(action_qualifier_c *symbol) { + if (symbol->action_time) { + for(unsigned int i = 0; i < symbol->action_time->candidate_datatypes.size(); i++) { + if (get_datatype_info_c::is_TIME_compatible(symbol->action_time->candidate_datatypes[i])) + symbol->action_time->datatype = symbol->action_time->candidate_datatypes[i]; + } + symbol->action_time->accept(*this); + } + symbol->action_qualifier->accept(*this); // Not really necessary for now... + return NULL; +} + + /********************************/ /* B 1.7 Configuration elements */ /********************************/ @@ -994,7 +1042,7 @@ void *narrow_candidate_datatypes_c::visit(instruction_list_c *symbol) { */ for(int j = 0; j < 2; j++) { for(int i = symbol->n-1; i >= 0; i--) { - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); } } return NULL; @@ -1109,7 +1157,7 @@ void *narrow_candidate_datatypes_c::visit(il_expression_c *symbol) { */ if ((NULL != symbol->il_operand) && ((NULL == symbol->simple_instr_list) || (0 == ((list_c *)symbol->simple_instr_list)->n))) ERROR; // stage2 is not behaving as we expect it to! if (NULL != symbol->il_operand) - symbol->il_operand->datatype = ((list_c *)symbol->simple_instr_list)->elements[0]->datatype; + symbol->il_operand->datatype = ((list_c *)symbol->simple_instr_list)->get_element(0)->datatype; return NULL; } @@ -1181,10 +1229,10 @@ void *narrow_candidate_datatypes_c::visit(il_formal_funct_call_c *symbol) { /* This object is referenced by il_expression_c objects */ void *narrow_candidate_datatypes_c::visit(simple_instr_list_c *symbol) { if (symbol->n > 0) - symbol->elements[symbol->n - 1]->datatype = symbol->datatype; + symbol->get_element(symbol->n - 1)->datatype = symbol->datatype; for(int i = symbol->n-1; i >= 0; i--) { - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); } return NULL; } @@ -1233,6 +1281,7 @@ void *narrow_candidate_datatypes_c::visit(il_simple_instruction_c *symbol) { * So, if yoy wish to set the prev_il_instruction->datatype = symbol->datatype; * do it __before__ calling set_il_operand_datatype() (which in turn calls il_operand->accept(*this)) !! */ +int count = 0; void *narrow_candidate_datatypes_c::set_il_operand_datatype(symbol_c *il_operand, symbol_c *datatype) { if (NULL == il_operand) return NULL; /* if no IL operand => error in the source code!! */ @@ -1716,8 +1765,8 @@ void *narrow_candidate_datatypes_c::visit(case_statement_c *symbol) { // SYM_LIST(case_element_list_c) void *narrow_candidate_datatypes_c::visit(case_element_list_c *symbol) { for (int i = 0; i < symbol->n; i++) { - symbol->elements[i]->datatype = symbol->datatype; - symbol->elements[i]->accept(*this); + symbol->get_element(i)->datatype = symbol->datatype; + symbol->get_element(i)->accept(*this); } return NULL; } @@ -1734,12 +1783,12 @@ void *narrow_candidate_datatypes_c::visit(case_element_c *symbol) { // SYM_LIST(case_list_c) void *narrow_candidate_datatypes_c::visit(case_list_c *symbol) { for (int i = 0; i < symbol->n; i++) { - for (unsigned int k = 0; k < symbol->elements[i]->candidate_datatypes.size(); k++) { - if (get_datatype_info_c::is_type_equal(symbol->datatype, symbol->elements[i]->candidate_datatypes[k])) - symbol->elements[i]->datatype = symbol->elements[i]->candidate_datatypes[k]; + for (unsigned int k = 0; k < symbol->get_element(i)->candidate_datatypes.size(); k++) { + if (get_datatype_info_c::is_type_equal(symbol->datatype, symbol->get_element(i)->candidate_datatypes[k])) + symbol->get_element(i)->datatype = symbol->get_element(i)->candidate_datatypes[k]; } /* NOTE: this may be an integer, a subrange_c, or a enumerated value! */ - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); } return NULL; } diff --git a/utils/matiec_src/stage3/narrow_candidate_datatypes.hh b/utils/matiec_src/stage3/narrow_candidate_datatypes.hh old mode 100755 new mode 100644 index 2904d66..4108c72 --- a/utils/matiec_src/stage3/narrow_candidate_datatypes.hh +++ b/utils/matiec_src/stage3/narrow_candidate_datatypes.hh @@ -69,6 +69,10 @@ class narrow_candidate_datatypes_c: public iterator_visitor_c { il_instruction_c *fake_prev_il_instruction; il_instruction_c *current_il_instruction; + protected: + virtual void set_datatype_in_prev_il_instructions(symbol_c *datatype, il_instruction_c *symbol); + + private: bool is_widening_compatible(const struct widen_entry widen_table[], symbol_c *left_type, symbol_c *right_type, symbol_c *result_type, bool *deprecated_status = NULL); void *narrow_spec_init (symbol_c *symbol, symbol_c *type_decl, symbol_c *init_value); @@ -185,8 +189,8 @@ class narrow_candidate_datatypes_c: public iterator_visitor_c { void *visit(initialized_structure_c *symbol); // void *visit(structure_element_declaration_list_c *symbol); // void *visit(structure_element_declaration_c *symbol); -// void *visit(structure_element_initialization_list_c *symbol); -// void *visit(structure_element_initialization_c *symbol); + void *visit(structure_element_initialization_list_c *symbol); + void *visit(structure_element_initialization_c *symbol); // void *visit(string_type_declaration_c *symbol); void *visit(fb_spec_init_c *symbol); @@ -249,6 +253,7 @@ class narrow_candidate_datatypes_c: public iterator_visitor_c { /* B 1.6 Sequential function chart elements */ /********************************************/ void *visit(transition_condition_c *symbol); + void *visit(action_qualifier_c *symbol); /********************************/ /* B 1.7 Configuration elements */ diff --git a/utils/matiec_src/stage3/print_datatypes_error.cc b/utils/matiec_src/stage3/print_datatypes_error.cc old mode 100755 new mode 100644 index 22d684f..79f7357 --- a/utils/matiec_src/stage3/print_datatypes_error.cc +++ b/utils/matiec_src/stage3/print_datatypes_error.cc @@ -545,6 +545,16 @@ void *print_datatypes_error_c::visit(enumerated_value_c *symbol) { } + +void *print_datatypes_error_c::visit(structure_element_initialization_c *symbol) { + symbol->value->accept(*this); + if (!get_datatype_info_c::is_type_valid(symbol->datatype)) + STAGE3_ERROR(0, symbol, symbol, "Initialization element identifier (%s) is not declared in referenced structure/FB scope, or is set to value of incompatible datatype.", + symbol->structure_element_name->token->value); + return NULL; +} + + /*********************/ /* B 1.4 - Variables */ /*********************/ @@ -587,9 +597,9 @@ void *print_datatypes_error_c::visit(array_variable_c *symbol) { void *print_datatypes_error_c::visit(subscript_list_c *symbol) { for (int i = 0; i < symbol->n; i++) { int start_error_count = error_count; - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); /* The following error message will only get printed if the current_display_error_level is set higher than 0! */ - if ((start_error_count == error_count) && (!get_datatype_info_c::is_type_valid(symbol->elements[i]->datatype))) + if ((start_error_count == error_count) && (!get_datatype_info_c::is_type_valid(symbol->get_element(i)->datatype))) STAGE3_ERROR(0, symbol, symbol, "Invalid data type for array subscript field."); } return NULL; diff --git a/utils/matiec_src/stage3/print_datatypes_error.hh b/utils/matiec_src/stage3/print_datatypes_error.hh old mode 100755 new mode 100644 index 881a120..d5aad98 --- a/utils/matiec_src/stage3/print_datatypes_error.hh +++ b/utils/matiec_src/stage3/print_datatypes_error.hh @@ -161,6 +161,8 @@ class print_datatypes_error_c: public iterator_visitor_c { void *visit(simple_spec_init_c *symbol); // void *visit(data_type_declaration_c *symbol); /* use base iterator_c method! */ void *visit(enumerated_value_c *symbol); +// void *visit(structure_element_initialization_list_c *symbol); + void *visit(structure_element_initialization_c *symbol); /*********************/ /* B 1.4 - Variables */ diff --git a/utils/matiec_src/stage3/remove_forward_dependencies.cc b/utils/matiec_src/stage3/remove_forward_dependencies.cc index b31ca7d..4538d40 100644 --- a/utils/matiec_src/stage3/remove_forward_dependencies.cc +++ b/utils/matiec_src/stage3/remove_forward_dependencies.cc @@ -209,10 +209,10 @@ void remove_forward_dependencies_c::print_circ_error(library_c *symbol) { /* Note too that circular references in derived datatypes is also not possible due to sytax! */ int initial_error_count = error_count; for (int i = 0; i < symbol->n; i++) - if ( (inserted_symbols.find(symbol->elements[i]) == inserted_symbols.end()) // if not copied to new AST - &&( (NULL != dynamic_cast (symbol->elements[i])) // and (is a FB - ||(NULL != dynamic_cast < function_declaration_c *>(symbol->elements[i])))) // or a Function) - STAGE3_ERROR(0, symbol->elements[i], symbol->elements[i], "POU (%s) contains a self-reference and/or belongs in a circular referencing loop", get_datatype_info_c::get_id_str(symbol->elements[i])); + if ( (inserted_symbols.find(symbol->get_element(i)) == inserted_symbols.end()) // if not copied to new AST + &&( (NULL != dynamic_cast (symbol->get_element(i))) // and (is a FB + ||(NULL != dynamic_cast < function_declaration_c *>(symbol->get_element(i))))) // or a Function) + STAGE3_ERROR(0, symbol->get_element(i), symbol->get_element(i), "POU (%s) contains a self-reference and/or belongs in a circular referencing loop", get_datatype_info_c::get_id_str(symbol->get_element(i))); if (error_count == initial_error_count) ERROR; // We were unable to determine which POUs contain the circular references!! } @@ -228,8 +228,8 @@ void *remove_forward_dependencies_c::visit(library_c *symbol) { /* first insert all the derived datatype declarations, in the same order by which they are delcared in the original AST */ /* Since IEC 61131-3 does not allow FBs in arrays or structures, it is actually safe to place all the datatypes before all the POUs! */ for (int i = 0; i < symbol->n; i++) - if (NULL != dynamic_cast (symbol->elements[i])) - new_tree->add_element(symbol->elements[i]); + if (NULL != dynamic_cast (symbol->get_element(i))) + new_tree->add_element(symbol->get_element(i)); /* now do the POUs, in whatever order is necessary to guarantee no forward references. */ long long int old_tree_pou_count = pou_count_c::get_count(symbol); @@ -241,7 +241,7 @@ void *remove_forward_dependencies_c::visit(library_c *symbol) { cycle_count++; prev_n = new_tree->n; current_code_generation_pragma = default_code_generation_pragma; - for (int i = 0; i < symbol->n; i++) symbol->elements[i]->accept(*this); + for (int i = 0; i < symbol->n; i++) symbol->get_element(i)->accept(*this); } while (prev_n != new_tree->n); // repeat while new elementns are still being added to the new AST if (old_tree_pou_count != pou_count_c::get_count(new_tree)) diff --git a/utils/matiec_src/stage3/stage3.cc b/utils/matiec_src/stage3/stage3.cc old mode 100755 new mode 100644 diff --git a/utils/matiec_src/stage3/stage3.hh b/utils/matiec_src/stage3/stage3.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/stage4/generate_c/generate_c.cc b/utils/matiec_src/stage4/generate_c/generate_c.cc index f2b3533..9965d43 100644 --- a/utils/matiec_src/stage4/generate_c/generate_c.cc +++ b/utils/matiec_src/stage4/generate_c/generate_c.cc @@ -178,13 +178,22 @@ static int generate_line_directives__ = 0; static int generate_pou_filepairs__ = 0; +static int generate_plc_state_backup_fuctions__ = 0; #ifdef __unix__ /* Parse command line options passed from main.c !! */ -#include // for getsybopt() +#include // for getsubopt() int stage4_parse_options(char *options) { - enum { LINE_OPT = 0 , SEPTFILE_OPT /*, SOME_OTHER_OPT, YET_ANOTHER_OPT */}; - char *const token[] = { /*[LINE_OPT]=*/(char *)"l",/*SEPTFILE_OPT*/(char *)"p" /*, SOME_OTHER_OPT, ... */, NULL }; + enum {LINE_OPT = 0, + SEPTFILE_OPT, + BACKUP_OPT /* option to generate function to backup and restore internal PLC state */ + /*, SOME_OTHER_OPT, YET_ANOTHER_OPT */}; + char *const token[] = { + /* LINE_OPT*/(char *)"l", + /* SEPTFILE_OPT*/(char *)"p", + /* BACKUP_OPT*/(char *)"b", + /* SOME_OTHER_OPT, ... */ + NULL }; /* unfortunately, the above commented out syntax for array initialization is valid in C, but not in C++ */ char *subopts = options; @@ -193,8 +202,9 @@ int stage4_parse_options(char *options) { while (*subopts != '\0') { switch (getsubopt(&subopts, token, &value)) { - case LINE_OPT: generate_line_directives__ = 1; break; - case SEPTFILE_OPT: generate_pou_filepairs__ = 1; break; + case LINE_OPT: generate_line_directives__ = 1; break; + case SEPTFILE_OPT: generate_pou_filepairs__ = 1; break; + case BACKUP_OPT: generate_plc_state_backup_fuctions__ = 1; break; default : fprintf(stderr, "Unrecognized option: -O %s\n", value); return -1; break; } } @@ -206,12 +216,13 @@ void stage4_print_options(void) { printf(" (options must be separated by commas. Example: 'l,w,x')\n"); printf(" l : insert '#line' directives in generated C code.\n"); printf(" p : place each POU in a separate pair of files (.c, .h).\n"); + printf(" b : generate functions to backup and restore internal PLC state.\n"); } #else /* not __unix__ */ /* getsubopt isn't supported with mingw, * then stage4 options aren't available on windows*/ void stage4_print_options(void) {} -int stage4_parse_options(char *options) {} +int stage4_parse_options(char *options) {return 0;} #endif /***********************************************************************/ @@ -296,9 +307,12 @@ class print_function_parameter_data_types_c: public generate_c_base_and_typeid_c //void *visit(input_declaration_list_c *symbol) {// iterate through list} void *visit(edge_declaration_c *symbol) { + {STAGE4_ERROR(symbol, symbol, "R_EDGE and F_EDGE declarations are not currently supported"); ERROR;} + /* current_type = &tmp_bool; symbol->var1_list->accept(*this); current_type = NULL; + */ return NULL; } @@ -530,9 +544,28 @@ analyse_variable_c *analyse_variable_c::singleton_ = NULL; /***********************************************************************/ /***********************************************************************/ -#define MILLISECOND 1000000 +#define MILLISECOND ((unsigned long long)1000000) #define SECOND 1000 * MILLISECOND +#define ULL_MAX std::numeric_limits::max() +#define UL_MAX std::numeric_limits::max() + +/* unsigned long long -> multiply and add : time_var += interval * multiplier */ +/* note: multiplier must be <> 0 due to overflow test */ +#define ULL_MUL_ADD(time_var, interval, multiplier, overflow_flag) { \ + /* Test overflow on MUL by pre-condition: If (ULL_MAX / a) < b => overflow! */ \ + overflow_flag |= ((ULL_MAX / (multiplier)) < GET_CVALUE(uint64, interval)); \ + /* Test overflow on ADD by pre-condition: If (ULL_MAX - a) < b => overflow! */ \ + overflow_flag |= ((ULL_MAX - (GET_CVALUE(uint64, interval) * multiplier)) < time_var); \ + time_var += GET_CVALUE(uint64, interval) * (multiplier); \ +} + +/* long double -> multiply and add : time_var += interval * multiplier */ +#define LDB_MUL_ADD(time_var, interval, multiplier) { \ + time_var += GET_CVALUE(real64, interval) * (multiplier); \ +} + + unsigned long long calculate_time(symbol_c *symbol) { if (NULL == symbol) return 0; @@ -553,52 +586,54 @@ unsigned long long calculate_time(symbol_c *symbol) { /* SYM_REF5(interval_c, days, hours, minutes, seconds, milliseconds) */ unsigned long long int time_ull = 0; long double time_ld = 0; - /* - const unsigned long long int MILLISECOND = 1000000; - const unsigned long long int SECOND = 1000 * MILLISECOND - */ + bool ovflow = false; if (NULL != interval->milliseconds) { if (VALID_CVALUE( int64, interval->milliseconds) && GET_CVALUE( int64, interval->milliseconds) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->milliseconds)) time_ull += GET_CVALUE( int64, interval->milliseconds) * MILLISECOND; - else if (VALID_CVALUE(uint64, interval->milliseconds)) time_ull += GET_CVALUE(uint64, interval->milliseconds) * MILLISECOND; - else if (VALID_CVALUE(real64, interval->milliseconds)) time_ld += GET_CVALUE(real64, interval->milliseconds) * MILLISECOND; + if (VALID_CVALUE(uint64, interval->milliseconds)) ULL_MUL_ADD(time_ull, interval->milliseconds, MILLISECOND, ovflow) + else if (VALID_CVALUE(real64, interval->milliseconds)) LDB_MUL_ADD(time_ld , interval->milliseconds, MILLISECOND) else ERROR; // if (NULL != interval->milliseconds) is true, then it must have a valid constant value! } if (NULL != interval->seconds ) { if (VALID_CVALUE( int64, interval->seconds ) && GET_CVALUE( int64, interval->seconds ) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->seconds )) time_ull += GET_CVALUE( int64, interval->seconds ) * SECOND; - else if (VALID_CVALUE(uint64, interval->seconds )) time_ull += GET_CVALUE(uint64, interval->seconds ) * SECOND; - else if (VALID_CVALUE(real64, interval->seconds )) time_ld += GET_CVALUE(real64, interval->seconds ) * SECOND; + if (VALID_CVALUE(uint64, interval->seconds )) ULL_MUL_ADD(time_ull, interval->seconds, SECOND, ovflow) + else if (VALID_CVALUE(real64, interval->seconds )) LDB_MUL_ADD(time_ld , interval->seconds, SECOND) else ERROR; // if (NULL != interval->seconds) is true, then it must have a valid constant value! } if (NULL != interval->minutes ) { if (VALID_CVALUE( int64, interval->minutes ) && GET_CVALUE( int64, interval->minutes ) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->minutes )) time_ull += GET_CVALUE( int64, interval->minutes ) * SECOND * 60; - else if (VALID_CVALUE(uint64, interval->minutes )) time_ull += GET_CVALUE(uint64, interval->minutes ) * SECOND * 60; - else if (VALID_CVALUE(real64, interval->minutes )) time_ld += GET_CVALUE(real64, interval->minutes ) * SECOND * 60; + if (VALID_CVALUE(uint64, interval->minutes )) ULL_MUL_ADD(time_ull, interval->minutes, SECOND * 60, ovflow) + else if (VALID_CVALUE(real64, interval->minutes )) LDB_MUL_ADD(time_ld , interval->minutes, SECOND * 60) else ERROR; // if (NULL != interval->minutes) is true, then it must have a valid constant value! } if (NULL != interval->hours ) { if (VALID_CVALUE( int64, interval->hours ) && GET_CVALUE( int64, interval->hours ) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->hours )) time_ull += GET_CVALUE( int64, interval->hours ) * SECOND * 60 * 60; - else if (VALID_CVALUE(uint64, interval->hours )) time_ull += GET_CVALUE(uint64, interval->hours ) * SECOND * 60 * 60; - else if (VALID_CVALUE(real64, interval->hours )) time_ld += GET_CVALUE(real64, interval->hours ) * SECOND * 60 * 60; + if (VALID_CVALUE(uint64, interval->hours )) ULL_MUL_ADD(time_ull, interval->hours, SECOND * 60 * 60, ovflow) + else if (VALID_CVALUE(real64, interval->hours )) LDB_MUL_ADD(time_ld , interval->hours, SECOND * 60 * 60) else ERROR; // if (NULL != interval->hours) is true, then it must have a valid constant value! } if (NULL != interval->days ) { if (VALID_CVALUE( int64, interval->days ) && GET_CVALUE( int64, interval->days ) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->days )) time_ull += GET_CVALUE( int64, interval->days ) * SECOND * 60 * 60 * 24; - else if (VALID_CVALUE(uint64, interval->days )) time_ull += GET_CVALUE(uint64, interval->days ) * SECOND * 60 * 60 * 24; - else if (VALID_CVALUE(real64, interval->days )) time_ld += GET_CVALUE(real64, interval->days ) * SECOND * 60 * 60 * 24; + if (VALID_CVALUE(uint64, interval->days )) ULL_MUL_ADD(time_ull, interval->days, SECOND * 60 * 60 * 24, ovflow) + else if (VALID_CVALUE(real64, interval->days )) LDB_MUL_ADD(time_ld , interval->days, SECOND * 60 * 60 * 24) else ERROR; // if (NULL != interval->days) is true, then it must have a valid constant value! } + /* Test overflow on ADD by pre-condition: If (ULL_MAX - a) < b => overflow! */ + ovflow |= ((ULL_MAX - time_ull) < (unsigned long long)time_ld); time_ull += time_ld; + + if (ovflow) { + /* time is being stored in ns resolution (MILLISECOND #define is set to 1000000) */ + /* time is being stored in unsigned long long (ISO C99 guarantees at least 64 bits) */ + /* 2⁶64ns works out to around 584.5 years, assuming 365.25 days per year */ + STAGE4_ERROR(symbol, symbol, "Internal overflow calculating task interval (must be < 584 years)."); + } + return time_ull; }; ERROR; // should never reach this point! @@ -613,53 +648,89 @@ unsigned long long calculate_time(symbol_c *symbol) { class calculate_common_ticktime_c: public iterator_visitor_c { private: unsigned long long common_ticktime; - unsigned long long least_common_ticktime; - + + /* Tick overflow can't happen at 2^32 because it + * must align with task periods. + * + * Instead of overflowing naturaly at 2^32 + * the overall periodicity of tasks scheduling + * is used to find the closest overflow lesser than 2^32 + * + */ + + /* after common_period ticks, all task period align again */ + unsigned long common_period; + public: calculate_common_ticktime_c(void){ common_ticktime = 0; - least_common_ticktime = 0; + common_period = 1; /* first tick time equals single/first task period */ } - unsigned long long euclide(unsigned long long a, unsigned long long b) { - unsigned long long c = a % b; - if (c == 0) - return b; - else - return euclide(b, c); - } - - void update_ticktime(unsigned long long time) { - if (common_ticktime == 0) - common_ticktime = time; - else if (time > common_ticktime) - common_ticktime = euclide(time, common_ticktime); - else - common_ticktime = euclide(common_ticktime, time); - if (least_common_ticktime == 0) - least_common_ticktime = time; - else - least_common_ticktime = (least_common_ticktime * time) / common_ticktime; + unsigned long long GCM(unsigned long long a, unsigned long long b) { + if(a >= b){ + unsigned long long c = a % b; + if (c == 0) + return b; + else + return GCM(b, c); + } else { + return GCM(b, a); + } } + bool update_ticktime(unsigned long long time) { + if (common_ticktime == 0) + common_ticktime = time; + else + common_ticktime = GCM(time, common_ticktime); + + unsigned long task_period = (time / common_ticktime); /* in tick count */ + + /* New Common Period is + * Least Common Multiple of + * Previous Common Period and + * New task period + * + * LCM(a,b) = a*b/GCD(a,b) + */ + unsigned long long new_common_period = + common_period * task_period / GCM(common_period, task_period); + + if(new_common_period >= UL_MAX){ + return false; + } else { + common_period = new_common_period; + } + /* else if task period already divides common period, + * keep the same common period */ + + return true; + } + unsigned long long get_common_ticktime(void) { return common_ticktime; } - unsigned long get_greatest_tick_count(void) { - unsigned long long least_common_tick = least_common_ticktime / common_ticktime; - if (least_common_tick >> 32) - ERROR; - return (unsigned long)(~(((unsigned long)-1) % (unsigned long)least_common_tick) + 1); + uint32_t get_greatest_tick_count(void) { + if (common_period == 1) { + return 0; + } else { + return UL_MAX - (UL_MAX % common_period); + } } /* TASK task_name task_initialization */ //SYM_REF2(task_configuration_c, task_name, task_initialization) void *visit(task_initialization_c *symbol) { if (symbol->interval_data_source != NULL) { - unsigned long long time = calculate_time(symbol->interval_data_source); - if (time < 0) ERROR; - else update_ticktime(time); + unsigned long long time = calculate_time(symbol->interval_data_source); + if(!update_ticktime(time)) { + /* time is being stored in ns resolution (MILLISECOND #define is set to 1000000) */ + /* time is being stored in unsigned long long (ISO C99 guarantees at least 64 bits) */ + /* 2⁶64ns works out to around 584.5 years, assuming 365.25 days per year */ + STAGE4_ERROR(symbol, symbol, "Internal overflow calculating least common multiple of task intervals (must be < 584 years)."); + } } return NULL; } @@ -859,36 +930,55 @@ class generate_c_pous_c { /* (B.2) Temporary variable for function's return value */ /* It will have the same name as the function itself! */ - s4o.print(s4o.indent_spaces); - symbol->type_name->accept(print_base); /* return type */ - s4o.print(" "); - symbol->derived_function_name->accept(print_base); - s4o.print(" = "); - { - /* get the default value of this variable's type */ - symbol_c *default_value = type_initial_value_c::get(symbol->type_name); - if (default_value == NULL) ERROR; - initialization_analyzer_c initialization_analyzer(default_value); - switch (initialization_analyzer.get_initialization_type()) { - case initialization_analyzer_c::struct_it: - { - generate_c_structure_initialization_c *structure_initialization = new generate_c_structure_initialization_c(&s4o); - structure_initialization->init_structure_default(symbol->type_name); - structure_initialization->init_structure_values(default_value); - delete structure_initialization; - } - break; - case initialization_analyzer_c::array_it: - { - generate_c_array_initialization_c *array_initialization = new generate_c_array_initialization_c(&s4o); - array_initialization->init_array_size(symbol->type_name); - array_initialization->init_array_values(default_value); - delete array_initialization; - } - break; - default: - default_value->accept(print_base); - break; + /* NOTE: matiec supports a non-standard syntax, in which functions do not return a value + * (declared as returning the special non-standard datatype VOID) + * e.g.: FUNCTION foo: VOID + * ... + * END_FUNCTION + * + * These functions cannot return any value, so they do not need a variable to + * store the return value. + * Note that any attemot to sto a value in the implicit variable + * e.g.: FUNCTION foo: VOID + * ... + * foo := 42; + * END_FUNCTION + * will always return a datatype incompatilibiyt error in stage 3 of matiec, + * so it is safe for stage 4 to assume that this return variable will never be needed + * if the function's return type is VOID. + */ + if (!get_datatype_info_c::is_VOID(symbol->type_name->datatype)) { // only print return variable if return datatype is not VOID + s4o.print(s4o.indent_spaces); + symbol->type_name->accept(print_base); /* return type */ + s4o.print(" "); + symbol->derived_function_name->accept(print_base); + s4o.print(" = "); + { + /* get the default value of this variable's type */ + symbol_c *default_value = type_initial_value_c::get(symbol->type_name); + if (default_value == NULL) ERROR; + initialization_analyzer_c initialization_analyzer(default_value); + switch (initialization_analyzer.get_initialization_type()) { + case initialization_analyzer_c::struct_it: + { + generate_c_structure_initialization_c *structure_initialization = new generate_c_structure_initialization_c(&s4o); + structure_initialization->init_structure_default(symbol->type_name); + structure_initialization->init_structure_values(default_value); + delete structure_initialization; + } + break; + case initialization_analyzer_c::array_it: + { + generate_c_array_initialization_c *array_initialization = new generate_c_array_initialization_c(&s4o); + array_initialization->init_array_size(symbol->type_name); + array_initialization->init_array_values(default_value); + delete array_initialization; + } + break; + default: + default_value->accept(print_base); + break; + } } } s4o.print(";\n\n"); @@ -909,9 +999,11 @@ class generate_c_pous_c { s4o.print(s4o.indent_spaces + "*__ENO = __BOOL_LITERAL(FALSE);\n"); s4o.indent_left(); s4o.print(s4o.indent_spaces + "}\n"); - s4o.print(s4o.indent_spaces + "return "); - symbol->derived_function_name->accept(print_base); - s4o.print(";\n"); + if (!get_datatype_info_c::is_VOID(symbol->type_name->datatype)) { // only print return variable if return datatype is not VOID + s4o.print(s4o.indent_spaces + "return "); + symbol->derived_function_name->accept(print_base); + s4o.print(";\n"); + } s4o.indent_left(); s4o.print(s4o.indent_spaces + "}\n"); } @@ -930,9 +1022,12 @@ class generate_c_pous_c { vardecl->print(symbol->var_declarations_list); delete vardecl; - s4o.print(s4o.indent_spaces + "return "); - symbol->derived_function_name->accept(print_base); - s4o.print(";\n"); + if (!get_datatype_info_c::is_VOID(symbol->type_name->datatype)) { // only print 'return ' if return datatype is not VOID + s4o.print(s4o.indent_spaces + "return "); + symbol->derived_function_name->accept(print_base); + s4o.print(";\n"); + } + s4o.indent_left(); s4o.print(s4o.indent_spaces + "}\n\n\n"); @@ -1548,6 +1643,7 @@ void *visit(single_resource_declaration_c *symbol) { }; + /***********************************************************************/ /***********************************************************************/ /***********************************************************************/ @@ -1570,10 +1666,9 @@ class generate_c_resources_c: public generate_c_base_and_typeid_c { symbol_c *current_task_name; symbol_c *current_global_vars; bool configuration_name; - stage4out_c *s4o_ptr; public: - generate_c_resources_c(stage4out_c *s4o_ptr, symbol_c *config_scope, symbol_c *resource_scope, unsigned long time) + generate_c_resources_c(stage4out_c *s4o_ptr, symbol_c *config_scope, symbol_c *resource_scope, unsigned long long time) : generate_c_base_and_typeid_c(s4o_ptr) { current_configuration = config_scope; search_config_instance = new search_var_instance_decl_c(config_scope); @@ -1583,7 +1678,6 @@ class generate_c_resources_c: public generate_c_base_and_typeid_c { current_task_name = NULL; current_global_vars = NULL; configuration_name = false; - generate_c_resources_c::s4o_ptr = s4o_ptr; }; virtual ~generate_c_resources_c(void) { @@ -1650,8 +1744,8 @@ class generate_c_resources_c: public generate_c_base_and_typeid_c { /********************/ /* 2.1.6 - Pragmas */ /********************/ - void *visit(enable_code_generation_pragma_c * symbol) {s4o_ptr->enable_output(); return NULL;} - void *visit(disable_code_generation_pragma_c * symbol) {s4o_ptr->disable_output(); return NULL;} + void *visit(enable_code_generation_pragma_c * symbol) {s4o.enable_output(); return NULL;} + void *visit(disable_code_generation_pragma_c * symbol) {s4o.disable_output(); return NULL;} /******************************************/ @@ -2077,6 +2171,336 @@ END_RESOURCE }; +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ + +/*******************************************************/ +/* Classes to generate the backup/restore functions... */ +/*******************************************************/ + +#define RESTORE_ "_restore__" +#define BACKUP_ "_backup__" + +/* class to generate the forward declaration of the XXXX_backup() and XXXX_restore() + * functions that will later (in the generated C source code) be defined + * to backup/restore the global state of each RESOURCE in the source code being compiled. + * The XXXX is actually the resource name! + */ +class generate_c_backup_resource_decl_c: public generate_c_base_and_typeid_c { + public: + generate_c_backup_resource_decl_c(stage4out_c *s4o_ptr) + : generate_c_base_and_typeid_c(s4o_ptr) {}; + + void *visit(resource_declaration_c *symbol) { + s4o.print(s4o.indent_spaces); + s4o.print("void "); + symbol->resource_name->accept(*this); + s4o.print("_backup__" "(void **buffer, int *maxsize);\n"); + s4o.print(s4o.indent_spaces); + s4o.print("void "); + symbol->resource_name->accept(*this); + s4o.print("_restore__" "(void **buffer, int *maxsize);\n"); + return NULL; + } + + + void *visit(single_resource_declaration_c *symbol) { + /* __Must__ not insert any code! */ + /* sinlge resources will not create a specific function for the resource */ + /* backup and restore opertions will be inserted together with the configuration! */ + return NULL; + } + +}; + + +/* print out the begining of the generic backup/restore function */ +void print_backup_restore_function_beg(stage4out_c &s4o, const char *func_name, const char *operation) { + /* operation will be either "_backup__" or "_restore__" */ + s4o.print("\n"); + s4o.print("void "); + s4o.print(func_name); + s4o.print(operation); + s4o.print("(void **buffer, int *maxsize) {\n"); + s4o.indent_right(); + // Don't save/restore the __CURRENT_TIME variable, as 'plc controller' has easy access to it + // and can therefore do the save/restore by itself. +//s4o.print(s4o.indent_spaces); +//s4o.print(operation); +//s4o.print("(&__CURRENT_TIME, sizeof(__CURRENT_TIME), buffer, maxsize);\n"); + s4o.print(s4o.indent_spaces); + s4o.print("#define " DECLARE_GLOBAL "(vartype, domain, varname) \\\n "); + s4o.print(operation); + s4o.print("(&domain##__##varname, sizeof(domain##__##varname), buffer, maxsize);\n"); + s4o.print(s4o.indent_spaces); + s4o.print("#define " DECLARE_GLOBAL_FB "(vartype, domain, varname) \\\n "); + s4o.print(operation); + s4o.print("(&domain##__##varname, sizeof(domain##__##varname), buffer, maxsize);\n"); + s4o.print(s4o.indent_spaces); + s4o.print("#define " DECLARE_GLOBAL_LOCATION "(vartype, location) \\\n "); + s4o.print(operation); + s4o.print("(location, sizeof(*location), buffer, maxsize);\n"); + s4o.print(s4o.indent_spaces); + s4o.print("#define " DECLARE_GLOBAL_LOCATED "(vartype, domain, varname) \\\n "); + s4o.print(operation); + s4o.print("(&domain##__##varname, sizeof(domain##__##varname), buffer, maxsize);\n"); +} + +/* print out the ending of the generic backup/restore function */ +void print_backup_restore_function_end(stage4out_c &s4o) { + s4o.print(s4o.indent_spaces); s4o.print("#undef " DECLARE_GLOBAL "\n"); + s4o.print(s4o.indent_spaces); s4o.print("#undef " DECLARE_GLOBAL_FB "\n"); + s4o.print(s4o.indent_spaces); s4o.print("#undef " DECLARE_GLOBAL_LOCATION "\n"); + s4o.print(s4o.indent_spaces); s4o.print("#undef " DECLARE_GLOBAL_LOCATED "\n"); + s4o.indent_left(); + s4o.print("}\n"); +} + + + + + +/* generate the backup/restore function for a RESOURCE */ +/* the backup/restore function generated here will be called by the backup/restore + * function generated for the configuration in which the resource is embedded + */ +class generate_c_backup_resource_c: public generate_c_base_and_typeid_c { + public: + const char *operation; + + generate_c_backup_resource_c(stage4out_c *s4o_ptr) + : generate_c_base_and_typeid_c(s4o_ptr) { + operation = NULL; + }; + + + virtual ~generate_c_backup_resource_c(void) {} + + +private: + void print_forward_declarations(void) { + s4o.print("\n\n\n"); + + s4o.print("void "); + s4o.print("_backup__"); + s4o.print("(void *varptr, int varsize, void **buffer, int *maxsize);\n"); + s4o.print("void "); + s4o.print("_restore__"); + s4o.print("(void *varptr, int varsize, void **buffer, int *maxsize);\n"); + + s4o.print("\n\n\n"); + s4o.print("#undef " DECLARE_GLOBAL "\n"); + s4o.print("#undef " DECLARE_GLOBAL_FB "\n"); + s4o.print("#undef " DECLARE_GLOBAL_LOCATION "\n"); + s4o.print("#undef " DECLARE_GLOBAL_LOCATED "\n"); + } + + public: + /********************/ + /* 2.1.6 - Pragmas */ + /********************/ + void *visit(enable_code_generation_pragma_c * symbol) {s4o.enable_output(); return NULL;} + void *visit(disable_code_generation_pragma_c * symbol) {s4o.disable_output();return NULL;} + + + /********************************/ + /* B 1.7 Configuration elements */ + /********************************/ + void *visit(resource_declaration_c *symbol) { + char *resource_name = strdup(symbol->resource_name->token->value); + /* convert to upper case */ + for (char *c = resource_name; *c != '\0'; *c = toupper(*c), c++); + + generate_c_vardecl_c vardecl = generate_c_vardecl_c(&s4o, + generate_c_vardecl_c::local_vf, + generate_c_vardecl_c::global_vt, + symbol->resource_name); + + print_forward_declarations(); + + print_backup_restore_function_beg(s4o, resource_name, "_backup__"); + if (symbol->global_var_declarations != NULL) + vardecl.print(symbol->global_var_declarations); + if (symbol->resource_declaration != NULL) { + operation = "_backup__"; + symbol->resource_declaration->accept(*this); // will call visit(single_resource_declaration_c *) + operation = NULL; + } + print_backup_restore_function_end(s4o); + + print_backup_restore_function_beg(s4o, resource_name, "_restore__"); + if (symbol->global_var_declarations != NULL) + vardecl.print(symbol->global_var_declarations); + if (symbol->resource_declaration != NULL) { + operation = "_restore__"; + symbol->resource_declaration->accept(*this); // will call visit(single_resource_declaration_c *) + operation = NULL; + } + print_backup_restore_function_end(s4o); + + return NULL; + } + + void *visit(single_resource_declaration_c *symbol) { + /* Must store the declared/instatiated PROGRAMS */ + if (symbol->program_configuration_list != NULL) + symbol->program_configuration_list->accept(*this); + return NULL; + } + + /* PROGRAM [RETAIN | NON_RETAIN] program_name [WITH task_name] ':' program_type_name ['(' prog_conf_elements ')'] */ + // SYM_REF5(program_configuration_c, retain_option, program_name, task_name, program_type_name, prog_conf_elements) + void *visit(program_configuration_c *symbol) { + // generate the following source code: + // _xxxxxx__(&program_name, sizeof(program_name), buffer, maxsize); + s4o.print(s4o.indent_spaces); + s4o.print(operation); // call _restore__() or _backup__() + s4o.print("(&"); + symbol->program_name->accept(*this); + s4o.print(", sizeof("); + symbol->program_name->accept(*this); + s4o.print("), buffer, maxsize);\n"); + return NULL; + } + + +}; + + +/* generate the backup/restore function for a CONFIGURATION */ +/* the generated function will backup/restore the global variables declared in the + * configuration, and call the backup/restore functions of each embedded resource to do + * the same for the global variables declared inside each resource. + * + * The matiec compiler will now generate two additional functions which + * will backup and restore the PLC internal state to a void *buffer. + * config_backup__(void **buffer, int *maxsize) + * config_restore__(void **buffer, int *maxsize) + * + * Both functions will backup/restore the internal state from the memory + * pointed to by *buffer, up to a maximum of *maxsize bytes. + * Both functions will return with buffer pointing to the first unused + * byte in the buffer, and maxsize with the number of remaining bytes. If + * the buffer is not sufficient to store all the internal state, maxsize + * will return with a negative number, equal to the number of missing + * bytes. + * + * In other words, to know the exact size of the buffer required to store + * the PLC internal state, malloc() that memory, and do the backup: + * int maxsize = 0; + * config_backup__(NULL, &maxsize); + * void *buffer = malloc(-1 * maxsize); + * // and now to really back the internal state... + * config_backup__(&buffer, &maxsize); + */ +class generate_c_backup_config_c: public generate_c_base_and_typeid_c { + private: + const char *func_to_call; // parameter to pass data from: void *visit(configuration_declaration_c *) + // to: void *visit(resource_declaration_c *) + + public: + generate_c_backup_config_c(stage4out_c *s4o_ptr) + : generate_c_base_and_typeid_c(s4o_ptr) { + func_to_call = NULL; + }; + + virtual ~generate_c_backup_config_c(void) {} + + + public: + /********************/ + /* 2.1.6 - Pragmas */ + /********************/ + void *visit(enable_code_generation_pragma_c * symbol) {s4o.enable_output(); return NULL;} + void *visit(disable_code_generation_pragma_c * symbol) {s4o.disable_output();return NULL;} + + + /********************************/ + /* B 1.7 Configuration elements */ + /********************************/ + /* + SYM_REF6(configuration_declaration_c, configuration_name, global_var_declarations, resource_declarations, access_declarations, instance_specific_initializations, unused) + */ + void *visit(configuration_declaration_c *symbol) { + + s4o.print("\n\n\n"); + + s4o.print("void "); + s4o.print("_backup__"); + s4o.print("(void *varptr, int varsize, void **buffer, int *maxsize) {\n"); + s4o.print(" if (varsize <= *maxsize) {memmove(*buffer, varptr, varsize); *buffer += varsize;}\n"); + s4o.print(" *maxsize -= varsize;\n"); + s4o.print("}\n"); + + s4o.print("void "); + s4o.print("_restore__"); + s4o.print("(void *varptr, int varsize, void **buffer, int *maxsize) {\n"); + s4o.print(" if (varsize <= *maxsize) {memmove(varptr, *buffer, varsize); *buffer += varsize;}\n"); + s4o.print(" *maxsize -= varsize;\n"); + s4o.print("}\n"); + + + generate_c_vardecl_c vardecl = generate_c_vardecl_c(&s4o, + generate_c_vardecl_c::local_vf, + generate_c_vardecl_c::global_vt, + symbol->configuration_name); + + s4o.print("\n\n\n"); + s4o.print("#undef " DECLARE_GLOBAL "\n"); + s4o.print("#undef " DECLARE_GLOBAL_FB "\n"); + s4o.print("#undef " DECLARE_GLOBAL_LOCATION "\n"); + s4o.print("#undef " DECLARE_GLOBAL_LOCATED "\n"); + + generate_c_backup_resource_decl_c declare_functions = generate_c_backup_resource_decl_c(&s4o); + symbol->resource_declarations->accept(declare_functions); + + print_backup_restore_function_beg(s4o, "config", "_backup__"); + vardecl.print(symbol); + s4o.print("\n"); + func_to_call = "_backup__"; + symbol->resource_declarations->accept(*this); // will call resource_declaration_list_c or single_resource_declaration_c + func_to_call = NULL; + print_backup_restore_function_end(s4o); + + print_backup_restore_function_beg(s4o, "config", "_restore__"); + vardecl.print(symbol); + s4o.print("\n"); + func_to_call = "_restore__"; + symbol->resource_declarations->accept(*this); // will call resource_declaration_list_c or single_resource_declaration_c + func_to_call = NULL; + print_backup_restore_function_end(s4o); + + return NULL; + } + + void *visit(resource_declaration_c *symbol) { + s4o.print(s4o.indent_spaces); + symbol->resource_name->accept(*this); + s4o.print(func_to_call); + s4o.print("(buffer, maxsize);\n"); + return NULL; + } + + void *visit(single_resource_declaration_c *symbol) { + /* If the configuration does not have any resources, we must store/restore the declared program instances + * inside the backup() restore() functions created for the configuration. + */ + generate_c_backup_resource_c handle_resource = generate_c_backup_resource_c(&s4o); + handle_resource.operation = func_to_call; + symbol->accept(handle_resource); + return NULL; + } + +}; + + + /***********************************************************************/ /***********************************************************************/ /***********************************************************************/ @@ -2167,7 +2591,7 @@ class generate_c_c: public iterator_visitor_c { pous_incl_s4o.print("#include \"accessor.h\"\n#include \"iec_std_lib.h\"\n\n"); for(int i = 0; i < symbol->n; i++) { - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); } pous_incl_s4o.print("#endif //__POUS_H\n"); @@ -2205,8 +2629,8 @@ class generate_c_c: public iterator_visitor_c { /* 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_implicit_typedecl); - symbol->elements[i]->accept(generate_c_typedecl); + symbol->get_element(i)->accept(generate_c_implicit_typedecl); + symbol->get_element(i)->accept(generate_c_typedecl); } return NULL; } @@ -2303,10 +2727,17 @@ class generate_c_c: public iterator_visitor_c { config_s4o.print("unsigned long long common_ticktime__ = "); config_s4o.print_long_long_integer(common_ticktime); + config_s4o.print(" * "); + config_s4o.print_long_long_integer(1000000 / MILLISECOND); config_s4o.print("; /*ns*/\n"); - config_s4o.print("unsigned long greatest_tick_count__ = "); + config_s4o.print("unsigned long greatest_tick_count__ = (unsigned long)"); config_s4o.print_long_integer(calculate_common_ticktime.get_greatest_tick_count()); config_s4o.print("; /*tick*/\n"); + + if (generate_plc_state_backup_fuctions__ > 0) { + generate_c_backup_config_c generate_backup = generate_c_backup_config_c(&config_s4o); + symbol->accept(generate_backup); + } } symbol->resource_declarations->accept(*this); @@ -2322,6 +2753,10 @@ class generate_c_c: public iterator_visitor_c { stage4out_c resources_s4o(current_builddir, current_name, "c"); generate_c_resources_c generate_c_resources(&resources_s4o, current_configuration, symbol, common_ticktime); symbol->accept(generate_c_resources); + if (generate_plc_state_backup_fuctions__ > 0) { + generate_c_backup_resource_c generate_backup = generate_c_backup_resource_c(&resources_s4o); + symbol->accept(generate_backup); + } return NULL; } diff --git a/utils/matiec_src/stage4/generate_c/generate_c.hh b/utils/matiec_src/stage4/generate_c/generate_c.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/stage4/generate_c/generate_c_base.cc b/utils/matiec_src/stage4/generate_c/generate_c_base.cc index 676f400..639aff7 100644 --- a/utils/matiec_src/stage4/generate_c/generate_c_base.cc +++ b/utils/matiec_src/stage4/generate_c/generate_c_base.cc @@ -201,13 +201,13 @@ class generate_c_base_c: public iterator_visitor_c { if (list->n > 0) { //std::cout << "generate_c_base_c::print_list(n = " << list->n << ") 000\n"; s4o.print(pre_elem_str); - list->elements[0]->accept(*visitor); + list->get_element(0)->accept(*visitor); } for(int i = 1; i < list->n; i++) { //std::cout << "generate_c_base_c::print_list " << i << "\n"; s4o.print(inter_elem_str); - list->elements[i]->accept(*visitor); + list->get_element(i)->accept(*visitor); } if (list->n > 0) @@ -658,6 +658,8 @@ void *visit(date_and_time_c *symbol) { void *visit(safestring_type_name_c *symbol) {s4o.print("STRING"); return NULL;} void *visit(safewstring_type_name_c *symbol) {s4o.print("WSTRING"); return NULL;} + void *visit(void_type_name_c *symbol) {s4o.print("void"); return NULL;} + /********************************/ /* B.1.3.2 - Generic data types */ /********************************/ diff --git a/utils/matiec_src/stage4/generate_c/generate_c_configbody.cc b/utils/matiec_src/stage4/generate_c/generate_c_configbody.cc old mode 100755 new mode 100644 diff --git a/utils/matiec_src/stage4/generate_c/generate_c_il.cc b/utils/matiec_src/stage4/generate_c/generate_c_il.cc old mode 100755 new mode 100644 index 50c07fa..8499a38 --- a/utils/matiec_src/stage4/generate_c/generate_c_il.cc +++ b/utils/matiec_src/stage4/generate_c/generate_c_il.cc @@ -661,7 +661,7 @@ void *visit(subscript_list_c *symbol) { if (dimension == NULL) ERROR; s4o.print("[("); - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); s4o.print(") - ("); dimension->accept(*this); s4o.print(")]"); @@ -711,9 +711,9 @@ void *visit(instruction_list_c *symbol) { declare_implicit_variable_back(); for(int i = 0; i < symbol->n; i++) { - print_line_directive(symbol->elements[i]); + print_line_directive(symbol->get_element(i)); s4o.print(s4o.indent_spaces); - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); s4o.print(";\n"); } return NULL; @@ -884,8 +884,11 @@ void *visit(il_function_call_c *symbol) { int fdecl_mutiplicity = function_symtable.count(symbol->function_name); if (fdecl_mutiplicity == 0) ERROR; - this->implicit_variable_result.accept(*this); - s4o.print(" = "); + /* when function returns a void, we do not store the value in the default variable! */ + if (!get_datatype_info_c::is_VOID(symbol->datatype)) { + this->implicit_variable_result.accept(*this); + s4o.print(" = "); + } if (function_type_prefix != NULL) { s4o.print("("); @@ -1288,8 +1291,11 @@ void *visit(il_formal_funct_call_c *symbol) { /* function being called is NOT overloaded! */ f_decl = NULL; - this->implicit_variable_result.accept(*this); - s4o.print(" = "); + /* when function returns a void, we do not store the value in the default variable! */ + if (!get_datatype_info_c::is_VOID(symbol->datatype)) { + this->implicit_variable_result.accept(*this); + s4o.print(" = "); + } if (function_type_prefix != NULL) { s4o.print("("); diff --git a/utils/matiec_src/stage4/generate_c/generate_c_inlinefcall.cc b/utils/matiec_src/stage4/generate_c/generate_c_inlinefcall.cc old mode 100755 new mode 100644 index cbb00b7..641de21 --- a/utils/matiec_src/stage4/generate_c/generate_c_inlinefcall.cc +++ b/utils/matiec_src/stage4/generate_c/generate_c_inlinefcall.cc @@ -104,7 +104,7 @@ class generate_c_inlinefcall_c: public generate_c_base_and_typeid_c { } s4o.print(s4o.indent_spaces); - s4o.print("inline "); + s4o.print("static inline "); function_type_prefix->accept(*this); s4o.print(" __"); fbname->accept(*this); @@ -280,6 +280,15 @@ class generate_c_inlinefcall_c: public generate_c_base_and_typeid_c { return NULL; } + /********************/ + /* 2.1.6 - Pragmas */ + /********************/ + //SYM_REF0(disable_code_generation_pragma_c) + //SYM_REF0(enable_code_generation_pragma_c) + //SYM_TOKEN(pragma_c) + void *visit(pragma_c *symbol) {return NULL;} + + /*************************/ /* B.1 - Common elements */ /*************************/ diff --git a/utils/matiec_src/stage4/generate_c/generate_c_sfc.cc b/utils/matiec_src/stage4/generate_c/generate_c_sfc.cc old mode 100755 new mode 100644 index cd1b6a4..58a89c3 --- a/utils/matiec_src/stage4/generate_c/generate_c_sfc.cc +++ b/utils/matiec_src/stage4/generate_c/generate_c_sfc.cc @@ -443,7 +443,7 @@ class generate_c_sfc_elements_c: public generate_c_base_and_typeid_c { for(int i = 0; i < symbol->n; i++) { s4o.print(GET_VAR); s4o.print("("); - print_step_argument(symbol->elements[i], "X"); + print_step_argument(symbol->get_element(i), "X"); s4o.print(")"); if (i < symbol->n - 1) { s4o.print(" && "); @@ -452,12 +452,12 @@ class generate_c_sfc_elements_c: public generate_c_base_and_typeid_c { break; case stepset_sg: for(int i = 0; i < symbol->n; i++) { - print_set_step(symbol->elements[i]); + print_set_step(symbol->get_element(i)); } break; case stepreset_sg: for(int i = 0; i < symbol->n; i++) { - print_reset_step(symbol->elements[i]); + print_reset_step(symbol->get_element(i)); } break; default: @@ -577,7 +577,7 @@ class generate_c_sfc_elements_c: public generate_c_base_and_typeid_c { s4o.print(s4o.indent_spaces + "if (active && __time_cmp("); print_step_argument(current_step, "T.value"); s4o.print(", "); - symbol->action_time->accept(*this); + symbol->action_time->accept(*generate_c_st); if (strcmp(qualifier, "L") == 0) s4o.print(") < 0) "); else @@ -618,7 +618,7 @@ class generate_c_sfc_elements_c: public generate_c_base_and_typeid_c { s4o.print(" = 1;\n" + s4o.indent_spaces); print_action_argument(current_action, "reset_remaining_time"); s4o.print(" = "); - symbol->action_time->accept(*this); + symbol->action_time->accept(*generate_c_st); s4o.print(";\n"); s4o.indent_left(); s4o.print(s4o.indent_spaces + "}\n"); @@ -632,7 +632,7 @@ class generate_c_sfc_elements_c: public generate_c_base_and_typeid_c { s4o.print("\n" + s4o.indent_spaces); print_action_argument(current_action, "set_remaining_time"); s4o.print(" = "); - symbol->action_time->accept(*this); + symbol->action_time->accept(*generate_c_st); s4o.print(";\n"); s4o.indent_left(); s4o.print(s4o.indent_spaces + "}\n"); @@ -710,8 +710,8 @@ class generate_c_sfc_c: public generate_c_base_and_typeid_c { generate_c_sfc_elements->reset_transition_number(); for(i = 0; i < symbol->n; i++) { - symbol->elements[i]->accept(*this); - generate_c_sfc_elements->generate(symbol->elements[i], generate_c_sfc_elements_c::transitionlist_sg); + symbol->get_element(i)->accept(*this); + generate_c_sfc_elements->generate(symbol->get_element(i), generate_c_sfc_elements_c::transitionlist_sg); } s4o.print(s4o.indent_spaces +"INT i;\n"); @@ -853,7 +853,7 @@ class generate_c_sfc_c: public generate_c_base_and_typeid_c { s4o.print(s4o.indent_spaces + "// Transitions reset steps\n"); generate_c_sfc_elements->reset_transition_number(); for(i = 0; i < symbol->n; i++) { - generate_c_sfc_elements->generate(symbol->elements[i], generate_c_sfc_elements_c::stepreset_sg); + generate_c_sfc_elements->generate(symbol->get_element(i), generate_c_sfc_elements_c::stepreset_sg); } s4o.print("\n"); @@ -861,14 +861,14 @@ class generate_c_sfc_c: public generate_c_base_and_typeid_c { s4o.print(s4o.indent_spaces + "// Transitions set steps\n"); generate_c_sfc_elements->reset_transition_number(); for(i = 0; i < symbol->n; i++) { - generate_c_sfc_elements->generate(symbol->elements[i], generate_c_sfc_elements_c::stepset_sg); + generate_c_sfc_elements->generate(symbol->get_element(i), generate_c_sfc_elements_c::stepset_sg); } s4o.print("\n"); /* generate step association */ s4o.print(s4o.indent_spaces + "// Steps association\n"); for(i = 0; i < symbol->n; i++) { - generate_c_sfc_elements->generate(symbol->elements[i], generate_c_sfc_elements_c::actionassociation_sg); + generate_c_sfc_elements->generate(symbol->get_element(i), generate_c_sfc_elements_c::actionassociation_sg); } s4o.print("\n"); @@ -967,7 +967,7 @@ class generate_c_sfc_c: public generate_c_base_and_typeid_c { } } for(i = 0; i < symbol->n; i++) { - generate_c_sfc_elements->generate(symbol->elements[i], generate_c_sfc_elements_c::actionbody_sg); + generate_c_sfc_elements->generate(symbol->get_element(i), generate_c_sfc_elements_c::actionbody_sg); } s4o.print("\n"); diff --git a/utils/matiec_src/stage4/generate_c/generate_c_sfcdecl.cc b/utils/matiec_src/stage4/generate_c/generate_c_sfcdecl.cc old mode 100755 new mode 100644 index 5d7ff92..94a095e --- a/utils/matiec_src/stage4/generate_c/generate_c_sfcdecl.cc +++ b/utils/matiec_src/stage4/generate_c/generate_c_sfcdecl.cc @@ -85,7 +85,7 @@ class generate_c_sfcdecl_c: protected generate_c_base_and_typeid_c { switch (wanted_sfcdeclaration) { case sfcdecl_sd: for(int i = 0; i < symbol->n; i++) - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); /* steps table declaration */ s4o.print(s4o.indent_spaces + "STEP __step_list["); @@ -120,7 +120,7 @@ class generate_c_sfcdecl_c: protected generate_c_base_and_typeid_c { /* steps table count */ wanted_sfcdeclaration = stepcount_sd; for(int i = 0; i < symbol->n; i++) - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); s4o.print(s4o.indent_spaces); print_variable_prefix(); s4o.print("__nb_steps = "); @@ -130,7 +130,7 @@ class generate_c_sfcdecl_c: protected generate_c_base_and_typeid_c { wanted_sfcdeclaration = sfcinit_sd; /* steps table initialisation */ - s4o.print(s4o.indent_spaces + "static const STEP temp_step = {{0, 0}, 0, {0, 0}};\n"); + s4o.print(s4o.indent_spaces + "static const STEP temp_step = {{0, 0}, 0, {{0, 0}, 0}};\n"); s4o.print(s4o.indent_spaces + "for(i = 0; i < "); print_variable_prefix(); s4o.print("__nb_steps; i++) {\n"); @@ -141,12 +141,12 @@ class generate_c_sfcdecl_c: protected generate_c_base_and_typeid_c { s4o.indent_left(); s4o.print(s4o.indent_spaces + "}\n"); for(int i = 0; i < symbol->n; i++) - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); /* actions table count */ wanted_sfcdeclaration = actioncount_sd; for(int i = 0; i < symbol->n; i++) - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); s4o.print(s4o.indent_spaces); print_variable_prefix(); s4o.print("__nb_actions = "); @@ -170,7 +170,7 @@ class generate_c_sfcdecl_c: protected generate_c_base_and_typeid_c { /* transitions table count */ wanted_sfcdeclaration = transitioncount_sd; for(int i = 0; i < symbol->n; i++) - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); s4o.print(s4o.indent_spaces); print_variable_prefix(); s4o.print("__nb_transitions = "); @@ -187,7 +187,7 @@ class generate_c_sfcdecl_c: protected generate_c_base_and_typeid_c { case stepdef_sd: s4o.print("// Steps definitions\n"); for(int i = 0; i < symbol->n; i++) - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); s4o.print("\n"); break; case actiondef_sd: @@ -196,12 +196,12 @@ class generate_c_sfcdecl_c: protected generate_c_base_and_typeid_c { // first fill up the this->variable_list variable! wanted_sfcdeclaration = actioncount_sd; for(int i = 0; i < symbol->n; i++) - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); action_number = 0; // reset the counter! wanted_sfcdeclaration = actiondef_sd; // Now do the defines for actions! for(int i = 0; i < symbol->n; i++) - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); // Now do the defines for actions that reference a variable instead of an action block! std::list::iterator pt; for(pt = variable_list.begin(); pt != variable_list.end(); pt++) { @@ -219,18 +219,18 @@ class generate_c_sfcdecl_c: protected generate_c_base_and_typeid_c { case stepundef_sd: s4o.print("// Steps undefinitions\n"); for(int i = 0; i < symbol->n; i++) - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); s4o.print("\n"); break; case actionundef_sd: s4o.print("// Actions undefinitions\n"); for(int i = 0; i < symbol->n; i++) - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); { // first fill up the this->variable_list variable! wanted_sfcdeclaration = actioncount_sd; for(int i = 0; i < symbol->n; i++) - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); wanted_sfcdeclaration = actionundef_sd; std::list::iterator pt; for(pt = variable_list.begin(); pt != variable_list.end(); pt++) { diff --git a/utils/matiec_src/stage4/generate_c/generate_c_st.cc b/utils/matiec_src/stage4/generate_c/generate_c_st.cc old mode 100755 new mode 100644 index 2863d6c..083662c --- a/utils/matiec_src/stage4/generate_c/generate_c_st.cc +++ b/utils/matiec_src/stage4/generate_c/generate_c_st.cc @@ -169,8 +169,9 @@ void *print_setter(symbol_c* symbol, symbol_c* fb_symbol = NULL, symbol_c* fb_value = NULL) { + unsigned int vartype; if (fb_symbol == NULL) { - unsigned int vartype = analyse_variable_c::first_nonfb_vardecltype(symbol, scope_); + vartype = analyse_variable_c::first_nonfb_vardecltype(symbol, scope_); symbol_c *first_nonfb = analyse_variable_c::find_first_nonfb(symbol); if (first_nonfb == NULL) ERROR; if (vartype == search_var_instance_decl_c::external_vt) { @@ -186,7 +187,7 @@ void *print_setter(symbol_c* symbol, s4o.print(SET_VAR); } else { - unsigned int vartype = search_var_instance_decl->get_vartype(fb_symbol); + vartype = search_var_instance_decl->get_vartype(fb_symbol); if (vartype == search_var_instance_decl_c::external_vt) s4o.print(SET_EXTERNAL_FB); else @@ -195,12 +196,20 @@ void *print_setter(symbol_c* symbol, s4o.print("("); if (fb_symbol != NULL) { - print_variable_prefix(); - // It is my (MJS) conviction that by this time the following will always be true... - // wanted_variablegeneration == expression_vg; - fb_symbol->accept(*this); - s4o.print(".,"); - symbol->accept(*this); + if (vartype == search_var_instance_decl_c::external_vt){ + print_variable_prefix(); + s4o.print(","); + fb_symbol->accept(*this); + s4o.print("->"); + symbol->accept(*this); + }else{ + print_variable_prefix(); + // It is my (MJS) conviction that by this time the following will always be true... + // wanted_variablegeneration == expression_vg; + fb_symbol->accept(*this); + s4o.print(".,"); + symbol->accept(*this); + } s4o.print(","); s4o.print(","); } else { @@ -422,7 +431,7 @@ void *visit(subscript_list_c *symbol) { if (dimension == NULL) ERROR; s4o.print("[("); - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); s4o.print(") - ("); dimension->accept(*this); s4o.print(")]"); @@ -593,7 +602,7 @@ void *visit(or_expression_c *symbol) { void *visit(xor_expression_c *symbol) { if (get_datatype_info_c::is_BOOL_compatible(symbol->datatype)) { - s4o.print("("); + s4o.print("(("); symbol->l_exp->accept(*this); s4o.print(" && !"); symbol->r_exp->accept(*this); @@ -601,7 +610,7 @@ void *visit(xor_expression_c *symbol) { symbol->l_exp->accept(*this); s4o.print(" && "); symbol->r_exp->accept(*this); - s4o.print(")"); + s4o.print("))"); return NULL; } if (get_datatype_info_c::is_ANY_nBIT_compatible(symbol->datatype)) @@ -925,9 +934,9 @@ void *visit(function_invocation_c *symbol) { /********************/ void *visit(statement_list_c *symbol) { for(int i = 0; i < symbol->n; i++) { - print_line_directive(symbol->elements[i]); + print_line_directive(symbol->get_element(i)); s4o.print(s4o.indent_spaces); - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); s4o.print(";\n"); } return NULL; @@ -937,7 +946,7 @@ void *visit(statement_list_c *symbol) { /* B 3.2.1 Assignment Statements */ /*********************************/ void *visit(assignment_statement_c *symbol) { - symbol_c *left_type = search_varfb_instance_type->get_type_id(symbol->l_exp); + symbol_c *left_type = symbol->l_exp->datatype; if (this->is_variable_prefix_null()) { symbol->l_exp->accept(*this); @@ -1213,10 +1222,10 @@ void *visit(case_list_c *symbol) { */ if (0 != i) s4o.print(" ||\n" + s4o.indent_spaces + " "); s4o.print("("); - subrange_c *subrange = dynamic_cast(symbol->elements[i]); + subrange_c *subrange = dynamic_cast(symbol->get_element(i)); if (NULL == subrange) { s4o.print("__case_expression == "); - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); } else { s4o.print("__case_expression >= "); subrange->lower_limit->accept(*this); @@ -1233,19 +1242,70 @@ void *visit(case_list_c *symbol) { /* B 3.2.4 Iteration Statements */ /********************************/ void *visit(for_statement_c *symbol) { - s4o.print("for("); - symbol->control_variable->accept(*this); - s4o.print(" = "); - symbol->beg_expression->accept(*this); - s4o.print("; "); + /* Due to the way the GET/SET_GLOBAL accessor macros access VAR_GLOBAL variables, + * these varibles cannot be used within a C for(;;) loop. + * We must therefore implemnt the FOR END_FOR loop as a C while() loop + */ + s4o.print("/* FOR ... */\n" + s4o.indent_spaces); + /* For the initialization part, we create an assignment_statement_c */ + /* and have this visitor visit it! */ + assignment_statement_c ini_assignment(symbol->control_variable, symbol->beg_expression); + ini_assignment.accept(*this); + //symbol->control_variable->accept(*this); // this does not work for VAR_GLOBAL variables + //s4o.print(" = "); + //symbol->beg_expression->accept(*this); + + /* comparison // check for end of loop */ + s4o.print(";\n"); + s4o.print(s4o.indent_spaces + "{\n"); + s4o.indent_right(); + s4o.print(s4o.indent_spaces + "int __do_increment = 0;\n"); + s4o.print(s4o.indent_spaces + "while(1) {\n"); + + s4o.indent_right(); + + /* increment part */ + s4o.print(s4o.indent_spaces + "if(__do_increment){\n"); + s4o.indent_right(); + s4o.print(s4o.indent_spaces + "/* BY ... (of FOR loop) */\n"); + s4o.print(s4o.indent_spaces); if (symbol->by_expression == NULL) { - /* increment by 1 */ + /* increment by 1 */ + /* For the increment part, we create an add_expression_c and assignment_statement_c */ + /* and have this visitor vist the latter! */ + integer_c integer_oneval("1"); + add_expression_c add_expression(symbol->control_variable, &integer_oneval); + assignment_statement_c inc_assignment(symbol->control_variable, &add_expression); + integer_oneval.const_value._int64 .set(1); // set the stage3 anottation we need + integer_oneval.const_value._uint64.set(1); // set the stage3 anottation we need + integer_oneval.datatype = symbol->control_variable->datatype; // set the stage3 anottation we need + add_expression.datatype = symbol->control_variable->datatype; // set the stage3 anottation we need + inc_assignment.accept(*this); + //symbol->control_variable->accept(*this); // this does not work for VAR_GLOBAL variables + //s4o.print("++"); + } else { + /* increment by user defined value */ + /* For the increment part, we create an add_expression_c and assignment_statement_c */ + /* and have this visitor vist the latter! */ + add_expression_c add_expression(symbol->control_variable, symbol->by_expression); + assignment_statement_c inc_assignment(symbol->control_variable, &add_expression); + add_expression.datatype = symbol->control_variable->datatype; // set the stage3 anottation we need + inc_assignment.accept(*this); + //symbol->control_variable->accept(*this); // this does not work for VAR_GLOBAL variables + //s4o.print(" += ("); + //symbol->by_expression->accept(*this); + //s4o.print(")"); + } + s4o.print(";\n"); + s4o.indent_left(); + s4o.print(s4o.indent_spaces + "} else __do_increment = 1;\n"); + + s4o.print(s4o.indent_spaces + "if("); + if (symbol->by_expression == NULL) { + /* increment by 1 */ symbol->control_variable->accept(*this); s4o.print(" <= "); symbol->end_expression->accept(*this); - s4o.print("; "); - symbol->control_variable->accept(*this); - s4o.print("++"); } else { /* increment by user defined value */ /* The user defined increment value may be negative, in which case @@ -1265,19 +1325,21 @@ void *visit(for_statement_c *symbol) { symbol->control_variable->accept(*this); s4o.print(" >= ("); symbol->end_expression->accept(*this); - s4o.print(")); "); - symbol->control_variable->accept(*this); - s4o.print(" += ("); - symbol->by_expression->accept(*this); - s4o.print(")"); + s4o.print(")) "); } - s4o.print(")"); - - s4o.print(" {\n"); + s4o.print(s4o.indent_spaces + "){\n"); s4o.indent_right(); + + /* the body part */ symbol->statement_list->accept(*this); + s4o.indent_left(); - s4o.print(s4o.indent_spaces); s4o.print("}"); + s4o.print(s4o.indent_spaces + "}else break;\n"); + + s4o.indent_left(); + s4o.print(s4o.indent_spaces + "}\n"); + s4o.indent_left(); + s4o.print(s4o.indent_spaces + "} /* END_FOR */"); return NULL; } @@ -1297,9 +1359,9 @@ void *visit(repeat_statement_c *symbol) { s4o.indent_right(); symbol->statement_list->accept(*this); s4o.indent_left(); - s4o.print(s4o.indent_spaces); s4o.print("} while("); + s4o.print(s4o.indent_spaces); s4o.print("} while(!("); symbol->expression->accept(*this); - s4o.print(")"); + s4o.print("))"); return NULL; } @@ -1308,6 +1370,10 @@ void *visit(exit_statement_c *symbol) { return NULL; } +void *visit(continue_statement_c *symbol) { + s4o.print("continue"); + return NULL; +} }; /* generate_c_st_c */ diff --git a/utils/matiec_src/stage4/generate_c/generate_c_typedecl.cc b/utils/matiec_src/stage4/generate_c/generate_c_typedecl.cc index f5708cb..a3bfdc2 100644 --- a/utils/matiec_src/stage4/generate_c/generate_c_typedecl.cc +++ b/utils/matiec_src/stage4/generate_c/generate_c_typedecl.cc @@ -178,7 +178,7 @@ class generate_datatypes_aliasid_c: fcall_visitor_c { /* 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);} + for(int i = 0; i < symbol->n; i++) {symbol->get_element(i)->accept(*this);} return NULL; } @@ -295,12 +295,12 @@ class generate_c_typedecl_c: public generate_c_base_and_typeid_c { if (list->n > 0) { s4o_incl.print(pre_elem_str); - list->elements[0]->accept(*this); + list->get_element(0)->accept(*this); } for(int i = 1; i < list->n; i++) { s4o_incl.print(inter_elem_str); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); } if (list->n > 0) diff --git a/utils/matiec_src/stage4/generate_c/generate_c_vardecl.cc b/utils/matiec_src/stage4/generate_c/generate_c_vardecl.cc index 4f1e2a3..8e8d140 100644 --- a/utils/matiec_src/stage4/generate_c/generate_c_vardecl.cc +++ b/utils/matiec_src/stage4/generate_c/generate_c_vardecl.cc @@ -168,7 +168,7 @@ class generate_c_array_initialization_c: public generate_c_base_and_typeid_c { s4o.print("("); print_variable_prefix(); s4o.print(","); - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); s4o.print(",,temp);\n"); } return NULL; @@ -249,14 +249,14 @@ class generate_c_array_initialization_c: public generate_c_base_and_typeid_c { ERROR; if (defined_values_count > 0) s4o.print(","); - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); defined_values_count++; } else { - array_initial_elements_c *array_initial_element = dynamic_cast(symbol->elements[i]); + array_initial_elements_c *array_initial_element = dynamic_cast(symbol->get_element(i)); if (array_initial_element != NULL) { - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); } } current_initialization_count++; @@ -414,7 +414,7 @@ class structure_element_iterator_c : public null_visitor_c { void *visit(structure_element_declaration_list_c *symbol) { void *res; for (int i = 0; i < symbol->n; i++) { - res = symbol->elements[i]->accept(*this); + res = symbol->get_element(i)->accept(*this); if (res != NULL) return res; } @@ -472,7 +472,7 @@ class structure_init_element_iterator_c : public null_visitor_c { void *visit(structure_element_initialization_list_c *symbol) { void *res; for (int i = 0; i < symbol->n; i++) { - res = symbol->elements[i]->accept(*this); + res = symbol->get_element(i)->accept(*this); if (res != NULL) return res; } @@ -599,7 +599,7 @@ class generate_c_structure_initialization_c: public generate_c_base_and_typeid_c s4o.print("("); print_variable_prefix(); s4o.print(","); - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); s4o.print(",,temp);\n"); } return NULL; @@ -836,6 +836,7 @@ class generate_c_vardecl_c: protected generate_c_base_and_typeid_c { * c = 99.9; * * constructorinit_vf: initialising of member variables... + * TODO: FIX THIS COMMENT!!! It is wrong!!! * e.g. for a constructor... * class_name_c(void) * : a(9), b(99), c(99.9) { // code... } @@ -860,7 +861,8 @@ class generate_c_vardecl_c: protected generate_c_base_and_typeid_c { init_vf, constructorinit_vf, globalinit_vf, - globalprototype_vf + globalprototype_vf, + location_list_vf } varformat_t; @@ -957,6 +959,44 @@ class generate_c_vardecl_c: protected generate_c_base_and_typeid_c { return NULL; } + /* helper function for declare_variables(). + * Only called from one place! + * + * If we were to follow the visitor pattern, the following code should really be placed inside the + * method visit(structure_element_initialization_list_c *), but would be conditionally executed in + * a specific state/situation (which would need to be indicated through flags -> yuck). + * Instead of adding the code there inside an if() statement, I (msousa) prefered to keep it separate. + * + * To be honest I consider this a quick hack. + * The time is approaching for when this class will need a general clean up. + */ + void print_fb_explicit_initial_values(symbol_c *fbvar_name, symbol_c *init_values_list) { + structure_element_initialization_list_c *init_list = dynamic_cast(init_values_list); + if (NULL == init_list) ERROR; + + for (int i = 0; i < init_list->n; i++) { + structure_element_initialization_c *init_list_elem = dynamic_cast(init_list->get_element(i)); + if (NULL == init_list_elem) ERROR; + if (!get_datatype_info_c::is_ANY_ELEMENTARY(init_list_elem->value->datatype)) { + STAGE4_ERROR(init_list_elem, init_list_elem, + "C code generation does not yet support initializing FB/structures with non-elementary values."); + ERROR; + } + s4o.print("\n"); + s4o.print(s4o.indent_spaces); + s4o.print(INIT_VAR); + s4o.print("("); + this->print_variable_prefix(); + fbvar_name->accept(*this); + s4o.print("."); + init_list_elem->structure_element_name->accept(*this); + s4o.print(","); + init_list_elem->value->accept(*this); + print_retain(); + s4o.print(")"); + } + }; + /* Actually produce the output where variables are declared... */ /* Note that located variables and EN/ENO are the exception, they * being declared in the located_var_decl_c, @@ -996,20 +1036,20 @@ class generate_c_vardecl_c: protected generate_c_base_and_typeid_c { print_variable_prefix(); s4o.print(","); } - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); if (wanted_varformat != local_vf) { if (wanted_varformat == localinit_vf && (current_vartype & inoutput_vt) != 0) { s4o.print(";\n"); s4o.print(s4o.indent_spaces); s4o.print("if (__"); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); s4o.print(" != NULL) {\n"); s4o.indent_right(); s4o.print(s4o.indent_spaces); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); s4o.print(" = *__"); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); s4o.print(";\n"); s4o.indent_left(); s4o.print(s4o.indent_spaces); @@ -1024,7 +1064,7 @@ class generate_c_vardecl_c: protected generate_c_base_and_typeid_c { this->current_var_init_symbol->accept(*this); s4o.print(";\n"); s4o.print(s4o.indent_spaces); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); s4o.print(" = temp;\n"); s4o.indent_left(); s4o.print(s4o.indent_spaces); @@ -1060,7 +1100,7 @@ class generate_c_vardecl_c: protected generate_c_base_and_typeid_c { s4o.print(" *__"); else s4o.print(" "); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); /* We do not print the initial value at function declaration! * It is up to the caller to pass the correct default value * if none is specified in the ST source code @@ -1075,13 +1115,13 @@ class generate_c_vardecl_c: protected generate_c_base_and_typeid_c { for(int i = 0; i < list->n; i++) { if ((current_vartype & (output_vt | inoutput_vt)) != 0) { s4o.print(s4o.indent_spaces + "if (__"); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); s4o.print(" != NULL) {\n"); s4o.indent_right(); s4o.print(s4o.indent_spaces + "*__"); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); s4o.print(" = "); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); s4o.print(";\n"); s4o.indent_left(); s4o.print(s4o.indent_spaces + "}\n"); @@ -1092,21 +1132,41 @@ class generate_c_vardecl_c: protected generate_c_base_and_typeid_c { if (wanted_varformat == constructorinit_vf) { for(int i = 0; i < list->n; i++) { if (is_fb) { + /* If we are declaring and/or initializing a FB instance, then we + * simply call the FBNAME_init__() function, which will initialise the + * FB instance with the default values of this FB type. + * For a FB instance declared as: + * VAR my_fb : FB_typ; END_VAR + * The generated C code will look something like: + * FB_TYP_init__(&data__->MY_FB,retain); + */ s4o.print(nv->get()); this->current_var_type_symbol->accept(*this); s4o.print(FB_INIT_SUFFIX); s4o.print("(&"); this->print_variable_prefix(); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); print_retain(); s4o.print(");"); + if (this->current_var_init_symbol != NULL) { + /* This FB instance declaration includes an explicit initialiser list + * e.g. VAR my_fb : FB_typ := (var1 := 42, var2 := 'hello'); END_VAR + * -------------------------------- + * To handle this, we insert some extra code to set each of the initialised + * FB variables one by one... + * The generated C code will lokk something like: + * __INIT_VAR(data__->my_fb.var1, __INT_LITERAL(42), retain); + * __INIT_VAR(data__->my_fb.var1, __STRING_LITERAL("hello"), retain); + */ + print_fb_explicit_initial_values(list->get_element(i), this->current_var_init_symbol); + } } else if (this->current_var_init_symbol != NULL) { s4o.print(nv->get()); s4o.print(INIT_VAR); s4o.print("("); this->print_variable_prefix(); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); s4o.print(","); this->current_var_init_symbol->accept(*this); print_retain(); @@ -1256,11 +1316,6 @@ void *visit(non_retain_option_c *symbol) { void *visit(input_declarations_c *symbol) { TRACE("input_declarations_c"); if ((wanted_vartype & input_vt) != 0) { -/* - // TO DO ... - if (symbol->option != NULL) - symbol->option->accept(*this); -*/ //s4o.indent_right(); current_vartype = input_vt; if (symbol->option != NULL) @@ -1331,7 +1386,6 @@ void *visit(en_param_declaration_c *symbol) { } if (wanted_varformat == constructorinit_vf) { - /* NOTE: I (Mario) think this is dead code - never gets executed. Must confirm it before deleting it... */ s4o.print(nv->get()); s4o.print(INIT_VAR); s4o.print("("); @@ -1401,7 +1455,6 @@ void *visit(eno_param_declaration_c *symbol) { } if (wanted_varformat == constructorinit_vf) { - /* NOTE: I (Mario) think this is dead code - never gets executed. Must confirm it before deleting it... */ s4o.print(nv->get()); s4o.print(INIT_VAR); s4o.print("("); @@ -1713,6 +1766,31 @@ void *visit(located_var_decl_list_c *symbol) { return NULL; } +/********************************************/ +/* B.1.4.1 Directly Represented Variables */ +/********************************************/ + +void *visit(direct_variable_c *symbol) { + if(wanted_varformat == location_list_vf){ + s4o.printlocation((symbol->value)+1); + s4o.print(","); + s4o.printlocation_comasep((symbol->value)+1); + } else { + // explicit call to base class method + return generate_c_base_c::visit(symbol); + } + return NULL; +} + + +#define print_located_var_list_item \ + s4o.print("__LOCATED_VAR("); \ + this->current_var_type_symbol->accept(*this); \ + s4o.print(","); \ + symbol->location->accept(*this); \ + s4o.print(")\n"); + + /* [variable_name] location ':' located_var_spec_init */ /* variable_name -> may be NULL ! */ @@ -1759,6 +1837,20 @@ void *visit(located_var_decl_c *symbol) { print_retain(); s4o.print(")\n"); if (this->current_var_init_symbol != NULL) { + int is_struct = get_datatype_info_c::is_structure(this->current_var_type_symbol); + if(is_struct){ + s4o.print("\n"); + s4o.print(s4o.indent_spaces + "{\n"); + s4o.indent_right(); + s4o.print(s4o.indent_spaces); + s4o.print("static const "); + + this->current_var_type_symbol->accept(*this); + + s4o.print(" temp = "); + this->current_var_init_symbol->accept(*this); + s4o.print(";\n"); + } s4o.print(s4o.indent_spaces); s4o.print(INIT_LOCATED_VALUE); s4o.print("("); @@ -1768,8 +1860,17 @@ void *visit(located_var_decl_c *symbol) { else symbol->location->accept(*this); s4o.print(","); - this->current_var_init_symbol->accept(*this); + if(is_struct){ + s4o.print(" temp"); + }else{ + this->current_var_init_symbol->accept(*this); + } s4o.print(")"); + if(is_struct){ + s4o.print(";\n"); + s4o.indent_left(); + s4o.print(s4o.indent_spaces + "}"); + } } break; @@ -1804,6 +1905,11 @@ void *visit(located_var_decl_c *symbol) { s4o.print(");\n"); break; + case location_list_vf: + // use macro to avoid code duplication with visit(global_var_spec_c *symbol) + print_located_var_list_item + break; + default: ERROR; } /* switch() */ @@ -2067,6 +2173,10 @@ void *visit(global_var_spec_c *symbol) { s4o.print(")\n"); break; + case location_list_vf: + print_located_var_list_item + break; + default: ERROR; } /* switch() */ @@ -2110,7 +2220,7 @@ void *visit(global_var_list_c *symbol) { if(this->resource_name != NULL) this->resource_name->accept(*this); s4o.print(","); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); s4o.print(")\n"); } break; @@ -2127,7 +2237,7 @@ void *visit(global_var_list_c *symbol) { s4o.print("("); this->current_var_type_symbol->accept(*this); s4o.print(","); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); if (this->current_var_init_symbol != NULL) { s4o.print(","); s4o.print(INITIAL_VALUE); @@ -2137,6 +2247,7 @@ void *visit(global_var_list_c *symbol) { } print_retain(); s4o.print(")"); + current_varqualifier = none_vq; #if 0 /* The following code would be for globalinit_vf !! * But it is not currently required... @@ -2148,7 +2259,7 @@ void *visit(global_var_list_c *symbol) { this->globalnamespace->accept(*this); s4o.print("::"); } - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); if (this->current_var_init_symbol != NULL) { s4o.print(" = "); @@ -2171,11 +2282,14 @@ void *visit(global_var_list_c *symbol) { s4o.print("("); this->current_var_type_symbol->accept(*this); s4o.print(","); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); s4o.print(")\n"); } break; + case location_list_vf: + break; + default: ERROR; /* not supported, and not needed either... */ } diff --git a/utils/matiec_src/stage4/generate_c/generate_location_list.cc b/utils/matiec_src/stage4/generate_c/generate_location_list.cc old mode 100755 new mode 100644 index c13cdbc..ef6c1ca --- a/utils/matiec_src/stage4/generate_c/generate_location_list.cc +++ b/utils/matiec_src/stage4/generate_c/generate_location_list.cc @@ -26,78 +26,17 @@ class generate_location_list_c: public iterator_visitor_c { protected: stage4out_c &s4o; + generate_c_vardecl_c generate_c_vardecl; - private: - symbol_c *current_var_type_symbol; - generate_c_base_c *generate_c_base; - public: - generate_location_list_c(stage4out_c *s4o_ptr): s4o(*s4o_ptr) { - generate_c_base = new generate_c_base_c(s4o_ptr); - current_var_type_symbol = NULL; + generate_location_list_c(stage4out_c *s4o_ptr): + s4o(*s4o_ptr), + generate_c_vardecl(s4o_ptr, + generate_c_vardecl_c::location_list_vf, + generate_c_vardecl_c::global_vt) { } + ~generate_location_list_c(void) { - delete generate_c_base; - } - - bool test_location_type(symbol_c *direct_variable) { - - token_c *location = dynamic_cast(direct_variable); - - if (location == NULL) - /* invalid identifiers... */ - return false; - - switch (location->value[2]) { - case 'X': // bit - if (typeid(*current_var_type_symbol) == typeid(bool_type_name_c)) return true; - break; - case 'B': // Byte, 8 bits - if (typeid(*current_var_type_symbol) == typeid(sint_type_name_c)) return true; - if (typeid(*current_var_type_symbol) == typeid(usint_type_name_c)) return true; - if (typeid(*current_var_type_symbol) == typeid(string_type_name_c)) return true; - if (typeid(*current_var_type_symbol) == typeid(byte_type_name_c)) return true; - break; - case 'W': // Word, 16 bits - if (typeid(*current_var_type_symbol) == typeid(int_type_name_c)) return true; - if (typeid(*current_var_type_symbol) == typeid(uint_type_name_c)) return true; - if (typeid(*current_var_type_symbol) == typeid(word_type_name_c)) return true; - if (typeid(*current_var_type_symbol) == typeid(wstring_type_name_c)) return true; - break; - case 'D': // Double, 32 bits - if (typeid(*current_var_type_symbol) == typeid(dint_type_name_c)) return true; - if (typeid(*current_var_type_symbol) == typeid(udint_type_name_c)) return true; - if (typeid(*current_var_type_symbol) == typeid(real_type_name_c)) return true; - if (typeid(*current_var_type_symbol) == typeid(dword_type_name_c)) return true; - break; - case 'L': // Long, 64 bits - if (typeid(*current_var_type_symbol) == typeid(lint_type_name_c)) return true; - if (typeid(*current_var_type_symbol) == typeid(ulint_type_name_c)) return true; - if (typeid(*current_var_type_symbol) == typeid(lreal_type_name_c)) return true; - if (typeid(*current_var_type_symbol) == typeid(lword_type_name_c)) return true; - break; - default: - if (typeid(*current_var_type_symbol) == typeid(bool_type_name_c)) return true; - } - return false; - } - -/********************************************/ -/* B.1.4.1 Directly Represented Variables */ -/********************************************/ - - void *visit(direct_variable_c *symbol) { - if (current_var_type_symbol) { - s4o.print("__LOCATED_VAR("); - current_var_type_symbol->accept(*generate_c_base); - s4o.print(","); - /* Do not use print_token() as it will change everything into uppercase */ - s4o.printlocation((symbol->value)+1); - s4o.print(","); - s4o.printlocation_comasep((symbol->value)+1); - s4o.print(")\n"); - } - return NULL; } @@ -109,17 +48,9 @@ class generate_location_list_c: public iterator_visitor_c { /* variable_name -> may be NULL ! */ //SYM_REF4(located_var_decl_c, variable_name, location, located_var_spec_init, unused) void *visit(located_var_decl_c *symbol) { - current_var_type_symbol = spec_init_sperator_c::get_spec(symbol->located_var_spec_init); - if (current_var_type_symbol == NULL) - ERROR; - - current_var_type_symbol = search_base_type_c::get_basetype_decl(current_var_type_symbol); - if (current_var_type_symbol == NULL) - ERROR; - - symbol->location->accept(*this); - - current_var_type_symbol = NULL; + + generate_c_vardecl.print(symbol); + return NULL; } @@ -127,28 +58,10 @@ class generate_location_list_c: public iterator_visitor_c { /* type_specification ->may be NULL ! */ //SYM_REF2(global_var_decl_c, global_var_spec, type_specification) void *visit(global_var_decl_c *symbol) { - current_var_type_symbol = spec_init_sperator_c::get_spec(symbol->type_specification); - if (current_var_type_symbol == NULL) - ERROR; - - current_var_type_symbol = search_base_type_c::get_basetype_decl(current_var_type_symbol); - if (current_var_type_symbol == NULL) - ERROR; - - symbol->global_var_spec->accept(*this); - - current_var_type_symbol = NULL; + + generate_c_vardecl.print(symbol); + return NULL; } -/* AT direct_variable */ -//SYM_REF2(location_c, direct_variable, unused) - void *visit(location_c *symbol) { - if (test_location_type(symbol->direct_variable)) - symbol->direct_variable->accept(*this); - else - ERROR; - return NULL; - } - }; /* generate_location_list_c */ diff --git a/utils/matiec_src/stage4/generate_c/generate_var_list.cc b/utils/matiec_src/stage4/generate_c/generate_var_list.cc old mode 100755 new mode 100644 index e2443a9..aa9242e --- a/utils/matiec_src/stage4/generate_c/generate_var_list.cc +++ b/utils/matiec_src/stage4/generate_c/generate_var_list.cc @@ -238,7 +238,8 @@ class generate_var_list_c: protected generate_c_base_and_typeid_c { bool configuration_defined; std::list current_symbol_list; search_type_symbol_c *search_type_symbol; - + unsigned int is_retain; + public: generate_var_list_c(stage4out_c *s4o_ptr, symbol_c *scope) : generate_c_base_and_typeid_c(s4o_ptr) { @@ -248,6 +249,7 @@ class generate_var_list_c: protected generate_c_base_and_typeid_c { current_var_type_name = NULL; current_declarationtype = none_dt; current_var_class_category = none_vcc; + is_retain = 0; } ~generate_var_list_c(void) { @@ -289,7 +291,7 @@ class generate_var_list_c: protected generate_c_base_and_typeid_c { if (list == NULL) ERROR; for(int i = 0; i < list->n; i++) { - declare_variable(list->elements[i]); + declare_variable(list->get_element(i)); } } @@ -345,6 +347,8 @@ class generate_var_list_c: protected generate_c_base_and_typeid_c { case search_type_symbol_c::structure_vtc: case search_type_symbol_c::function_block_vtc: this->current_var_type_name->accept(*this); + s4o.print(";;"); + print_retain(); s4o.print(";\n"); if (this->current_var_class_category != external_vcc) { SYMBOL *current_name; @@ -360,14 +364,28 @@ class generate_var_list_c: protected generate_c_base_and_typeid_c { break; case search_type_symbol_c::array_vtc: this->current_var_type_name->accept(*this); + s4o.print(";;"); + print_retain(); s4o.print(";\n"); break; default: + // base type name this->current_var_type_symbol->accept(*this); + s4o.print(";"); + // type name (eventualy derived) + this->current_var_type_name->accept(*this); + s4o.print(";"); + print_retain(); s4o.print(";\n"); break; } } + void print_retain() { + if(is_retain) + s4o.print("1"); + else + s4o.print("0"); + } void print_var_number(void) { char str[10]; @@ -440,6 +458,55 @@ class generate_var_list_c: protected generate_c_base_and_typeid_c { /* B.1.4.3 - Declaration and initialization */ /********************************************/ + void *visit(retain_option_c *symbol) { + is_retain = 1; + return NULL; + } + + void *visit(non_retain_option_c *symbol) { + is_retain = 0; + return NULL; + } + + /* VAR_OUTPUT [RETAIN | NON_RETAIN] var_init_decl_list END_VAR */ + void *visit(output_declarations_c *symbol) { + unsigned int was_retain = is_retain; + if (symbol->option != NULL) + symbol->option->accept(*this); + symbol->var_init_decl_list->accept(*this); + is_retain = was_retain; + return NULL; + } + + /* VAR RETAIN var_init_decl_list END_VAR */ + void *visit(retentive_var_declarations_c *symbol) { + unsigned int was_retain = is_retain; + is_retain = 1; + symbol->var_init_decl_list->accept(*this); + is_retain = was_retain; + return NULL; + } + + /* VAR [CONSTANT|RETAIN|NON_RETAIN] located_var_decl_list END_VAR */ + void *visit(located_var_declarations_c *symbol) { + unsigned int was_retain = is_retain; + if (symbol->option != NULL) + symbol->option->accept(*this); + symbol->located_var_decl_list->accept(*this); + is_retain = was_retain; + return NULL; + } + + /* VAR_GLOBAL [CONSTANT|RETAIN] global_var_decl_list END_VAR */ + void *visit(global_var_declarations_c *symbol) { + unsigned int was_retain = is_retain; + if (symbol->option != NULL) + symbol->option->accept(*this); + symbol->global_var_decl_list->accept(*this); + is_retain = was_retain; + return NULL; + } + /* [variable_name] location ':' located_var_spec_init */ /* variable_name -> may be NULL ! */ //SYM_REF4(located_var_decl_c, variable_name, location, located_var_spec_init, unused) @@ -793,7 +860,7 @@ class generate_var_list_c: protected generate_c_base_and_typeid_c { void *visit(structure_element_declaration_list_c *symbol) { for(int i = 0; i < symbol->n; i++) { - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); } return NULL; } @@ -860,7 +927,7 @@ class generate_var_list_c: protected generate_c_base_and_typeid_c { transition_number = 0; action_number = 0; for(int i = 0; i < symbol->n; i++) { - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); } return NULL; } @@ -876,7 +943,7 @@ class generate_var_list_c: protected generate_c_base_and_typeid_c { print_symbol_list(); s4o.print("__step_list["); print_step_number(); - s4o.print("].X;BOOL;\n"); + s4o.print("].X;BOOL;BOOL;\n"); step_number++; return NULL; } @@ -892,7 +959,7 @@ class generate_var_list_c: protected generate_c_base_and_typeid_c { print_symbol_list(); s4o.print("__step_list["); print_step_number(); - s4o.print("].X;BOOL;\n"); + s4o.print("].X;BOOL;BOOL;\n"); step_number++; return NULL; } @@ -916,7 +983,7 @@ class generate_var_list_c: protected generate_c_base_and_typeid_c { print_symbol_list(); s4o.print("__debug_transition_list["); print_transition_number(); - s4o.print("];BOOL;\n"); + s4o.print("];BOOL;BOOL;\n"); transition_number++; return NULL; } @@ -937,7 +1004,7 @@ class generate_var_list_c: protected generate_c_base_and_typeid_c { //SYM_LIST(step_name_list_c) void *visit(step_name_list_c *symbol) { for(int i = 0; i < symbol->n; i++) { - symbol->elements[i]->accept(*this); + symbol->get_element(i)->accept(*this); if (i < symbol->n - 1) s4o.print(","); } @@ -955,7 +1022,7 @@ class generate_var_list_c: protected generate_c_base_and_typeid_c { print_symbol_list(); s4o.print("__action_list["); print_action_number(); - s4o.print("].state;BOOL;\n"); + s4o.print("].state;BOOL;BOOL;\n"); action_number++; return NULL; } diff --git a/utils/matiec_src/stage4/generate_iec/generate_iec.cc b/utils/matiec_src/stage4/generate_iec/generate_iec.cc index ae0c156..f6422d1 100644 --- a/utils/matiec_src/stage4/generate_iec/generate_iec.cc +++ b/utils/matiec_src/stage4/generate_iec/generate_iec.cc @@ -164,12 +164,12 @@ void *print_list(list_c *list, std::string post_elem_str = "") { if (list->n > 0) { s4o.print(pre_elem_str); - list->elements[0]->accept(*this); + list->get_element(0)->accept(*this); } for(int i = 1; i < list->n; i++) { s4o.print(inter_elem_str); - list->elements[i]->accept(*this); + list->get_element(i)->accept(*this); } if (list->n > 0) @@ -392,48 +392,50 @@ void *visit(date_and_time_c *symbol) { /***********************************/ /* B 1.3.1 - Elementary Data Types */ /***********************************/ -void *visit(time_type_name_c *symbol) {s4o.print("TIME"); return NULL;} -void *visit(bool_type_name_c *symbol) {s4o.print("BOOL"); return NULL;} -void *visit(sint_type_name_c *symbol) {s4o.print("SINT"); return NULL;} -void *visit(int_type_name_c *symbol) {s4o.print("INT"); return NULL;} -void *visit(dint_type_name_c *symbol) {s4o.print("DINT"); return NULL;} -void *visit(lint_type_name_c *symbol) {s4o.print("LINT"); return NULL;} -void *visit(usint_type_name_c *symbol) {s4o.print("USINT"); return NULL;} -void *visit(uint_type_name_c *symbol) {s4o.print("UINT"); return NULL;} -void *visit(udint_type_name_c *symbol) {s4o.print("UDINT"); return NULL;} -void *visit(ulint_type_name_c *symbol) {s4o.print("ULINT"); return NULL;} -void *visit(real_type_name_c *symbol) {s4o.print("REAL"); return NULL;} -void *visit(lreal_type_name_c *symbol) {s4o.print("LREAL"); return NULL;} -void *visit(date_type_name_c *symbol) {s4o.print("DATE"); return NULL;} -void *visit(tod_type_name_c *symbol) {s4o.print("TOD"); return NULL;} -void *visit(dt_type_name_c *symbol) {s4o.print("DT"); return NULL;} -void *visit(byte_type_name_c *symbol) {s4o.print("BYTE"); return NULL;} -void *visit(word_type_name_c *symbol) {s4o.print("WORD"); return NULL;} -void *visit(lword_type_name_c *symbol) {s4o.print("LWORD"); return NULL;} -void *visit(dword_type_name_c *symbol) {s4o.print("DWORD"); return NULL;} -void *visit(string_type_name_c *symbol) {s4o.print("STRING"); return NULL;} -void *visit(wstring_type_name_c *symbol) {s4o.print("WSTRING"); return NULL;} +void *visit( time_type_name_c *symbol) {s4o.print("TIME"); return NULL;} +void *visit( bool_type_name_c *symbol) {s4o.print("BOOL"); return NULL;} +void *visit( sint_type_name_c *symbol) {s4o.print("SINT"); return NULL;} +void *visit( int_type_name_c *symbol) {s4o.print("INT"); return NULL;} +void *visit( dint_type_name_c *symbol) {s4o.print("DINT"); return NULL;} +void *visit( lint_type_name_c *symbol) {s4o.print("LINT"); return NULL;} +void *visit( usint_type_name_c *symbol) {s4o.print("USINT"); return NULL;} +void *visit( uint_type_name_c *symbol) {s4o.print("UINT"); return NULL;} +void *visit( udint_type_name_c *symbol) {s4o.print("UDINT"); return NULL;} +void *visit( ulint_type_name_c *symbol) {s4o.print("ULINT"); return NULL;} +void *visit( real_type_name_c *symbol) {s4o.print("REAL"); return NULL;} +void *visit( lreal_type_name_c *symbol) {s4o.print("LREAL"); return NULL;} +void *visit( date_type_name_c *symbol) {s4o.print("DATE"); return NULL;} +void *visit( tod_type_name_c *symbol) {s4o.print("TOD"); return NULL;} +void *visit( dt_type_name_c *symbol) {s4o.print("DT"); return NULL;} +void *visit( byte_type_name_c *symbol) {s4o.print("BYTE"); return NULL;} +void *visit( word_type_name_c *symbol) {s4o.print("WORD"); return NULL;} +void *visit( lword_type_name_c *symbol) {s4o.print("LWORD"); return NULL;} +void *visit( dword_type_name_c *symbol) {s4o.print("DWORD"); return NULL;} +void *visit( string_type_name_c *symbol) {s4o.print("STRING"); return NULL;} +void *visit( wstring_type_name_c *symbol) {s4o.print("WSTRING"); return NULL;} -void *visit(safetime_type_name_c *symbol) {s4o.print("SAFETIME"); return NULL;} -void *visit(safebool_type_name_c *symbol) {s4o.print("SAFEBOOL"); return NULL;} -void *visit(safesint_type_name_c *symbol) {s4o.print("SAFESINT"); return NULL;} -void *visit(safeint_type_name_c *symbol) {s4o.print("SAFEINT"); return NULL;} -void *visit(safedint_type_name_c *symbol) {s4o.print("SAFEDINT"); return NULL;} -void *visit(safelint_type_name_c *symbol) {s4o.print("SAFELINT"); return NULL;} -void *visit(safeusint_type_name_c *symbol) {s4o.print("SAFEUSINT"); return NULL;} -void *visit(safeuint_type_name_c *symbol) {s4o.print("SAFEUINT"); return NULL;} -void *visit(safeudint_type_name_c *symbol) {s4o.print("SAFEUDINT"); return NULL;} -void *visit(safeulint_type_name_c *symbol) {s4o.print("SAFEULINT"); return NULL;} -void *visit(safereal_type_name_c *symbol) {s4o.print("SAFEREAL"); return NULL;} -void *visit(safelreal_type_name_c *symbol) {s4o.print("SAFELREAL"); return NULL;} -void *visit(safedate_type_name_c *symbol) {s4o.print("SAFEDATE"); return NULL;} -void *visit(safetod_type_name_c *symbol) {s4o.print("SAFETOD"); return NULL;} -void *visit(safedt_type_name_c *symbol) {s4o.print("SAFEDT"); return NULL;} -void *visit(safebyte_type_name_c *symbol) {s4o.print("SAFEBYTE"); return NULL;} -void *visit(safeword_type_name_c *symbol) {s4o.print("SAFEWORD"); return NULL;} -void *visit(safelword_type_name_c *symbol) {s4o.print("SAFELWORD"); return NULL;} -void *visit(safedword_type_name_c *symbol) {s4o.print("SAFEDWORD"); return NULL;} -void *visit(safestring_type_name_c *symbol) {s4o.print("SAFESTRING"); return NULL;} +void *visit( void_type_name_c *symbol) {s4o.print("VOID"); return NULL;} /* a non-standard extension! */ + +void *visit( safetime_type_name_c *symbol) {s4o.print("SAFETIME"); return NULL;} +void *visit( safebool_type_name_c *symbol) {s4o.print("SAFEBOOL"); return NULL;} +void *visit( safesint_type_name_c *symbol) {s4o.print("SAFESINT"); return NULL;} +void *visit( safeint_type_name_c *symbol) {s4o.print("SAFEINT"); return NULL;} +void *visit( safedint_type_name_c *symbol) {s4o.print("SAFEDINT"); return NULL;} +void *visit( safelint_type_name_c *symbol) {s4o.print("SAFELINT"); return NULL;} +void *visit( safeusint_type_name_c *symbol) {s4o.print("SAFEUSINT"); return NULL;} +void *visit( safeuint_type_name_c *symbol) {s4o.print("SAFEUINT"); return NULL;} +void *visit( safeudint_type_name_c *symbol) {s4o.print("SAFEUDINT"); return NULL;} +void *visit( safeulint_type_name_c *symbol) {s4o.print("SAFEULINT"); return NULL;} +void *visit( safereal_type_name_c *symbol) {s4o.print("SAFEREAL"); return NULL;} +void *visit( safelreal_type_name_c *symbol) {s4o.print("SAFELREAL"); return NULL;} +void *visit( safedate_type_name_c *symbol) {s4o.print("SAFEDATE"); return NULL;} +void *visit( safetod_type_name_c *symbol) {s4o.print("SAFETOD"); return NULL;} +void *visit( safedt_type_name_c *symbol) {s4o.print("SAFEDT"); return NULL;} +void *visit( safebyte_type_name_c *symbol) {s4o.print("SAFEBYTE"); return NULL;} +void *visit( safeword_type_name_c *symbol) {s4o.print("SAFEWORD"); return NULL;} +void *visit( safelword_type_name_c *symbol) {s4o.print("SAFELWORD"); return NULL;} +void *visit( safedword_type_name_c *symbol) {s4o.print("SAFEDWORD"); return NULL;} +void *visit( safestring_type_name_c *symbol) {s4o.print("SAFESTRING"); return NULL;} void *visit(safewstring_type_name_c *symbol) {s4o.print("SAFEWSTRING"); return NULL;} /********************************/ @@ -2144,6 +2146,10 @@ void *visit(exit_statement_c *symbol) { return NULL; } +void *visit(continue_statement_c *symbol) { + s4o.print("CONTINUE"); + return NULL; +} }; /* class generate_iec_c */ diff --git a/utils/matiec_src/stage4/generate_iec/generate_iec.hh b/utils/matiec_src/stage4/generate_iec/generate_iec.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/stage4/stage4.cc b/utils/matiec_src/stage4/stage4.cc index 12063fb..df99fe7 100644 --- a/utils/matiec_src/stage4/stage4.cc +++ b/utils/matiec_src/stage4/stage4.cc @@ -186,9 +186,24 @@ void *stage4out_c::printlocation_comasep(const char *str) { if (!allow_output) return NULL; *out << (unsigned char)toupper(str[0]); *out << ','; - *out << (unsigned char)toupper(str[1]); - *out << ','; - for (int i = 2; str[i] != '\0'; i++) + int i = 1; + unsigned char size_char = (unsigned char)toupper(str[1]); + switch (size_char) { + case 'X': // bit + case 'B': // Byte, 8 bits + case 'W': // Word, 16 bits + case 'D': // Double, 32 bits + case 'L': // Long, 64 bits + *out << size_char; + i = 2; + break; + default: + // S for struct, etc. (todo: support arrays and others) + *out << "S"; + break; + } + *out << ','; + for (; str[i] != '\0'; i++) if(str[i] == '.') *out << ','; else diff --git a/utils/matiec_src/stage4/stage4.hh b/utils/matiec_src/stage4/stage4.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/util/dsymtable.cc b/utils/matiec_src/util/dsymtable.cc old mode 100755 new mode 100644 diff --git a/utils/matiec_src/util/dsymtable.hh b/utils/matiec_src/util/dsymtable.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/util/strdup.hh b/utils/matiec_src/util/strdup.hh old mode 100755 new mode 100644 diff --git a/utils/matiec_src/util/symtable.cc b/utils/matiec_src/util/symtable.cc old mode 100755 new mode 100644 diff --git a/utils/matiec_src/util/symtable.hh b/utils/matiec_src/util/symtable.hh old mode 100755 new mode 100644