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: * Declaration of the Abstract Syntax data structure components etisserant@0: */ etisserant@0: etisserant@0: /* etisserant@0: * ABSYNTAX.H etisserant@0: * etisserant@0: * This generates the parse tree structure used to bind the components etisserant@0: * identified by Bison in the correct syntax order. At the end of the etisserant@0: * Bison analysis the tree is walked in a sequential fashion generating etisserant@0: * the relavent code. etisserant@0: */ etisserant@0: etisserant@0: #ifndef _ABSYNTAX_HH etisserant@0: #define _ABSYNTAX_HH etisserant@0: etisserant@0: etisserant@0: #include // required for NULL msousa@417: #include conti@564: #include msousa@565: #include // required for uint64_t, etc... etisserant@0: msousa@568: msousa@569: /* Determine, for the current platform, which data type (float, double or long double) uses 64 bits. */ msousa@572: /* NOTE: We cant use sizeof() in pre-processor directives, so we have to do it another way... */ msousa@572: /* CURIOSITY: We can use sizeof() and offsetof() inside static_assert() but: msousa@572: * - this only allows us to make assertions, and not #define new macros msousa@572: * - is only available in the C standard [ISO/IEC 9899:2011] and the C++ 0X draft standard [Becker 2008]. It is not available in C99. msousa@572: * https://www.securecoding.cert.org/confluence/display/seccode/DCL03-C.+Use+a+static+assertion+to+test+the+value+of+a+constant+expression msousa@572: * struct {int a, b, c, d} header_t; msousa@572: * e.g.: static_assert(offsetof(struct header_t, c) == 8, "Compile time error message."); msousa@572: */ msousa@572: msousa@568: #include msousa@568: #if (LDBL_MANT_DIG == 53) /* NOTE: 64 bit IEC559 real has 53 bits for mantissa! */ msousa@568: #define long_double long double msousa@568: #define real64_t long_double /* so we can later use #if (real64_t == long_double) directives in the code! */ msousa@568: #elif ( DBL_MANT_DIG == 53) /* NOTE: 64 bit IEC559 real has 53 bits for mantissa! */ msousa@568: #define real64_t double msousa@568: #elif ( FLT_MANT_DIG == 53) /* NOTE: 64 bit IEC559 real has 53 bits for mantissa! */ msousa@568: #define real64_t float msousa@568: #else msousa@568: #error Could not find a 64 bit floating point data type on this platform. Aborting... msousa@568: #endif msousa@568: msousa@568: etisserant@0: /* Forward declaration of the visitor interface conti@564: * declared in the visitor.hh file etisserant@0: * We cannot include the visitor.hh file, as it will etisserant@0: * include this same file first, as it too requires references etisserant@0: * to the abstract syntax classes defined here. etisserant@0: */ etisserant@0: class visitor_c; // forward declaration etisserant@0: etisserant@0: etisserant@0: class symbol_c; // forward declaration etisserant@0: etisserant@0: msousa@569: msousa@569: msousa@569: msousa@569: msousa@569: msousa@569: msousa@569: msousa@569: msousa@569: etisserant@0: /* The base class of all symbols */ etisserant@0: class symbol_c { etisserant@0: etisserant@0: public: etisserant@0: /* msousa@569: * Line number for the purposes of error checking. msousa@569: * Annotated (inserted) by stage1_2 etisserant@0: */ mario@69: int first_line; mario@69: int first_column; msousa@286: const char *first_file; /* filename referenced by first line/column */ msousa@287: long int first_order; /* relative order in which it is read by lexcial analyser */ mario@69: int last_line; mario@69: int last_column; msousa@286: const char *last_file; /* filename referenced by last line/column */ msousa@287: long int last_order; /* relative order in which it is read by lexcial analyser */ msousa@569: msousa@569: msousa@569: /* msousa@569: * Annotations produced during stage 3 msousa@569: */ msousa@569: /*** Data type analysis ***/ msousa@417: std::vector candidate_datatypes; /* All possible data types the expression/literal/etc. may take. Filled in stage3 by fill_candidate_datatypes_c class */ msousa@459: /* Data type of the expression/literal/etc. Filled in stage3 by narrow_candidate_datatypes_c msousa@459: * If set to NULL, it means it has not yet been evaluated. msousa@459: * If it points to an object of type invalid_type_name_c, it means it is invalid. msousa@459: * Otherwise, it points to an object of the apropriate data type (e.g. int_type_name_c, bool_type_name_c, ...) msousa@459: */ conti@564: symbol_c *datatype; conti@564: msousa@569: /*** constant folding ***/ msousa@569: /* During stage 3 (semantic analysis/checking) we will be doing constant folding. msousa@569: * That algorithm will anotate the abstract syntax tree with the result of operations msousa@569: * on literals (i.e. 44 + 55 will store the result 99). msousa@569: * Since the same source code (e.g. 1 + 0) may actually be a BOOL or an ANY_INT, msousa@569: * or an ANY_BIT, we need to handle all possibilities, and determine the result of the msousa@569: * operation assuming each type. msousa@569: * For this reason, we have one entry for each possible type, with some expressions msousa@569: * having more than one entry filled in! msousa@569: */ msousa@569: typedef enum { cs_undefined, /* not defined --> const_value is not valid! */ msousa@569: cs_const_value, /* const value is valid */ msousa@569: cs_overflow /* result produced overflow or underflow --> const_value is not valid! */ msousa@569: } const_status_t; msousa@569: msousa@569: typedef struct { msousa@569: const_status_t status; msousa@569: real64_t value; msousa@569: } const_value_real64_t; msousa@569: const_value_real64_t *const_value_real64; /* when NULL --> UNDEFINED */ msousa@569: msousa@569: typedef struct { msousa@569: const_status_t status; msousa@569: int64_t value; msousa@569: } const_value_int64_t; msousa@569: const_value_int64_t *const_value_int64; /* when NULL --> UNDEFINED */ msousa@569: msousa@569: typedef struct { msousa@569: const_status_t status; msousa@569: uint64_t value; msousa@569: } const_value_uint64_t; msousa@569: const_value_uint64_t *const_value_uint64; /* when NULL --> UNDEFINED */ msousa@569: msousa@569: typedef struct { msousa@569: const_status_t status; msousa@569: bool value; msousa@569: } const_value_bool_t; msousa@569: const_value_bool_t *const_value_bool; /* when NULL --> UNDEFINED */ msousa@417: etisserant@0: etisserant@0: public: etisserant@0: /* default constructor */ msousa@287: 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 */ msousa@287: int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0 /* order in which it is read by lexcial analyser */ mario@69: ); etisserant@0: etisserant@0: /* default destructor */ etisserant@0: /* must be virtual so compiler does not complain... */ etisserant@0: virtual ~symbol_c(void) {return;}; etisserant@0: etisserant@0: virtual void *accept(visitor_c &visitor) {return NULL;}; etisserant@0: }; etisserant@0: etisserant@0: etisserant@0: class token_c: public symbol_c { etisserant@0: public: etisserant@0: /* the value of the symbol. */ etisserant@0: const char *value; etisserant@0: etisserant@0: public: msousa@286: token_c(const char *value, msousa@287: int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, /* order in which it is read by lexcial analyser */ msousa@287: int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0 /* order in which it is read by lexcial analyser */ msousa@286: ); etisserant@0: }; etisserant@0: etisserant@0: etisserant@0: /* a list of symbols... */ etisserant@0: class list_c: public symbol_c { etisserant@0: public: etisserant@0: int n; etisserant@0: symbol_c **elements; etisserant@0: etisserant@0: public: msousa@287: 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 */ msousa@287: int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0 /* order in which it is read by lexcial analyser */ msousa@286: ); msousa@286: msousa@286: list_c(symbol_c *elem, msousa@287: int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, /* order in which it is read by lexcial analyser */ msousa@287: int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0 /* order in which it is read by lexcial analyser */ msousa@286: ); msousa@350: /* append a new element to the end of the list */ etisserant@0: virtual void add_element(symbol_c *elem); 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: virtual void insert_element(symbol_c *elem, int pos = 0); msousa@438: /* remove element at position pos. */ msousa@438: virtual void remove_element(int pos = 0); msousa@350: }; msousa@350: msousa@350: msousa@350: msousa@350: msousa@568: #define SYM_LIST(class_name_c, ...) \ msousa@286: class class_name_c: public list_c { \ msousa@286: public: \ msousa@350: __VA_ARGS__ \ msousa@350: public: \ msousa@286: class_name_c( \ msousa@287: int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ msousa@287: int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ msousa@286: class_name_c(symbol_c *elem, \ msousa@287: int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ msousa@287: int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ msousa@286: virtual void *accept(visitor_c &visitor); \ msousa@286: }; msousa@286: msousa@286: msousa@568: #define SYM_TOKEN(class_name_c, ...) \ msousa@286: class class_name_c: public token_c { \ msousa@286: public: \ msousa@350: __VA_ARGS__ \ msousa@350: public: \ msousa@286: class_name_c(const char *value, \ msousa@287: int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ msousa@287: int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ msousa@286: virtual void *accept(visitor_c &visitor); \ msousa@286: }; msousa@286: msousa@286: msousa@568: #define SYM_REF0(class_name_c, ...) \ msousa@350: class class_name_c: public symbol_c { \ msousa@350: public: \ msousa@350: __VA_ARGS__ \ msousa@286: public: \ msousa@286: class_name_c( \ msousa@287: int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ msousa@287: int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ msousa@286: virtual void *accept(visitor_c &visitor); \ msousa@286: }; msousa@286: msousa@286: msousa@350: #define SYM_REF1(class_name_c, ref1, ...) \ msousa@350: class class_name_c: public symbol_c { \ msousa@350: public: \ msousa@350: symbol_c *ref1; \ msousa@350: __VA_ARGS__ \ msousa@350: public: \ msousa@350: class_name_c(symbol_c *ref1, \ msousa@350: int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ msousa@350: int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ msousa@350: virtual void *accept(visitor_c &visitor); \ msousa@350: }; msousa@350: msousa@350: msousa@350: #define SYM_REF2(class_name_c, ref1, ref2, ...) \ msousa@350: class class_name_c: public symbol_c { \ msousa@350: public: \ msousa@350: symbol_c *ref1; \ msousa@350: symbol_c *ref2; \ msousa@350: __VA_ARGS__ \ msousa@286: public: \ msousa@286: class_name_c(symbol_c *ref1, \ msousa@286: symbol_c *ref2 = NULL, \ msousa@287: int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ msousa@287: int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ msousa@286: virtual void *accept(visitor_c &visitor); \ msousa@286: }; msousa@286: msousa@286: msousa@350: #define SYM_REF3(class_name_c, ref1, ref2, ref3, ...) \ msousa@350: class class_name_c: public symbol_c { \ msousa@350: public: \ msousa@350: symbol_c *ref1; \ msousa@350: symbol_c *ref2; \ msousa@350: symbol_c *ref3; \ msousa@350: __VA_ARGS__ \ msousa@350: public: \ msousa@350: class_name_c(symbol_c *ref1, \ msousa@350: symbol_c *ref2, \ msousa@350: symbol_c *ref3, \ msousa@350: int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ msousa@350: int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ msousa@350: virtual void *accept(visitor_c &visitor); \ msousa@350: }; msousa@350: msousa@350: msousa@350: #define SYM_REF4(class_name_c, ref1, ref2, ref3, ref4, ...) \ msousa@286: class class_name_c: public symbol_c { \ msousa@286: public: \ msousa@286: symbol_c *ref1; \ msousa@286: symbol_c *ref2; \ msousa@286: symbol_c *ref3; \ msousa@286: symbol_c *ref4; \ msousa@350: __VA_ARGS__ \ msousa@286: public: \ msousa@286: class_name_c(symbol_c *ref1, \ msousa@286: symbol_c *ref2, \ msousa@286: symbol_c *ref3, \ msousa@286: symbol_c *ref4 = NULL, \ msousa@287: int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ msousa@287: int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ msousa@286: virtual void *accept(visitor_c &visitor); \ msousa@286: }; msousa@286: msousa@286: msousa@568: #define SYM_REF5(class_name_c, ref1, ref2, ref3, ref4, ref5, ...) \ msousa@286: class class_name_c: public symbol_c { \ msousa@286: public: \ msousa@286: symbol_c *ref1; \ msousa@286: symbol_c *ref2; \ msousa@286: symbol_c *ref3; \ msousa@286: symbol_c *ref4; \ msousa@286: symbol_c *ref5; \ msousa@350: __VA_ARGS__ \ msousa@286: public: \ msousa@286: 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 = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ msousa@287: int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ msousa@286: virtual void *accept(visitor_c &visitor); \ msousa@286: }; msousa@286: msousa@286: msousa@350: #define SYM_REF6(class_name_c, ref1, ref2, ref3, ref4, ref5, ref6, ...) \ msousa@286: class class_name_c: public symbol_c { \ msousa@286: public: \ msousa@286: 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@350: __VA_ARGS__ \ msousa@286: public: \ msousa@286: 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 = NULL, \ msousa@287: int fl = 0, int fc = 0, const char *ffile = NULL /* filename */, long int forder=0, \ msousa@287: int ll = 0, int lc = 0, const char *lfile = NULL /* filename */, long int lorder=0); \ msousa@286: virtual void *accept(visitor_c &visitor); \ etisserant@0: }; etisserant@0: etisserant@0: etisserant@0: #include "absyntax.def" etisserant@0: etisserant@0: etisserant@0: etisserant@0: #undef SYM_LIST 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: #endif /* _ABSYNTAX_HH */