← index
cplusplus17.Examples/examples/ScanLex/parser_ast.cpp
Source: cplusplus17.Examples/examples/ScanLex/parser_ast.cpp
#include "parser_ast.hpp"

namespace parse {

    using namespace scan;
    using namespace backend;

    Item::Item() : keyword{KEY_EMPTY}, oper{OP_EMPTY}, id{}, type{TOKEN_NULL}, index{-1}, index_const{-1}, val{0} {

    }
    Item::Item(KEYWORD_TYPES k) : keyword{k}, oper{OP_EMPTY}, id{}, type{TOKEN_KEYWORD}, index{-1}, index_const{-1}, val{0} {

    }
    
    Item::Item(OP_TYPES o) : keyword{KEY_EMPTY}, oper{o}, id{}, type{TOKEN_SYMBOL}, index{-1}, index_const{-1}, val{0} {

    }
    
    Item::Item(std::string i) : keyword{KEY_EMPTY}, oper{OP_EMPTY}, id{i}, type{TOKEN_ID}, index{-1}, index_const{-1}, val{0} {

    }
        
    Item::Item(int i) : keyword{KEY_EMPTY}, oper{OP_EMPTY}, id{}, type{TOKEN_STRING}, index{-1}, index_const{i}, val{0} {

    }

    Item::Item(int i, bool) : keyword{KEY_EMPTY}, oper{OP_EMPTY}, id{}, type{TOKEN_ID}, index{i}, index_const{-1}, val{0} {

    }
        
    Item::Item(double d) : keyword{KEY_EMPTY}, oper{OP_EMPTY}, id{}, type{TOKEN_NUMBER}, index{-1}, index_const{-1}, val{d} {

    }

    Item::Item(const Item &i) {
        copy(i);
    }
    Item::Item(Item &&i) {
        copy(i);
    }
    Item &Item::operator=(const Item &i) {
        copy(i);
        return *this;
    }
    
    Item &Item::operator=(Item && i) {
        copy(i);
        return *this;
    }

    void Item::copy(const Item &i) {
        index = i.index;
        keyword = i.keyword;
        oper = i.oper;
        type = i.type;
        index_const = i.index_const;
        val = i.val;
        id = i.id;
    }

    Function::~Function() {
        for(std::size_t i = 0; i < expressions.size(); ++i) {
            Expr *expression = expressions[i];
            if(expression != nullptr)
               delete expression;
        }
    }

    Expr::Expr() {
        left = nullptr;
        right = nullptr;
        group = nullptr;
        func = nullptr;
    }

     Expr::~Expr() {
         if(left != nullptr)
            delete left;
        left = nullptr;
        if(right != nullptr)
            delete right;
        right = nullptr;
        if(group != nullptr)
            delete group;
        group = nullptr;

        if(func != nullptr)
            delete func;
        func = nullptr;

        if(body != nullptr)
            delete body;

        body = nullptr;
        //std::cout << "deleted expression\n";
     }

    Statement::Statement() {
        expression = nullptr;
    }

     Statement::~Statement() {
        if(expression != nullptr)
            delete expression;
        expression = nullptr;
     }

    Body::~Body() {
        for(std::size_t i = 0; i < statements.size(); ++i) {
            Statement *s = statements[i];
            if(s != nullptr) {
                delete s;
                s = nullptr;
            }
        }
    }

   Procedure::Procedure() {

   }
        
  Procedure::~Procedure() {
    for(std::size_t i = 0; i < body.size(); ++i) {
          Body *b = body[i];
          if(b != nullptr)
            delete b;
      }
  }

  TreeNode::~TreeNode() {
    for(std::size_t i = 0; i < children.size(); ++i) {
          TreeNode *n = children[i];
          delete n;
          n = nullptr;
      }
  }

    AST::AST(std::istream *i) : in{i} {}

    bool AST::scan() {
        char c = 0;
        char header[5];
        in->read(header, 4);
        header[4] = 0;
        if(std::string(header) != "!MXE") {
            return false;
        }
        
        while(!in->eof()) {
            in->read(reinterpret_cast<char*>(&c), sizeof(c));
            switch(c) {
                case '$': {
                   KEYWORD_TYPES keyword;
                   in->read(reinterpret_cast<char*>(&keyword), sizeof(keyword));
                   tokens.push_back(Item(keyword));

                }
                break; 
                case '@': {
                    OP_TYPES op;
                    in->read(reinterpret_cast<char*>(&op), sizeof(op));
                    tokens.push_back(Item(op));
                }
                break; 
                case '~': {
                    int index;
                    in->read(reinterpret_cast<char*>(&index), sizeof(index));
                    tokens.push_back(Item(index, true));
                }
                break;
                case '#': {
                    int index;
                    in->read(reinterpret_cast<char*>(&index), sizeof(index));
                    tokens.push_back(Item(index));
                }
                break;
                case '&': {
                    double d;
                    in->read(reinterpret_cast<char*>(&d), sizeof(d));
                    tokens.push_back(Item(d));
                }
                break;
                case '!': {
                    int ts = 0;
                    in->read(reinterpret_cast<char*>(&ts), sizeof(ts));
                    for(int i = 0; i < ts; ++i) {
                        int len = 0;
                        in->read(reinterpret_cast<char*>(&len), sizeof(len));
                        char *buf = new char [len + 1];
                        in->read(buf, len);
                        buf[len] = 0;
                        std::string text = buf;
                        delete [] buf;
                        const_strings.push_back(text);                     
                    }
                }
                break;
                case '^': {
                    int sz = 0;
                    in->read(reinterpret_cast<char*>(&sz), sizeof(sz));
                    for(int i = 0; i < sz; ++i) {
                        int len = 0;
                        in->read(reinterpret_cast<char*>(&len), sizeof(len));
                        char *buf;
                        buf = new char [len+1];
                        in->read(buf, len);
                        buf[len] = 0;
                        std::string text = buf;
                        delete [] buf;
                        int index;
                        in->read(reinterpret_cast<char*>(&index), sizeof(index));
                        id.enter(text, "", index);
                        identifiers[index] = text;
                        
                    }
                    return true;
                }
                break; 
            }
        }
        return true;
    }

    void AST::print(std::ostream &out) {
        for(std::size_t i = 0; i < tokens.size(); ++i) {
            switch(tokens[i].type) {
                case TOKEN_ID:
                out << "id: " << identifiers[tokens[i].index] << "\n";
                break;
                case TOKEN_STRING:
                out << "str: " << const_strings[tokens[i].index_const] << "\n";
                break;
                case TOKEN_KEYWORD:
                out << "keyword: " << keywords[tokens[i].keyword] << "\n";
                break;
                case TOKEN_NUMBER:
                out << "number: " << tokens[i].val << "\n";
                break;
                case TOKEN_SYMBOL:
                out << "operator: " << operators[tokens[i].oper] << "\n";
                break;
                default:
                break;
            }
        }
    }

   bool AST::buildTree() {
       token = tokens[0];
       sindex = 0;
       try {
           cur_table = &id;
           parseCode();
       } catch(ParserException &e) {
           std::cerr << e.error() << "\n";
           return false;
       }
       return true;
   }

    AST::~AST() {
        
    }

   void AST::parseCode() {
       getToken();
       switch(token.type) {
           case TOKEN_KEYWORD:
           switch(token.keyword) {
               case KEY_PROC:
               getToken();
               parseProc();
               parseCode();
               break;
               default:
               break;
           }
           break;
           default:
           break;
       }
   }

    Expr *AST::parseAssignment() {
        if(!cur_table->valid(identifiers[token.index])) {
            std::ostringstream stream;
            stream << "Exception: Variable " << identifiers[token.index] << " not declared!\n";
            throw ParserException(stream.str());
        }
        getToken();
        if(match({OP_EQUAL})) {
            consume(OP_EQUAL);
            Expr *e = parseExpr();
            return e;
         } else if(match({OP_STRING_EQUAL})) {
             consume(OP_STRING_EQUAL);
             Expr *e = parseExpr();
             return e;
         }
        return nullptr;
    }

   


    Expr *AST::parseStringAssignment() {

        return nullptr;
    }

  void AST::parseStatement(Body *body) {
      while(token.keyword != KEY_END) {
          if(token.oper == OP_BLOCK_C) {
              return;
          }
          if(match(KEY_RETURN)) {
              Statement *s = new Statement();
              s->expression = parseReturn();
              s->type = STATE_RETURN;
              body->statements.push_back(s);
          } else if (match(KEY_LET)) {
              Statement *s = new Statement();
              s->expression = parseLet(s);
              s->type = STATE_LET;
              body->statements.push_back(s);
              consume(OP_SEMI_COLON);
          } else if(match(KEY_IF)) {

                getToken();
          } else if(match(KEY_WHILE)) {
              Statement *s = new Statement();
              s->type = STATE_WHILE;
              consume(KEY_WHILE);
              consume(OP_OP);
              Expr *e = parseExpr();
              consume(OP_CP);
              Body *b = parseBlock();
              e->body = b;
              s->expression = e;
              body->statements.push_back(s);
          }
          else if(match(TOKEN_ID) && match_lookahead(OP_EQUAL)) {
             Statement *s = new Statement();
             s->var = identifiers[token.index];
             s->expression = parseAssignment();
             s->type = STATE_ASSIGN;
            body->statements.push_back(s);
          } else if(match(TOKEN_ID) && match_lookahead(OP_OP)) {
              Statement *s = new Statement();
              s->var = identifiers[token.index];
              s->expression = parseExpr();
              s->type = STATE_FUNC;
              body->statements.push_back(s);
          } else {
              getToken();
          }
      }
  }

    Expr *AST::parseReturn() {
      consume(KEY_RETURN);
      Expr *e = parseExpr();
      return e;
    }

    Expr *AST::parseLet(Statement *s) {
        consume(KEY_LET);
        if(match(TOKEN_ID)) {
            cur_table->enter(identifiers[token.index], "");
            s->var = identifiers[token.index];
            if(match_lookahead(OP_EQUAL)) {
                s->var_type = VAR_DOUBLE;
                return parseAssignment();
            }
            else if(match_lookahead(OP_STRING_EQUAL)) {
                s->var_type = VAR_STRING;
                return parseAssignment();
            } else
                getToken();
        }
        return 0;
    }

    Body *AST::parseBody(Body *body) {
       if(consume(KEY_BEGIN)) {
           parseStatement(body);
            if(match(KEY_END)) {
               consume(KEY_END);
               consume(OP_SEMI_COLON);
           } else {
               
           }
       }
       return body;
   }

   Body *AST::parseBlock() {
       Body *body = new Body();
       consume(OP_BLOCK_O);
       parseStatement(body);
       //if(match({OP_BLOCK_C})) {
           consume(OP_BLOCK_C);
       //}
       return body;
   }

    void AST::parseArgs(ArgList &args) {
        consume(OP_OP);
        if(match({OP_CP})) { 
            consume(OP_CP);
            return;
        }

        while(token.type == TOKEN_ID) {
            args.args.push_back(identifiers[token.index]);
            getToken();
            if(match({OP_CP})) {
                consume(OP_CP);
                return;
            }
            if(match({OP_COMMA}))
            {
                consume(OP_COMMA);
            }
        }
    }



   void AST::parseProc() {
       std::string name;
       name = identifiers[token.index];
       TreeNode *n = new TreeNode();
       n->proc.name = name;
       n->type = NODE_PROC;
       n->proc.id.parent = &id;
       n->proc.id.name = name;
       cur_table = &n->proc.id;
       proc = &n->proc;
       getToken();
       parseArgs(n->proc.param);
       // while(b) body.push_back(b)
       Body *b = new Body();
       b = parseBody(b);
       proc->body.push_back(b);
       root.children.push_back(n);
   }

   Expr *AST::parseExpr() {
       return parseEqual();
   }
        
    Expr *AST::parseComp() {
        Expr *e = parseTerm();
        while(match({OP_GREATER, OP_LESS, OP_GTE, OP_LTE})) {
            OP_TYPES oper = token.oper;
            getToken();
            Expr *ne = new Expr();
            ne->left = e;
            ne->oper = oper;
            ne->right = parseTerm();
            ne->type = EXPR_BINARY;
            e = ne;
        }
        return e;
    }
        
    Expr *AST::parseEqual() {
        Expr *e = parseComp();
        while(match({OP_EQ_EQ, OP_NE})) {
            OP_TYPES oper = token.oper;
            getToken();
            Expr *ne = new Expr();
            ne->left = e;
            ne->oper = oper;
            ne->right = parseComp();
            ne->type = EXPR_BINARY;
            e = ne;
        }
        return e;
    }
    
    Expr *AST::parseTerm() {
        Expr *e = parseFactor();
        while(match({OP_PLUS, OP_MINUS})) {
            OP_TYPES oper = token.oper;
            getToken();
            Expr *right = parseFactor();
            Expr *ne = new Expr();
            ne->left = e;
            ne->oper = oper;
            ne->right = right;
            ne->type = EXPR_BINARY;
            e = ne;
        }
        return e;
    }
        
    Expr *AST::parseFactor() {
        Expr *e = parseUnary();
        while(match({OP_DIV, OP_MUL})) {
            OP_TYPES oper = token.oper;
            getToken();
            Expr *ne = new Expr();
            ne->left = e;
            ne->oper = oper;
            ne->right = parseUnary();
            ne->type = EXPR_BINARY;
            e = ne;
        }
        return e;
    }
        
    Expr *AST::parsePrim() {
        if(match(TOKEN_ID)||match(TOKEN_NUMBER)||match(TOKEN_STRING)) {

            if(match(TOKEN_ID) && match_lookahead(OP_OP)) {
                Expr *e = new Expr();
                e->left = nullptr;
                e->right = nullptr;
                e->oper = OP_EMPTY;
                e->type = EXPR_FUNC;
                e->func = parseFunction();
                return e;
            } else {

                Expr *e = new Expr();
                e->left = 0;
                e->right = 0;
                e->oper = OP_EMPTY;
                e->type = EXPR_LITERAL;
                e->token = token;
                getToken();
                return e;
            }
        }

        if(match({OP_OP})) {
            getToken();
            Expr *e = parseExpr();
            consume(OP_CP);
            Expr *ne = new Expr();
            ne->group = e;
            ne->type = EXPR_GROUP;
            return ne;
        }
        return 0;
    }

    Expr *AST::parseUnary() {
        if(match({OP_MINUS, OP_NOT})) {
            OP_TYPES oper = token.oper;
            getToken();
            Expr *right = parseUnary();
            Expr *ne = new Expr();
            ne->left = 0;
            ne->oper = oper;
            ne->right = right;
            ne->type = EXPR_UNARY;
            return ne;
        }
        return parsePrim();
    }


    bool AST::match(const std::initializer_list<OP_TYPES> &lst) {
        for(auto &i : lst) {
            if(i == token.oper)
                return true;
        }
        return false;
    }

    bool AST::match(TOKEN_TYPE type) {
        if(token.type == type)
            return true;
        return false;
    }

    bool AST::match_lookahead(OP_TYPES type) {
        if(sindex < static_cast<int>(tokens.size()) && tokens[sindex].oper == type)
            return true;
        return false;
    }

    Item *AST::prev() {
        if(sindex-1 >= 0)
            return &tokens[sindex-1];
        else {
            std::ostringstream stream;
            stream << "Exception: index of token out of range.\n";
            throw ParserException(stream.str());
        }
        return nullptr;
    }


    bool AST::match(KEYWORD_TYPES key) {
        if(token.keyword == key)
            return true;
        return false;
    }


   bool AST::consume(TOKEN_TYPE type) {
       if(token.type == type) {
           getToken();
           return true;
       }
       std::ostringstream stream;
       stream << "Expected: " << type << " found: " << type;
       throw ParserException(stream.str());
       return false;
   }
   bool AST::consume(OP_TYPES type) {
       if(token.oper == type) {
           getToken();
           return true;
       }
       std::ostringstream stream;
       stream << "Expected: " << operators[type] << " found: " << token.type;
       switch(token.type) {
           case TOKEN_SYMBOL:
           stream << " " << operators[token.oper];
           break;
           case TOKEN_ID:
           stream << " " << identifiers[token.index];
           break;
           case TOKEN_KEYWORD:
           stream << " " << keywords[token.keyword];
           break;
           default:
           break;
       }
       throw ParserException(stream.str());
       return false;
   }
   
   bool AST::consume(KEYWORD_TYPES key) {
       if(token.keyword == key) {
           getToken();
           return true;
       }
       std::ostringstream stream;
       stream << "Expected: " << keywords[key] << " found: " << token.type;
       switch(token.type) {
           case TOKEN_SYMBOL:
           stream << " " << operators[token.oper];
           break;
           case TOKEN_ID:
           stream << " " << identifiers[token.index];
           break;
           case TOKEN_KEYWORD:
           stream << " " << keywords[token.keyword];
           break;
           default:
           break;
       }
       throw ParserException(stream.str());
       return false;
   }

    void AST::printTree(std::ostream &, TreeNode *) {
   }

   Function *AST::parseFunction() {
       if(match(TOKEN_ID)) {
           std::string name = identifiers[token.index];
           getToken();
           consume(OP_OP);
           if(match({OP_CP})) {
               consume(OP_CP);
               Function *f = new Function();
               f->name = name;
               return f;
           } else {
                Function *f = new Function();
                f->name = name;
                bool active = true;
                while(active) {
                    Expr *e = parseExpr();
                    f->expressions.push_back(e);
                    if(match({OP_COMMA})) {
                        consume(OP_COMMA);
                        continue;
                    } else {
                        active = false;
                        break;
                    }
                } 
                consume(OP_CP);
                return f;
           }
        
       } else {
           std::ostringstream stream;
           stream << "Exception: expected identifier found: " << token.type;
           throw ParserException(stream.str());
       }
       return nullptr;
   }

    void AST::eraseTree(TreeNode *) {
   }


    void AST::parExpr(OP_TYPES, Expr *, Expr *) {
     
    }
        

    void AST::printExpr(Expr *) {

   }

   void AST::eval(Expr *e) {
        if(e != nullptr) {
            switch(e->type) {
                case EXPR_BINARY: {

                    if(e->left != nullptr)
                        eval(e->left);
                    if(e->right != nullptr)
                        eval(e->right);
                    
                    switch(e->oper) {
                    case OP_PLUS:
                        bend.put(Inc(O_ADD, Variable(), Variable()));
                    break;
                    case OP_MINUS:
                        bend.put(Inc(O_SUB, Variable(), Variable()));
                    break;
                    case OP_MUL:
                        bend.put(Inc(O_MUL, Variable(), Variable()));
                    break;
                    case OP_DIV:
                        bend.put(Inc(O_DIV,Variable(), Variable()));
                    break;
                    case OP_EQ_EQ:
                        bend.put(Inc(O_EE,Variable(),Variable()));
                    break;
                    case OP_NE:
                        bend.put(Inc(O_NE,Variable(),Variable()));
                    break;
                    case OP_LTE:
                        bend.put(Inc(O_LTE,Variable(),Variable()));
                    break;
                    case OP_LESS:
                        bend.put(Inc(O_LT,Variable(),Variable()));
                    break;
                    case OP_GREATER:
                        bend.put(Inc(O_GT,Variable(),Variable()));
                    break;
                    case OP_GTE:
                        bend.put(Inc(O_GTE,Variable(),Variable()));
                    break;
                    default:
                    break;
                }                

            }
            break;
             case EXPR_FUNC: {
                 if(e->func != nullptr) {
                     for(std::size_t i = 0; i < e->func->expressions.size(); ++i) {
                         Expr *expression = e->func->expressions[i];
                        if(expression != nullptr)
                            eval(expression);
                     }
                    bend.put(Inc(O_CALL, Variable(e->func->name, VAR_FUNC_NAME, VAR_STRING), Variable(double(e->func->expressions.size()))));
                 }
             }
            break;
            case EXPR_LITERAL:
                switch(e->token.type) {
                    case TOKEN_ID:
                    bend.put(Inc(O_PUSH, Variable(identifiers[e->token.index], VAR_DOUBLE), Variable()));
                    break;
                    case TOKEN_STRING:
                    bend.put(Inc(O_PUSH, Variable(const_strings[e->token.index_const]), Variable()));
                    break;
                    case TOKEN_NUMBER:
                    bend.put(Inc(O_PUSH, Variable(e->token.val), Variable()));
                    break;
                    default:
                    break;
                }
                break;
                default:
                case EXPR_GROUP:
                if(e->group != nullptr)
                    eval(e->group);
                break;
                break;
            }
        }
   }

  void AST::buildBackendBody(Body *body) {
      for(auto &i : body->statements) {
            switch(i->type) {
                case STATE_LET: {
                   switch(i->var_type) {
                        case VAR_DOUBLE:
                            bend.decl(i->var, 0);
                            if(i->expression != 0)
                                eval(i->expression);   
                           bend.put(Inc(O_ASSIGN, Variable(i->var, VAR_DOUBLE), Variable()));                        
                           break;
                        case VAR_STRING:
                            bend.decl(i->var, "");
                           if(i->expression != 0)
                                eval(i->expression);
                           bend.put(Inc(O_SASSIGN, Variable(i->var, VAR_STRING), Variable()));
                           break;
                           default:
                           break;
                       }
                   }
                   break;
                   case STATE_ASSIGN:
                        bend.decl(i->var, "");
                        if(i->expression != 0) {
                            eval(i->expression);
                        }
                        bend.put(Inc(O_ASSIGN, Variable(i->var, ""), Variable()));

                   break;
                   case STATE_FUNC:
                        eval(i->expression);
                        bend.put(Inc(O_POP, Variable(), Variable()));
                        break;

                    case STATE_WHILE: {
                        static int counter = 0;
                        std::ostringstream stream;
                        stream << "LW" << counter++;
                        std::string label = stream.str();
                        std::string label2;
                        stream << "_OVER";
                        label2 = stream.str();
                        bend.put(Inc(O_LABEL, Variable(label), Variable()));
                        if(i->expression != nullptr)
                            eval(i->expression);
                        bend.put(Inc(O_BNE, Variable(label2), Variable()));
                        if(i->expression != nullptr && i->expression->body != nullptr)
                            buildBackendBody(i->expression->body);
                         bend.put(Inc(O_B, Variable(label), Variable()));
                         bend.put(Inc(O_LABEL, Variable(label2), Variable()));
                    }
                    break;
                   default:
                   break;
                   case STATE_IF:
                   break;
               }
      }
  }

  void AST::buildCode() {
    buildBackend(rootNode());
    
  }

   void AST::buildBackend(TreeNode *n) {

       switch(n->type) {
           case NODE_PROC: {
               bend.put(Inc(O_PROC, Variable(n->proc.name), Variable()));
               for(auto &b : n->proc.body) {
                   buildBackendBody(b);
               }
               if(n->proc.name == "main")
                    bend.put(Inc(O_EXIT, Variable(), Variable()));
                else
                    bend.put(Inc(O_RET, Variable(), Variable()));
           }
           break;
           default:
           break;
       }
        for(std::size_t i = 0; i < n->children.size(); ++i)
        buildBackend(n->children[i]);
   }

   void AST::printBackend(std::ostream &out) {
       bend.print(out);
   }

   void AST::run() {
       bend.go();
   }

   TreeNode *AST::rootNode() {
       return &root;
   }


    bool AST::getToken() {
        if(sindex < static_cast<int>(tokens.size())) {
            token = tokens[sindex++];
            return true;
        }
        return false;
    }
}