etisserant@0: /* msousa@261: * matiec - a compiler for the programming languages defined in IEC 61131-3 msousa@261: * Copyright (C) 2003-2011 Mario de Sousa (msousa@fe.up.pt) Edouard@279: * Copyright (C) 2007-2011 Laurent Bessard and Edouard Tisserant msousa@261: * msousa@261: * This program is free software: you can redistribute it and/or modify msousa@261: * it under the terms of the GNU General Public License as published by msousa@261: * the Free Software Foundation, either version 3 of the License, or msousa@261: * (at your option) any later version. msousa@261: * msousa@261: * This program is distributed in the hope that it will be useful, msousa@261: * but WITHOUT ANY WARRANTY; without even the implied warranty of msousa@261: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the msousa@261: * GNU General Public License for more details. msousa@261: * msousa@261: * You should have received a copy of the GNU General Public License msousa@261: * along with this program. If not, see . msousa@261: * etisserant@0: * etisserant@0: * This code is made available on the understanding that it will not be etisserant@0: * used in safety-critical situations without a full and competent review. etisserant@0: */ etisserant@0: etisserant@0: /* msousa@261: * An IEC 61131-3 compiler. etisserant@0: * etisserant@0: * Based on the etisserant@0: * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) etisserant@0: * etisserant@0: */ etisserant@0: etisserant@0: /* etisserant@0: * Definition of the Abstract Syntax data structure components etisserant@0: */ etisserant@0: etisserant@0: #include etisserant@0: #include /* required for exit() */ etisserant@0: #include etisserant@0: etisserant@0: #include "absyntax.hh" etisserant@0: //#include "../stage1_2/iec.hh" /* required for BOGUS_TOKEN_ID, etc... */ etisserant@0: #include "visitor.hh" msousa@596: #include "../main.hh" // required for ERROR() and ERROR_MSG() macros. etisserant@0: etisserant@0: etisserant@0: mjsousa@965: etisserant@0: /* The base class of all symbols */ msousa@286: symbol_c::symbol_c( msousa@287: int first_line, int first_column, const char *ffile, long int first_order, msousa@287: int last_line, int last_column, const char *lfile, long int last_order ) { msousa@286: this->first_file = ffile, mario@69: this->first_line = first_line; mario@69: this->first_column = first_column; msousa@287: this->first_order = first_order; msousa@286: this->last_file = lfile, mario@69: this->last_line = last_line; mario@69: this->last_column = last_column; msousa@287: this->last_order = last_order; mjsousa@936: this->parent = NULL; msousa@1043: this->token = NULL; msousa@417: this->datatype = NULL; mjsousa@889: this->scope = NULL; mario@69: } mario@69: mario@69: mario@69: msousa@286: token_c::token_c(const char *value, msousa@287: int fl, int fc, const char *ffile, long int forder, msousa@287: int ll, int lc, const char *lfile, long int lorder) msousa@287: :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { etisserant@0: this->value = value; msousa@1043: this->token = this; // every token is its own reference token. etisserant@0: // printf("New token: %s\n", value); etisserant@0: } etisserant@0: etisserant@0: etisserant@0: etisserant@0: agraeper@654: # define LIST_CAP_INIT 8 agraeper@654: # define LIST_CAP_INCR 8 etisserant@0: msousa@286: list_c::list_c( msousa@287: int fl, int fc, const char *ffile, long int forder, msousa@287: int ll, int lc, const char *lfile, long int lorder) msousa@655: :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder),c(LIST_CAP_INIT) { msousa@655: n = 0; msousa@1043: elements = (element_entry_t*)malloc(LIST_CAP_INIT*sizeof(element_entry_t)); msousa@655: if (NULL == elements) ERROR_MSG("out of memory"); msousa@655: } msousa@655: etisserant@0: msousa@286: list_c::list_c(symbol_c *elem, msousa@287: int fl, int fc, const char *ffile, long int forder, msousa@287: int ll, int lc, const char *lfile, long int lorder) msousa@655: :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder),c(LIST_CAP_INIT) { msousa@655: n = 0; msousa@1043: elements = (element_entry_t*)malloc(LIST_CAP_INIT*sizeof(element_entry_t)); msousa@655: if (NULL == elements) ERROR_MSG("out of memory"); msousa@655: add_element(elem); msousa@655: } msousa@655: etisserant@0: msousa@1043: /*******************************************/ msousa@1041: /* get element in position pos of the list */ msousa@1043: /*******************************************/ msousa@1043: symbol_c *list_c::get_element(int pos) {return elements[pos].symbol;} msousa@1043: msousa@1043: msousa@1043: msousa@1043: /******************************************/ msousa@1043: /* find element associated to token value */ msousa@1043: /******************************************/ msousa@1043: symbol_c *list_c::find_element(symbol_c *token) { msousa@1043: token_c *t = dynamic_cast(token); msousa@1043: if (t == NULL) ERROR; msousa@1043: return find_element((const char *)t->value); msousa@1043: } msousa@1043: msousa@1043: symbol_c *list_c::find_element(const char *token_value) { msousa@1043: // We could use strcasecmp(), but it's best to always use the same msousa@1043: // method of string comparison throughout matiec msousa@1043: nocasecmp_c ncc; msousa@1043: for (int i = 0; i < n; i++) msousa@1043: if (ncc(elements[i].token_value, token_value)) msousa@1043: return elements[i].symbol; msousa@1043: return NULL; // not found msousa@1043: } msousa@1043: msousa@1043: msousa@1043: /***********************************************/ msousa@350: /* append a new element to the end of the list */ msousa@1043: /***********************************************/ msousa@1043: void list_c::add_element(symbol_c *elem) {add_element(elem, elem);} msousa@1043: msousa@1043: void list_c::add_element(symbol_c *elem, symbol_c *token) { msousa@1043: token_c *t = (token == NULL)? NULL : token->token; msousa@1043: add_element(elem, (t == NULL)? NULL : t->value); msousa@1043: } msousa@1043: msousa@1043: void list_c::add_element(symbol_c *elem, const char *token_value) { msousa@655: if (c <= n) msousa@1043: if (!(elements=(element_entry_t*)realloc(elements,(c+=LIST_CAP_INCR)*sizeof(element_entry_t)))) msousa@655: ERROR_MSG("out of memory"); msousa@1043: //elements[n++] = {token_value, elem}; // only available from C++11 onwards, best not use it for now. msousa@1043: elements[n].symbol = elem; msousa@1043: elements[n].token_value = token_value; msousa@1043: n++; msousa@1043: msousa@655: if (NULL == elem) return; mjsousa@936: /* Sometimes add_element() is called in stage3 or stage4 to temporarily add an AST symbol to the list. mjsousa@936: * Since this symbol already belongs in some other place in the aST, it will have the 'parent' pointer set, mjsousa@936: * and so we must not overwrite it. We only set the 'parent' pointer on new symbols that have the 'parent' mjsousa@936: * pointer still set to NULL. mjsousa@936: */ mjsousa@936: if (NULL == elem->parent) elem->parent = this; mario@69: mario@69: /* adjust the location parameters, taking into account the new element. */ msousa@779: if (NULL == first_file) { msousa@779: first_file = elem->first_file; msousa@779: first_line = elem->first_line; msousa@779: first_column = elem->first_column; msousa@779: } msousa@779: if ((first_line == elem->first_line) && (first_column > elem->first_column)) { mario@69: first_column = elem->first_column; mario@69: } mario@69: if (first_line > elem->first_line) { mario@69: first_line = elem->first_line; mario@69: first_column = elem->first_column; mario@69: } msousa@779: if (NULL == last_file) { msousa@779: last_file = elem->last_file; msousa@779: last_line = elem->last_line; msousa@779: last_column = elem->last_column; msousa@779: } mario@69: if ((last_line == elem->last_line) && mario@69: (last_column < elem->last_column)) { mario@69: last_column = elem->last_column; mario@69: } mario@69: if (last_line < elem->last_line) { mario@69: last_line = elem->last_line; mario@69: last_column = elem->last_column; mario@69: } mario@69: } etisserant@0: msousa@1043: msousa@1043: /*********************************************/ msousa@350: /* insert a new element before position pos. */ msousa@1043: /*********************************************/ msousa@350: /* To insert into the begining of list, call with pos=0 */ msousa@350: /* To insert into the end of list, call with pos=list->n */ msousa@1043: msousa@1043: void list_c::insert_element(symbol_c *elem, int pos) {insert_element(elem, elem, pos);} msousa@1043: msousa@1043: void list_c::insert_element(symbol_c *elem, symbol_c *token, int pos) { msousa@1043: token_c *t = (token == NULL)? NULL : token->token; msousa@1043: insert_element(elem, (t == NULL)? NULL : t->value, pos); msousa@1043: } msousa@1043: msousa@1043: void list_c::insert_element(symbol_c *elem, const char *token_value, int pos) { agraeper@654: if((pos<0) || (n=pos ; --i) elements[i+1] = elements[i]; msousa@1043: elements[pos].symbol = elem; msousa@1043: elements[pos].token_value = token_value; msousa@1043: } msousa@1043: } msousa@1043: msousa@1043: msousa@1043: /***********************************/ msousa@438: /* remove element at position pos. */ msousa@1043: /***********************************/ msousa@438: void list_c::remove_element(int pos) { agraeper@654: if((pos<0) || (n<=pos)) ERROR; msousa@438: msousa@438: /* Shift all elements down one position, starting at the entry to delete. */ msousa@438: for (int i = pos; i < n-1; i++) elements[i] = elements[i+1]; agraeper@654: /* corrent the new size */ msousa@438: n--; msousa@1043: /* elements = (symbol_c **)realloc(elements, n * sizeof(element_entry_t)); */ mjsousa@958: /* TODO: adjust the location parameters, taking into account the removed element. */ mjsousa@958: } mjsousa@958: mjsousa@958: msousa@1043: /**********************************/ msousa@1043: /* Remove all elements from list. */ msousa@1043: /**********************************/ mjsousa@958: void list_c::clear(void) { mjsousa@958: n = 0; mjsousa@958: /* TODO: adjust the location parameters, taking into account the removed element. */ mjsousa@958: } mjsousa@958: msousa@350: msousa@350: #define SYM_LIST(class_name_c, ...) \ msousa@286: class_name_c::class_name_c( \ msousa@287: int fl, int fc, const char *ffile, long int forder, \ msousa@287: int ll, int lc, const char *lfile, long int lorder) \ msousa@287: :list_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) {} \ msousa@286: class_name_c::class_name_c(symbol_c *elem, \ msousa@287: int fl, int fc, const char *ffile, long int forder, \ msousa@287: int ll, int lc, const char *lfile, long int lorder) \ msousa@287: :list_c(elem, fl, fc, ffile, forder, ll, lc, lfile, lorder) {} \ msousa@286: void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} msousa@286: msousa@350: #define SYM_TOKEN(class_name_c, ...) \ msousa@286: class_name_c::class_name_c(const char *value, \ msousa@287: int fl, int fc, const char *ffile, long int forder, \ msousa@287: int ll, int lc, const char *lfile, long int lorder) \ msousa@287: :token_c(value, fl, fc, ffile, forder, ll, lc, lfile, lorder) {} \ msousa@286: void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} msousa@286: msousa@350: #define SYM_REF0(class_name_c, ...) \ msousa@286: class_name_c::class_name_c( \ msousa@287: int fl, int fc, const char *ffile, long int forder, \ msousa@287: int ll, int lc, const char *lfile, long int lorder) \ msousa@287: :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) {} \ msousa@286: void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} msousa@286: msousa@286: msousa@350: #define SYM_REF1(class_name_c, ref1, ...) \ msousa@350: class_name_c::class_name_c(symbol_c *ref1, \ msousa@350: int fl, int fc, const char *ffile, long int forder, \ msousa@350: int ll, int lc, const char *lfile, long int lorder) \ msousa@350: :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { \ msousa@350: this->ref1 = ref1; \ mjsousa@936: if (NULL != ref1) ref1->parent = this; \ msousa@350: } \ msousa@350: void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} msousa@350: msousa@350: msousa@350: #define SYM_REF2(class_name_c, ref1, ref2, ...) \ msousa@350: class_name_c::class_name_c(symbol_c *ref1, \ msousa@350: symbol_c *ref2, \ msousa@350: int fl, int fc, const char *ffile, long int forder, \ msousa@350: int ll, int lc, const char *lfile, long int lorder) \ msousa@350: :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { \ msousa@350: this->ref1 = ref1; \ msousa@350: this->ref2 = ref2; \ mjsousa@936: if (NULL != ref1) ref1->parent = this; \ mjsousa@936: if (NULL != ref2) ref2->parent = this; \ msousa@350: } \ msousa@350: void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} msousa@350: msousa@350: msousa@350: #define SYM_REF3(class_name_c, ref1, ref2, ref3, ...) \ msousa@350: class_name_c::class_name_c(symbol_c *ref1, \ msousa@350: symbol_c *ref2, \ msousa@350: symbol_c *ref3, \ msousa@350: int fl, int fc, const char *ffile, long int forder, \ msousa@350: int ll, int lc, const char *lfile, long int lorder) \ msousa@350: :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { \ msousa@350: this->ref1 = ref1; \ msousa@350: this->ref2 = ref2; \ msousa@350: this->ref3 = ref3; \ mjsousa@936: if (NULL != ref1) ref1->parent = this; \ mjsousa@936: if (NULL != ref2) ref2->parent = this; \ mjsousa@936: if (NULL != ref3) ref3->parent = this; \ msousa@350: } \ msousa@350: void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} msousa@350: msousa@350: msousa@350: #define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4, ...) \ msousa@286: class_name_c::class_name_c(symbol_c *ref1, \ msousa@286: symbol_c *ref2, \ msousa@286: symbol_c *ref3, \ msousa@286: symbol_c *ref4, \ msousa@287: int fl, int fc, const char *ffile, long int forder, \ msousa@287: int ll, int lc, const char *lfile, long int lorder) \ msousa@287: :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { \ msousa@286: this->ref1 = ref1; \ msousa@286: this->ref2 = ref2; \ msousa@286: this->ref3 = ref3; \ msousa@286: this->ref4 = ref4; \ mjsousa@936: if (NULL != ref1) ref1->parent = this; \ mjsousa@936: if (NULL != ref2) ref2->parent = this; \ mjsousa@936: if (NULL != ref3) ref3->parent = this; \ mjsousa@936: if (NULL != ref4) ref4->parent = this; \ msousa@286: } \ msousa@286: void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} msousa@286: msousa@286: msousa@350: #define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5, ...) \ msousa@286: class_name_c::class_name_c(symbol_c *ref1, \ msousa@286: symbol_c *ref2, \ msousa@286: symbol_c *ref3, \ msousa@286: symbol_c *ref4, \ msousa@286: symbol_c *ref5, \ msousa@287: int fl, int fc, const char *ffile, long int forder, \ msousa@287: int ll, int lc, const char *lfile, long int lorder) \ msousa@287: :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { \ msousa@286: this->ref1 = ref1; \ msousa@286: this->ref2 = ref2; \ msousa@286: this->ref3 = ref3; \ msousa@286: this->ref4 = ref4; \ msousa@286: this->ref5 = ref5; \ mjsousa@936: if (NULL != ref1) ref1->parent = this; \ mjsousa@936: if (NULL != ref2) ref2->parent = this; \ mjsousa@936: if (NULL != ref3) ref3->parent = this; \ mjsousa@936: if (NULL != ref4) ref4->parent = this; \ mjsousa@936: if (NULL != ref5) ref5->parent = this; \ msousa@286: } \ msousa@286: void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} msousa@286: msousa@286: msousa@286: msousa@350: #define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6, ...) \ msousa@286: class_name_c::class_name_c(symbol_c *ref1, \ msousa@286: symbol_c *ref2, \ msousa@286: symbol_c *ref3, \ msousa@286: symbol_c *ref4, \ msousa@286: symbol_c *ref5, \ msousa@286: symbol_c *ref6, \ msousa@287: int fl, int fc, const char *ffile, long int forder, \ msousa@287: int ll, int lc, const char *lfile, long int lorder) \ msousa@287: :symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { \ msousa@286: this->ref1 = ref1; \ msousa@286: this->ref2 = ref2; \ msousa@286: this->ref3 = ref3; \ msousa@286: this->ref4 = ref4; \ msousa@286: this->ref5 = ref5; \ msousa@286: this->ref6 = ref6; \ mjsousa@936: if (NULL != ref1) ref1->parent = this; \ mjsousa@936: if (NULL != ref2) ref2->parent = this; \ mjsousa@936: if (NULL != ref3) ref3->parent = this; \ mjsousa@936: if (NULL != ref4) ref4->parent = this; \ mjsousa@936: if (NULL != ref5) ref5->parent = this; \ mjsousa@936: if (NULL != ref6) ref6->parent = this; \ msousa@286: } \ etisserant@0: void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);} etisserant@0: etisserant@0: etisserant@0: etisserant@0: #include "absyntax.def" etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: #undef SYM_LIST etisserant@0: #undef SYM_TOKEN etisserant@0: #undef SYM_TOKEN etisserant@0: #undef SYM_REF0 mario@69: #undef SYM_REF1 etisserant@0: #undef SYM_REF2 mario@69: #undef SYM_REF3 etisserant@0: #undef SYM_REF4 mario@69: #undef SYM_REF5 etisserant@0: #undef SYM_REF6 etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: