compiler / LR1.cc
LR1.cc
Raw
#include "LR1.h"
#include <iostream>
#include <utility>
#include <sstream>
#include <fstream>
using std::string; 
using std::pair;

LR1Node::LR1Node(string s): s(s) {}

LR1Node::~LR1Node() {
    for (auto child : children) {
        delete child;
    }
}

void LR1Node::addchild(LR1Node *child) {
    children.push_back(child);
}

void LR1Node::addToVector(std::vector<string> &v) {
    v.push_back(s);
    for (auto child : children) {
        child->addToVector(v);
    }
}

LR1::LR1() {
    stateStack.push_back(0);
}

LR1::~LR1() {
    for (auto node : TreeStack) {
        delete node;
    }
}

ParsingFailure::ParsingFailure(int prefix):
  prefix(prefix) {}

const string ParsingFailure::what() const { return std::to_string(prefix + 1); }

void LR1::initialize() {
    parseFile.open("parse.txt");
    int numTerm, numNonTerm, numRules, numShiftReduce;
    string line;

    // read the number of terminals and move to the next line
    parseFile >> numTerm;
    term(numTerm);

    // read the number of non-terminals and move to the next line
    parseFile >> numNonTerm;
    nonTerm(numNonTerm);

    // read start symbol
    startSym();

    // read the number of rules and move to the next line
    parseFile >> numRules;
    std::getline(parseFile, line); // clear line
    addRules(numRules);

    // read number of states
    statesNum();

    // read shift reduce rules
    parseFile >> numShiftReduce;
    std::getline(parseFile, line); // clear line
    shiftReduceRules(numShiftReduce);

    parseFile.close();
}

void LR1::term(int in) {
    string t;
    for (int i = 0; i < in; i++) {
        parseFile >> t;
        symbols.push_back(t);
        terminals.push_back(t);
    }
}

void LR1::nonTerm(int in) {
    string t;
    for (int i = 0; i < in; i++) {
        parseFile >> t;
        symbols.push_back(t);
        nonTerminals.push_back(t);
    }
}

void LR1::startSym() {
    parseFile >> start;
}

void LR1::addRules(int in) {
    string r;
    for (int i = 0; i < in; i++) {
        std::getline(parseFile, r);
        rules.push_back(r);
    }
}

void LR1::statesNum() {
    int n;
    parseFile >> n;
    states = n;
    reduceRules.resize(states);
    shiftRules.resize(states);
}

void LR1::shiftReduceRules(int in) {
    string r;
    for (int i = 0; i < in; i++) {
        std::getline(parseFile, r);
        std::istringstream iss (r);
        int initialState, nextState;
        string terminal, action;
        iss >> initialState;
        iss >> terminal;
        iss >> action;
        iss >> nextState;
        pair<int, string> lookahead = std::make_pair(initialState, terminal);
        pair<pair<int, string>, int> rule = std::make_pair(lookahead, nextState);
        if (action == "reduce") {
            reduceRules[initialState].push_back(rule);
        } else if (action == "shift") {
            shiftRules[initialState].push_back(rule);
        }
    }
}

int LR1::shift(string in) {
    int state = stateStack.back();
    pair<int, string> top = std::make_pair(state, in);
    for (auto rule : shiftRules[state]) {
        if (rule.first == top) {
            return rule.second;
        }
    }
    return states + 1;
}

bool LR1::parseUtil(string in) {
    while (true) {
        // check reduce rules for in
        int state = stateStack.back();
        pair<int, string> top = std::make_pair(state, in);
        bool reduced = false;
        for (auto rule : reduceRules[state]) {
            if (rule.first == top) {
                string reduceRule = rules[rule.second];
                int nRight = 0;
                for (auto c : reduceRule) {
                    if (c == ' ') {
                        nRight++;
                    }
                }
                LR1Node *reduce = new LR1Node(reduceRule);
                std::istringstream iss (reduceRule);
                string leftHand, rightHand;
                iss >> leftHand;
                for (int i = nRight; i > 0; i--) {
                    iss >> rightHand;
                    string sym = symStack[symStack.size() - i];
                    if (sym != rightHand) {
                        delete reduce;
                        return false;
                    }
                    symStack.erase(symStack.begin() + (symStack.size() - i));
                    reduce->addchild(TreeStack[TreeStack.size() - i]);
                    TreeStack.erase(TreeStack.begin() + (TreeStack.size() - i));
                    stateStack.pop_back();
                }
                symStack.push_back(leftHand);
                int shifted = shift(leftHand);
                if (shifted > states) {
                    delete reduce;
                    return false;
                }
                TreeStack.push_back(reduce);
                stateStack.push_back(shifted);
                reduced = true;
                break;
            }
        }
        if (!reduced) { break; }
    }
    symStack.push_back(in);
    int shifted = shift(in);
    if (shifted > states) {
        return false;
    }
    stateStack.push_back(shifted);
    return true;
}

void LR1::parse(std::vector<string> &tokens) {
    string in;
    int i = 0;
    parseUtil("BOF");
    LR1Node *bof = new LR1Node("BOF BOF");
    TreeStack.push_back(bof);
    while (tokens.size() != 0) {
        in = tokens.front();
        tokens.erase(tokens.begin());
        std::istringstream iss (in);
        string token;
        iss >> token;
        bool check = parseUtil(token);
        if (!check) {
            throw ParsingFailure(i);
        }
        LR1Node *terminal = new LR1Node(in);
        TreeStack.push_back(terminal);
        i++;
    }
    parseUtil("EOF");
    LR1Node *eof = new LR1Node("EOF EOF");
    TreeStack.push_back(eof);

    std::istringstream rule (rules[0]);
    string rightHand;
    rule >> rightHand;
    LR1Node *s = new LR1Node(rules[0]);
    for (int n = 3; n > 0; n--) {
        rule >> rightHand;
        string sym = symStack[symStack.size() - n];
        if (sym != rightHand) {
            delete s;
            throw ParsingFailure(i);
        }
        s->addchild(TreeStack[TreeStack.size() - n]);
        TreeStack.erase(TreeStack.begin() + (TreeStack.size() - n));
    }
    TreeStack.push_back(s);
}

std::vector<string> LR1::generate() {
    std::vector<string> nodeVector;
    for (auto s : TreeStack) {
        s->addToVector(nodeVector);
    }
    return nodeVector;
}