Česky
Kamil Dudka

Flex/Bison based compiler and interpreter written in C++ (using Boost)

File detail

Name:Downloadparser.cc [Download]
Location: vyp08 > vyp08-1.0pre1 > src
Size:11.9 KB
Last modification:2022-09-09 13:06

Source code

/*
 * Copyright (C) 2008 Kamil Dudka <xdudka00@stud.fit.vutbr.cz>
 *
 * This file is part of vyp08 (compiler and interpreter of VYP08 language).
 *
 * vyp08 is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * vyp08 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with vyp08.  If not, see <http://www.gnu.org/licenses/>.
 */
 
#include "config.h"
#include "parser.h"
 
#include "parser.tab.hh"
#include "vypIO.h"
 
#ifndef BUILDING_DOX
#   include <stack>
#   include <string>
#endif
 
using namespace StreamDecorator;
using std::string;
 
/// bison callback implementation
class BisonListener: public IBisonListener {
    public:
        BisonListener(IBuilder *, string fileName);
        virtual ~BisonListener() { }
        virtual void setType(EToken type);      ///< token type detected
        virtual void glVar(Token token);        ///< global variable
        virtual void fncInit(Token token);      ///< fnc decl/def detected
        virtual void fncDecl();                 ///< fnc declaration complete
        virtual void fncDefEnter();             ///< fnc definition body enter
        virtual void fncDefLeave();             ///< fnc definition body leave
        virtual void argDecl();                 ///< arg in fnc declaration
        virtual void argDef(Token token);       ///< arg in fnc definition
        virtual void lcVar(Token token);        ///< local variable in fnc def
        virtual void assign(Token token)        { builder_ -> assign(token); }
        virtual void ifEnter(Token token)       { builder_ -> ifEnter(token); }
        virtual void ifElse()                   { builder_ -> ifElse(); }
        virtual void ifLeave()                  { builder_ -> ifLeave(); }
        virtual void whileInit(Token token)     { builder_ -> whileInit(token); }
        virtual void whileEnter()               { builder_ -> whileEnter(); }
        virtual void whileLeave()               { builder_ -> whileLeave(); }
        virtual void pushToken(Token token)     { builder_ -> pushToken(token); }
        virtual void evalUnOp(Token token)      { builder_ -> evalUnOp(token); }
        virtual void evalBinOp(Token token)     { builder_ -> evalBinOp(token); }
        virtual void fncCallInit(Token token);  ///< fnc call detected
        virtual void fncCallArg();              ///< fnc call arg
        virtual void fncCallPrintArg();         ///< fnc call arg of print()
        virtual void fncCallAsCmd();            ///< fnc call as command
        virtual void fncCallAsExpr();           ///< fnc call as expression
    private:
        IBuilder    *builder_;                  ///< entry point to higher layer (IBuilder object)
        string      fileName_;                  ///< name (or alias) of input file (used in messages)
        EToken      type_;                      ///< last type detected by bison (will be never T_VOID)
        EToken      fncType_;                   ///< return type of function currently being read
        Token       fncId_;                     ///< name (as defining token) of function currently being read
        bool        fncInitDeclSent_;           ///< true if higher layer is now reading function declaration
        bool        fncInitDefSent_;            ///< true if higher layer is now reading function definition
        EToken      fncPrint_;                  ///< type of print function currently being read (if any)
 
        typedef STD_PAIR(Token, int)    TFncCall;
        typedef STD_STACK(TFncCall)     TStack;
        TStack      stack_;                     ///< function call stack
 
        bool initDeclIfNeeded();                ///< init function declaration in higher layer (if not already initiated)
        bool initDefIfNeeded();                 ///< init function definition in higher layer (if not already initiated)
        void errMixedDeclDef();                 ///< handle error caused by mixed syntax of function declaration/definition
        bool chkStack();                        ///< check stack if not empty; if so handle such error; return true on success
};
 
BisonListener::BisonListener(IBuilder *builder, string fileName):
    builder_(builder),
    fileName_(fileName),
    type_(ETOKEN_NULL),
    fncType_(ETOKEN_NULL),
    fncInitDeclSent_(false),
    fncInitDefSent_(false),
    fncPrint_(ETOKEN_NULL)
{
}
 
void BisonListener::setType(EToken type) {
    type_ = type;
}
 
void BisonListener::glVar(Token token) {
    builder_ -> glVar(type_, token);
}
 
void BisonListener::fncInit(Token token) {
    fncType_ = type_;
    fncId_ = token;
    fncInitDeclSent_ = false;
    fncInitDefSent_ = false;
}
 
void BisonListener::fncDecl() {
    if (initDeclIfNeeded())
        builder_ -> fncDecl();
}
 
void BisonListener::fncDefEnter() {
    initDefIfNeeded();
    builder_ -> fncDefBody();
}
 
void BisonListener::fncDefLeave() {
    if (initDefIfNeeded())
        builder_ -> fncDef();
}
 
void BisonListener::argDecl() {
    if (initDeclIfNeeded())
        builder_ -> fncDeclArg(type_);
}
 
void BisonListener::argDef(Token token) {
    if (initDefIfNeeded())
        builder_ -> fncDefArg(type_, token);
}
 
void BisonListener::lcVar(Token token) {
    if (initDefIfNeeded())
        builder_ -> fncDefVar(type_, token);
}
 
void BisonListener::fncCallInit(Token token) {
    fncPrint_ = ETOKEN_NULL;
#if DEBUG_BISON_LISTENER_STACK
    std::cerr << Color(C_LIGHT_PURPLE) << "BisonListener stack"
        << Color(C_NO_COLOR) << " <-- " << token
        << "[" << Color(C_LIGHT_PURPLE) << 0
        << Color(C_NO_COLOR) << "]" << std::endl;
#endif
    stack_.push(TFncCall(token, 0));
}
 
void BisonListener::fncCallArg() {
    TFncCall &top = stack_.top();
    int &argCnt = top.second;
    ++ argCnt;
#if DEBUG_BISON_LISTENER_STACK
    std::cerr << Color(C_LIGHT_PURPLE) << "BisonListener stack"
        << Color(C_NO_COLOR) << " <-> " << top.first
        << "[" << Color(C_LIGHT_PURPLE) << top.second
        << Color(C_NO_COLOR) << "]" << std::endl;
#endif
}
 
void BisonListener::fncCallPrintArg() {
    if (!chkStack())
        return;
    TFncCall &top = stack_.top();
    Token tFnc = top.first;
    if (tFnc.text != "print") {
        std::cerr << Error(E_ERROR, fileName_, "print syntax used for another function", tFnc) << std::endl;
        builder_->errorDetected();
    }
    fncPrint_ = type_;
}
 
void BisonListener::fncCallAsCmd() {
    if (!chkStack())
        return;
 
    TFncCall top = stack_.top();
    stack_.pop();
#if DEBUG_BISON_LISTENER_STACK
    std::cerr << Color(C_LIGHT_PURPLE) << "BisonListener stack"
        << Color(C_NO_COLOR) << " --> " << top.first
        << "[" << Color(C_LIGHT_PURPLE) << top.second
        << Color(C_NO_COLOR) << "]" << std::endl;
#endif
    if (fncPrint_ == ETOKEN_NULL)
        builder_ -> fncCall(top.first, top.second, false);
    else
        builder_ -> fncCallPrint(top.first, fncPrint_);
}
 
void BisonListener::fncCallAsExpr() {
    if (!chkStack())
        return;
 
    TFncCall top = stack_.top();
    stack_.pop();
#if DEBUG_BISON_LISTENER_STACK
    std::cerr << Color(C_LIGHT_PURPLE) << "BisonListener stack"
        << Color(C_NO_COLOR) << " --> " << top.first
        << "[" << Color(C_LIGHT_PURPLE) << top.second
        << Color(C_NO_COLOR) << "]" << std::endl;
#endif
    builder_ -> fncCall(top.first, top.second, true);
}
 
bool BisonListener::initDeclIfNeeded() {
    if (fncInitDefSent_) {
        errMixedDeclDef();
        return false;
    }
 
    if (!fncInitDeclSent_) {
        builder_ -> fncDeclInit(fncType_, fncId_);
        fncInitDeclSent_ = true;
    }
    return true;
}
 
bool BisonListener::initDefIfNeeded() {
    if (fncInitDeclSent_) {
        errMixedDeclDef();
        return false;
    }
 
    if (!fncInitDefSent_) {
        builder_ -> fncDefInit(fncType_, fncId_);
        fncInitDefSent_ = true;
    }
    return true;
}
 
bool BisonListener::chkStack() {
    if (stack_.empty()) {
        std::cerr << Error(E_ERROR, fileName_, "BisonListener: stack underflow", Token(), true) << std::endl;
        builder_ -> errorDetected();
        return false;
    }
    return true;
}
 
void BisonListener::errMixedDeclDef() {
    std::cerr << Error(E_ERROR, fileName_, "mixed declaration/definition is not allowed", fncId_) << std::endl;
    builder_ -> errorDetected();
}
 
namespace yy {
#ifndef BUILDING_DOX
    void BisonParser::error(const yy::location& loc, const string& msg) {
        std::cerr << Error(E_ERROR, fileName, msg, loc.end.line, "syntax error")
            << std::endl;
    }
#endif
 
    int yylex (Token *token, yy::location *loc, IScanner *scanner) {
        for (;;) {
            if (!scanner->readNext(*token))
                return 0;
            loc->begin.line = loc->end.line = token->lineno;
            // convert scanner token enumeration to bison #define values
            switch (token->type) {
                case ETOKEN_ID:             return BisonParser::token::T_ID;
                case ETOKEN_KW_AND:         return BisonParser::token::T_AND;
                case ETOKEN_KW_DIV:         return BisonParser::token::T_DIV;
                case ETOKEN_KW_DOUBLE:      return BisonParser::token::T_DOUBLE;
                case ETOKEN_KW_ELSE:        return BisonParser::token::T_ELSE;
                case ETOKEN_KW_EQ:          return BisonParser::token::T_EQ;
                case ETOKEN_KW_IF:          return BisonParser::token::T_IF;
                case ETOKEN_KW_INT:         return BisonParser::token::T_INT;
                case ETOKEN_KW_OR:          return BisonParser::token::T_OR;
                case ETOKEN_KW_NEQ:         return BisonParser::token::T_NEQ;
                case ETOKEN_KW_NOT:         return BisonParser::token::T_NOT;
                case ETOKEN_KW_STRING:      return BisonParser::token::T_STRING;
                case ETOKEN_KW_VAR:         return BisonParser::token::T_VAR;
                case ETOKEN_KW_VOID:        return BisonParser::token::T_VOID;
                case ETOKEN_KW_WHILE:       return BisonParser::token::T_WHILE;
                case ETOKEN_NUMBER_DOUBLE:  return BisonParser::token::T_DOUBLE_LIT;
                case ETOKEN_NUMBER_INT:     return BisonParser::token::T_INT_LIT;
                case ETOKEN_OP_ASSIGN:      return BisonParser::token::T_ASSIGN;
                case ETOKEN_OP_COMMA:       return ',';
                case ETOKEN_OP_GREATER:     return '>';
                case ETOKEN_OP_GREATER_EQ:  return BisonParser::token::T_GE;
                case ETOKEN_OP_LCBR:        return '{';
                case ETOKEN_OP_LESS:        return '<';
                case ETOKEN_OP_LESS_EQ:     return BisonParser::token::T_LE;
                case ETOKEN_OP_LPAR:        return '(';
                case ETOKEN_OP_MINUS:       return '-';
                case ETOKEN_OP_PLUS:        return '+';
                case ETOKEN_OP_RCBR:        return '}';
                case ETOKEN_OP_RPAR:        return ')';
                case ETOKEN_OP_SEMICOLON:   return ';';
                case ETOKEN_OP_SLASH:       return '/';
                case ETOKEN_OP_STAR:        return '*';
                case ETOKEN_STRING:         return BisonParser::token::T_STRING_LIT;
                default:
                    std::cerr << Error(E_WARNING, "yylex", "unhandled token", *token, true) << std::endl;
            }
        }
    }
}
 
int Parser::parse(IScanner *scanner, IBuilder *builder, std::string fileName) {
    IBisonListener *listener = new BisonListener(builder, fileName);
    yy::BisonParser *parser = new yy::BisonParser(scanner, listener, fileName);
#if 0
    parser->set_debug_level(1);
#endif
    int status = parser->parse();
 
    delete parser;
    delete listener;
    return status;
}