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:
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@417: this->datatype = NULL;
mjsousa@889: this->scope = NULL;
msousa@612: this->const_value._real64.status = cs_undefined;
msousa@612: this->const_value._int64.status = cs_undefined;
msousa@612: this->const_value._uint64.status = cs_undefined;
msousa@612: this->const_value._bool.status = cs_undefined;
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;
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@655: elements = (symbol_c**)malloc(LIST_CAP_INIT*sizeof(symbol_c*));
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@655: elements = (symbol_c**)malloc(LIST_CAP_INIT*sizeof(symbol_c*));
msousa@655: if (NULL == elements) ERROR_MSG("out of memory");
msousa@655: add_element(elem);
msousa@655: }
msousa@655:
etisserant@0:
msousa@350: /* append a new element to the end of the list */
etisserant@0: void list_c::add_element(symbol_c *elem) {
agraeper@654: // printf("list_c::add_element()\n");
msousa@655: if (c <= n)
msousa@655: if (!(elements=(symbol_c**)realloc(elements,(c+=LIST_CAP_INCR)*sizeof(symbol_c *))))
msousa@655: ERROR_MSG("out of memory");
agraeper@654: elements[n++] = elem;
mario@69:
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@350: /* insert a new element before position pos. */
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@350: void list_c::insert_element(symbol_c *elem, int pos) {
agraeper@654: if((pos<0) || (n=pos ; --i) elements[i+1] = elements[i];
agraeper@654: elements[pos] = elem;
agraeper@654: }
msousa@350: }
msousa@350:
msousa@350:
msousa@438: /* remove element at position pos. */
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--;
agraeper@654: /* elements = (symbol_c **)realloc(elements, n * sizeof(symbol_c *)); */
mjsousa@958: /* TODO: adjust the location parameters, taking into account the removed element. */
mjsousa@958: }
mjsousa@958:
mjsousa@958:
mjsousa@958: /* remove element at position pos. */
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: