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 */