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 <http://www.gnu.org/licenses/>.
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 <stdio.h> // required for NULL
msousa@417: #include <vector>
msousa@738: #include <map>
conti@564: #include <string>
msousa@565: #include <stdint.h>  // required for uint64_t, etc...
msousa@607: #include "../main.hh" // required for uint8_t, real_64_t, ..., and the macros INT8_MAX, REAL32_MAX, ... */
msousa@607: 
msousa@607: 
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@738: /* Case insensitive string compare */
msousa@738:   /* Case insensitive string compare copied from
msousa@738:    * "The C++ Programming Language" - 3rd Edition
msousa@738:    * by Bjarne Stroustrup, ISBN 0201889544.
msousa@738:    */
msousa@738: class nocasecmp_c {
msousa@738:     public:
msousa@738:       bool operator() (const std::string& x, const std::string& y) const {
msousa@738:         std::string::const_iterator ix = x.begin();
msousa@738:         std::string::const_iterator iy = y.begin();
msousa@738: 
msousa@738:         for(; (ix != x.end()) && (iy != y.end()) && (toupper(*ix) == toupper(*iy)); ++ix, ++iy);
msousa@738:         if (ix == x.end()) return (iy != y.end());
msousa@738:         if (iy == y.end()) return false;
msousa@738:         return (toupper(*ix) < toupper(*iy));
msousa@738:       };
msousa@738:   };
msousa@738: 
msousa@738: 
msousa@738: 
msousa@738: 
msousa@738: 
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:
msousa@659:     /* WARNING: only use this method for debugging purposes!! */
msousa@659:     virtual const char *absyntax_cname(void) {return "symbol_c";};
msousa@659: 
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@738:      */    
msousa@569:     /*** Data type analysis ***/
msousa@417:     std::vector <symbol_c *> 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@612:     typedef enum { cs_undefined,   /* not defined/not yet evaluated --> const_value is not valid! */
msousa@612:                    cs_non_const,   /* we have deternmined that expression is not a const value --> 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@612:     typedef struct {const_status_t status;  real64_t  value; } const_value_real64_t;
msousa@612:     typedef struct {const_status_t status;   int64_t  value; } const_value_int64_t;
msousa@612:     typedef struct {const_status_t status;  uint64_t  value; } const_value_uint64_t;
msousa@612:     typedef struct {const_status_t status;      bool  value; } const_value_bool_t;
msousa@612: 
msousa@569:     typedef struct {
msousa@612:       const_value_real64_t _real64; /* status is initialised to UNDEFINED */
msousa@612:       const_value_int64_t   _int64; /* status is initialised to UNDEFINED */
msousa@612:       const_value_uint64_t _uint64; /* status is initialised to UNDEFINED */
msousa@612:       const_value_bool_t     _bool; /* status is initialised to UNDEFINED */
msousa@612:     } const_value_t;
msousa@612:     const_value_t const_value;
msousa@569:     
msousa@738:     /*** Enumeration datatype checking ***/    
msousa@738:     /* Not all symbols will contain the following anotations, which is why they are not declared here in symbol_c
msousa@738:      * They will be declared only inside the symbols that require them (have a look at absyntax.def)
msousa@738:      */
msousa@738:     typedef std::multimap<std::string, symbol_c *, nocasecmp_c> enumvalue_symtable_t;
msousa@738:     
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: 
msousa@738: 
msousa@738: 
etisserant@0: class token_c: public symbol_c {
etisserant@0:   public:
msousa@659:     /* WARNING: only use this method for debugging purposes!! */
msousa@659:     virtual const char *absyntax_cname(void) {return "token_c";};
msousa@659: 
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: 
msousa@738: 
msousa@738: 
etisserant@0:  /* a list of symbols... */
etisserant@0: class list_c: public symbol_c {
etisserant@0:   public:
msousa@659:     /* WARNING: only use this method for debugging purposes!! */
msousa@659:     virtual const char *absyntax_cname(void) {return "list_c";};
msousa@659: 
msousa@655:     int c,n; /* c: current capacity of list (malloc'd memory);  n: current number of elements in list */
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@738: 
msousa@738: 
msousa@738: 
msousa@738: 
msousa@738: 
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@659:     /* WARNING: only use this method for debugging purposes!! */							\
msousa@659:     virtual const char *absyntax_cname(void) {return #class_name_c;};							\
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@659:     /* WARNING: only use this method for debugging purposes!! */							\
msousa@659:     virtual const char *absyntax_cname(void) {return #class_name_c;};							\
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@659:     /* WARNING: only use this method for debugging purposes!! */							\
msousa@659:     virtual const char *absyntax_cname(void) {return #class_name_c;};							\
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@659:     /* WARNING: only use this method for debugging purposes!! */							\
msousa@659:     virtual const char *absyntax_cname(void) {return #class_name_c;};							\
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@659:     /* WARNING: only use this method for debugging purposes!! */							\
msousa@659:     virtual const char *absyntax_cname(void) {return #class_name_c;};							\
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@659:     /* WARNING: only use this method for debugging purposes!! */							\
msousa@659:     virtual const char *absyntax_cname(void) {return #class_name_c;};							\
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@659:     /* WARNING: only use this method for debugging purposes!! */							\
msousa@659:     virtual const char *absyntax_cname(void) {return #class_name_c;};							\
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@659:     /* WARNING: only use this method for debugging purposes!! */							\
msousa@659:     virtual const char *absyntax_cname(void) {return #class_name_c;};							\
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);										\
msousa@659:     /* WARNING: only use this method for debugging purposes!! */							\
msousa@659:     virtual const char *absyntax_cname(void) {return #class_name_c;};							\
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 */