Cleaned up some debug messages, parseInput(string) now returns a parse tree of NodeTree*. This is done by having each non-terminal Symbol have it's own subtree and calling a method to combine subtrees and terminals on each reduce. The output is now the DOT version of the parse tree.
This commit is contained in:
@@ -10,9 +10,11 @@
|
|||||||
#include "Symbol.h"
|
#include "Symbol.h"
|
||||||
#include "State.h"
|
#include "State.h"
|
||||||
#include "StringReader.h"
|
#include "StringReader.h"
|
||||||
|
#include "NodeTree.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -29,7 +31,7 @@ class Parser {
|
|||||||
std::string stateSetToString();
|
std::string stateSetToString();
|
||||||
int gotoTable(int state, Symbol* token);
|
int gotoTable(int state, Symbol* token);
|
||||||
ParseAction* actionTable(int state, Symbol* token);
|
ParseAction* actionTable(int state, Symbol* token);
|
||||||
void parseInput(std::string inputString);
|
NodeTree* parseInput(std::string inputString);
|
||||||
|
|
||||||
std::string grammerToString();
|
std::string grammerToString();
|
||||||
std::string grammerToDOT();
|
std::string grammerToDOT();
|
||||||
@@ -46,6 +48,7 @@ class Parser {
|
|||||||
std::stack<Symbol*> symbolStack;
|
std::stack<Symbol*> symbolStack;
|
||||||
|
|
||||||
Symbol* getOrAddSymbol(std::string symbolString, bool isTerminal);
|
Symbol* getOrAddSymbol(std::string symbolString, bool isTerminal);
|
||||||
|
NodeTree* reduceTreeCombine(Symbol* newSymbol, std::vector<Symbol*> &symbols);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -5,18 +5,26 @@
|
|||||||
#define NULL 0
|
#define NULL 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "NodeTree.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class Symbol {
|
class Symbol {
|
||||||
public:
|
public:
|
||||||
Symbol(std::string name, bool isTerminal);
|
Symbol(std::string name, bool isTerminal);
|
||||||
|
Symbol(std::string name, bool isTerminal, NodeTree* tree);
|
||||||
~Symbol();
|
~Symbol();
|
||||||
bool const operator==(const Symbol &other);
|
bool const operator==(const Symbol &other);
|
||||||
std::string toString();
|
std::string toString();
|
||||||
|
Symbol* clone();
|
||||||
|
void setSubTree(NodeTree* tree);
|
||||||
|
NodeTree* getSubTree();
|
||||||
|
bool isTerminal();
|
||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
bool isTerminal;
|
bool terminal;
|
||||||
|
NodeTree* subTree;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
19
main.cpp
19
main.cpp
@@ -52,21 +52,26 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
Parser parser;
|
Parser parser;
|
||||||
parser.loadGrammer(grammerInputFileString);
|
parser.loadGrammer(grammerInputFileString);
|
||||||
std::cout << "Creating State Set from Main" << std::endl;
|
//std::cout << "Creating State Set from Main" << std::endl;
|
||||||
parser.createStateSet();
|
parser.createStateSet();
|
||||||
std::cout << "finished State Set from Main" << std::endl;
|
//std::cout << "finished State Set from Main" << std::endl;
|
||||||
std::cout << "Doing stateSetToString from Main" << std::endl;
|
//std::cout << "Doing stateSetToString from Main" << std::endl;
|
||||||
std::cout << parser.stateSetToString() << std::endl;
|
std::cout << parser.stateSetToString() << std::endl;
|
||||||
std::cout << "finished stateSetToString from Main" << std::endl;
|
//std::cout << "finished stateSetToString from Main" << std::endl;
|
||||||
|
|
||||||
std::cout << grammerInputFileString << std::endl;
|
std::cout << grammerInputFileString << std::endl;
|
||||||
std::cout << parser.grammerToString() << std::endl;
|
std::cout << parser.grammerToString() << std::endl;
|
||||||
std::cout << parser.grammerToDOT() << std::endl;
|
//std::cout << parser.grammerToDOT() << std::endl;
|
||||||
|
|
||||||
outFile << parser.grammerToDOT() << std::endl;
|
//outFile << parser.grammerToDOT() << std::endl;
|
||||||
|
|
||||||
std::cout << programInputFileString << std::endl;
|
std::cout << programInputFileString << std::endl;
|
||||||
parser.parseInput(programInputFileString);
|
NodeTree* parseTree = parser.parseInput(programInputFileString);
|
||||||
|
|
||||||
|
if (parseTree) {
|
||||||
|
std::cout << parseTree->DOTGraphString() << std::endl;
|
||||||
|
outFile << parseTree->DOTGraphString() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
programInFile.close();
|
programInFile.close();
|
||||||
grammerInFile.close();
|
grammerInFile.close();
|
||||||
|
|||||||
@@ -54,15 +54,15 @@ void Parser::loadGrammer(std::string grammerInputString) {
|
|||||||
void Parser::createStateSet() {
|
void Parser::createStateSet() {
|
||||||
std::cout << "Begining creation of stateSet" << std::endl;
|
std::cout << "Begining creation of stateSet" << std::endl;
|
||||||
stateSets.push_back( new State(0, loadedGrammer[0]) );
|
stateSets.push_back( new State(0, loadedGrammer[0]) );
|
||||||
std::cout << "Begining for main set for loop" << std::endl;
|
//std::cout << "Begining for main set for loop" << std::endl;
|
||||||
for (std::vector< State* >::size_type i = 0; i < stateSets.size(); i++) {
|
for (std::vector< State* >::size_type i = 0; i < stateSets.size(); i++) {
|
||||||
std::cout << "calling closure on " << stateSets[i]->toString() << std::endl;
|
//std::cout << "calling closure on " << stateSets[i]->toString() << std::endl;
|
||||||
closure(stateSets[i]);
|
closure(stateSets[i]);
|
||||||
std::cout << "finished closure" << std::endl;
|
//std::cout << "finished closure" << std::endl;
|
||||||
std::cout << "Starting inner for loop that adds states" << std::endl;
|
//std::cout << "Starting inner for loop that adds states" << std::endl;
|
||||||
std::vector<ParseRule*>* allRules = stateSets[i]->getTotal();
|
std::vector<ParseRule*>* allRules = stateSets[i]->getTotal();
|
||||||
for (std::vector<ParseRule*>::size_type j = 0; j < allRules->size(); j++) {
|
for (std::vector<ParseRule*>::size_type j = 0; j < allRules->size(); j++) {
|
||||||
std::cout << "about to call addState" << std::endl;
|
//std::cout << "about to call addState" << std::endl;
|
||||||
addState(&stateSets, stateSets[i], (*allRules)[j]->getAtNextIndex());
|
addState(&stateSets, stateSets[i], (*allRules)[j]->getAtNextIndex());
|
||||||
//Closure will be called in the outer loop
|
//Closure will be called in the outer loop
|
||||||
}
|
}
|
||||||
@@ -71,12 +71,12 @@ void Parser::createStateSet() {
|
|||||||
|
|
||||||
void Parser::closure(State* state) {
|
void Parser::closure(State* state) {
|
||||||
//Add all the applicable rules.
|
//Add all the applicable rules.
|
||||||
std::cout << "Closure on " << state->toString() << " is" << std::endl;
|
//std::cout << "Closure on " << state->toString() << " is" << std::endl;
|
||||||
for (std::vector<ParseRule*>::size_type i = 0; i < state->getTotal()->size(); i++) {
|
for (std::vector<ParseRule*>::size_type i = 0; i < state->getTotal()->size(); i++) {
|
||||||
for (std::vector<ParseRule*>::size_type j = 0; j < loadedGrammer.size(); j++) {
|
for (std::vector<ParseRule*>::size_type j = 0; j < loadedGrammer.size(); j++) {
|
||||||
//If the current symbol in the rule is not null (rule completed) and it equals a grammer's left side
|
//If the current symbol in the rule is not null (rule completed) and it equals a grammer's left side
|
||||||
if ((*state->getTotal())[i]->getAtNextIndex() != NULL && *((*state->getTotal())[i]->getAtNextIndex()) == *(loadedGrammer[j]->getLeftSide())) {
|
if ((*state->getTotal())[i]->getAtNextIndex() != NULL && *((*state->getTotal())[i]->getAtNextIndex()) == *(loadedGrammer[j]->getLeftSide())) {
|
||||||
std::cout << (*state->getTotal())[i]->getAtNextIndex()->toString() << " has an applicable production " << loadedGrammer[j]->toString() << std::endl;
|
//std::cout << (*state->getTotal())[i]->getAtNextIndex()->toString() << " has an applicable production " << loadedGrammer[j]->toString() << std::endl;
|
||||||
//Check to make sure not already in
|
//Check to make sure not already in
|
||||||
bool isAlreadyInState = false;
|
bool isAlreadyInState = false;
|
||||||
for (std::vector<ParseRule*>::size_type k = 0; k < state->getTotal()->size(); k++) {
|
for (std::vector<ParseRule*>::size_type k = 0; k < state->getTotal()->size(); k++) {
|
||||||
@@ -90,7 +90,7 @@ void Parser::closure(State* state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::cout << state->toString() << std::endl;
|
//std::cout << state->toString() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Adds state if it doesn't already exist.
|
//Adds state if it doesn't already exist.
|
||||||
@@ -188,7 +188,7 @@ ParseAction* Parser::actionTable(int state, Symbol* token) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//If the current rule in the state is not completed, see if it has the next correct token
|
//If the current rule in the state is not completed, see if it has the next correct token
|
||||||
std::cout << currentRule->getAtNextIndex()->toString() << " comp to " << token->toString() << std::endl;
|
//std::cout << currentRule->getAtNextIndex()->toString() << " comp to " << token->toString() << std::endl;
|
||||||
if ( *(currentRule->getAtNextIndex()) == *token){
|
if ( *(currentRule->getAtNextIndex()) == *token){
|
||||||
//If it does have the correct next token, then find the state that has this rule advanced as basis, that is the state we shift to
|
//If it does have the correct next token, then find the state that has this rule advanced as basis, that is the state we shift to
|
||||||
//Goes to n^2 here, really need that table
|
//Goes to n^2 here, really need that table
|
||||||
@@ -207,10 +207,10 @@ ParseAction* Parser::actionTable(int state, Symbol* token) {
|
|||||||
return new ParseAction(ParseAction::REJECT);
|
return new ParseAction(ParseAction::REJECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Parser::parseInput(std::string inputString) {
|
NodeTree* Parser::parseInput(std::string inputString) {
|
||||||
StringReader inputReader;
|
StringReader inputReader;
|
||||||
inputReader.setString(inputString);
|
inputReader.setString(inputString);
|
||||||
Symbol* token = new Symbol(inputReader.word(), true);
|
Symbol* token = new Symbol("\""+inputReader.word()+"\"", true);
|
||||||
ParseAction* action;
|
ParseAction* action;
|
||||||
|
|
||||||
stateStack.push(0);
|
stateStack.push(0);
|
||||||
@@ -222,33 +222,51 @@ void Parser::parseInput(std::string inputString) {
|
|||||||
case ParseAction::REDUCE:
|
case ParseAction::REDUCE:
|
||||||
{
|
{
|
||||||
int rightSideLength = action->reduceRule->getRightSide().size();
|
int rightSideLength = action->reduceRule->getRightSide().size();
|
||||||
|
//Keep track of symbols popped for parse tree
|
||||||
|
std::vector<Symbol*> poppedSymbols;
|
||||||
for (int i = 0; i < rightSideLength; i++) {
|
for (int i = 0; i < rightSideLength; i++) {
|
||||||
|
poppedSymbols.push_back(symbolStack.top());
|
||||||
stateStack.pop();
|
stateStack.pop();
|
||||||
symbolStack.pop();
|
symbolStack.pop();
|
||||||
}
|
}
|
||||||
symbolStack.push(action->reduceRule->getLeftSide());
|
std::reverse(poppedSymbols.begin(), poppedSymbols.end()); //To put in order
|
||||||
|
//Assign the new tree to the new Symbol
|
||||||
|
Symbol* newSymbol = action->reduceRule->getLeftSide()->clone();
|
||||||
|
newSymbol->setSubTree(reduceTreeCombine(newSymbol, poppedSymbols));
|
||||||
|
symbolStack.push(newSymbol);
|
||||||
stateStack.push(gotoTable(stateStack.top(), symbolStack.top()));
|
stateStack.push(gotoTable(stateStack.top(), symbolStack.top()));
|
||||||
std::cout << "Reduce by " << action->reduceRule->toString() << std::endl;
|
std::cout << "Reduce by " << action->reduceRule->toString() << std::endl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ParseAction::SHIFT:
|
case ParseAction::SHIFT:
|
||||||
symbolStack.push(token);
|
symbolStack.push(token);
|
||||||
token = new Symbol(inputReader.word(), true);
|
token = new Symbol("\""+inputReader.word()+"\"", true);
|
||||||
stateStack.push(action->shiftState);
|
stateStack.push(action->shiftState);
|
||||||
std::cout << "Shift " << symbolStack.top()->toString() << std::endl;
|
std::cout << "Shift " << symbolStack.top()->toString() << std::endl;
|
||||||
break;
|
break;
|
||||||
case ParseAction::ACCEPT:
|
case ParseAction::ACCEPT:
|
||||||
std::cout << "ACCEPTED!" << std::endl;
|
std::cout << "ACCEPTED!" << std::endl;
|
||||||
return;
|
return(symbolStack.top()->getSubTree());
|
||||||
break;
|
break;
|
||||||
case ParseAction::REJECT:
|
case ParseAction::REJECT:
|
||||||
std::cout << "REJECTED!" << std::endl;
|
std::cout << "REJECTED!" << std::endl;
|
||||||
return;
|
return(NULL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NodeTree* Parser::reduceTreeCombine(Symbol* newSymbol, std::vector<Symbol*> &symbols) {
|
||||||
|
NodeTree* newTree = new NodeTree(newSymbol->toString());
|
||||||
|
for (std::vector<Symbol*>::size_type i = 0; i < symbols.size(); i++) {
|
||||||
|
if (symbols[i]->isTerminal())
|
||||||
|
newTree->addChild(new NodeTree(symbols[i]->toString()));
|
||||||
|
else
|
||||||
|
newTree->addChild(symbols[i]->getSubTree());
|
||||||
|
}
|
||||||
|
return(newTree);
|
||||||
|
}
|
||||||
|
|
||||||
std::string Parser::grammerToString() {
|
std::string Parser::grammerToString() {
|
||||||
//Iterate through the vector, adding string representation of each grammer rule
|
//Iterate through the vector, adding string representation of each grammer rule
|
||||||
std::cout << "About to toString\n";
|
std::cout << "About to toString\n";
|
||||||
@@ -261,7 +279,7 @@ std::string Parser::grammerToString() {
|
|||||||
|
|
||||||
std::string Parser::grammerToDOT() {
|
std::string Parser::grammerToDOT() {
|
||||||
//Iterate through the vector, adding DOT representation of each grammer rule
|
//Iterate through the vector, adding DOT representation of each grammer rule
|
||||||
std::cout << "About to DOT export\n";
|
//std::cout << "About to DOT export\n";
|
||||||
std::string concat = "";
|
std::string concat = "";
|
||||||
for (int i = 0; i < loadedGrammer.size(); i++) {
|
for (int i = 0; i < loadedGrammer.size(); i++) {
|
||||||
concat += loadedGrammer[i]->toDOT();
|
concat += loadedGrammer[i]->toDOT();
|
||||||
|
|||||||
@@ -2,7 +2,14 @@
|
|||||||
|
|
||||||
Symbol::Symbol(std::string name, bool isTerminal) {
|
Symbol::Symbol(std::string name, bool isTerminal) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
this->isTerminal = isTerminal;
|
this->terminal = isTerminal;
|
||||||
|
this->subTree = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol::Symbol(std::string name, bool isTerminal, NodeTree* tree) {
|
||||||
|
this->name = name;
|
||||||
|
this->terminal = isTerminal;
|
||||||
|
this->subTree = tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol::~Symbol() {
|
Symbol::~Symbol() {
|
||||||
@@ -10,10 +17,26 @@ Symbol::~Symbol() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const bool Symbol::operator==(const Symbol &other) {
|
const bool Symbol::operator==(const Symbol &other) {
|
||||||
return( name == other.name && isTerminal == other.isTerminal);
|
return( name == other.name && terminal == other.terminal);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Symbol::toString() {
|
std::string Symbol::toString() {
|
||||||
return(name + "(" + (isTerminal ? "T" : "NT") + ")");
|
return(name); //+ "(" + (terminal ? "T" : "NT") + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol* Symbol::clone() {
|
||||||
|
return new Symbol(name, terminal, subTree);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Symbol::setSubTree(NodeTree* tree) {
|
||||||
|
subTree = tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeTree* Symbol::getSubTree() {
|
||||||
|
return subTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Symbol::isTerminal() {
|
||||||
|
return terminal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user