From 03770028ad25acbe94f5138eab73623137dd6dcc Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Mon, 30 Jun 2014 01:57:50 -0700 Subject: [PATCH] Fixed some bugs in Parser::firstSet and added a bit of caching. It still doesn't work quite right, though, there's some problem with nullable left recursion. However, it's better than it was, and I need to go to bed. More work later. --- include/GraphStructuredStack.h | 1 + include/ParseAction.h | 12 +++-- include/ParseRule.h | 12 ++--- include/Parser.h | 12 +++-- include/RNGLRParser.h | 3 ++ include/Table.h | 6 ++- src/GraphStructuredStack.cpp | 7 +++ src/Importer.cpp | 7 ++- src/ParseAction.cpp | 29 +++++++--- src/ParseRule.cpp | 26 +++++++-- src/Parser.cpp | 88 ++++++++++++++++++------------- src/RNGLRParser.cpp | 36 ++++++++++--- src/Table.cpp | 15 +++++- stdlib/io.krak | 10 ++-- stdlib/mem.krak | 6 +++ stdlib/util.krak | 12 +++++ stdlib/vector.krak | 52 ++++++++++++++++++ tests/vectorTest.expected_results | 2 + tests/vectorTest.krak | 15 ++++++ 19 files changed, 273 insertions(+), 78 deletions(-) create mode 100644 stdlib/util.krak create mode 100644 stdlib/vector.krak create mode 100644 tests/vectorTest.expected_results create mode 100644 tests/vectorTest.krak diff --git a/include/GraphStructuredStack.h b/include/GraphStructuredStack.h index e79a8fe..7d07443 100644 --- a/include/GraphStructuredStack.h +++ b/include/GraphStructuredStack.h @@ -27,6 +27,7 @@ class GraphStructuredStack { void addEdge(NodeTree* start, NodeTree* end, NodeTree* edge); void clear(); + std::vector getFrontier(int frontier); std::string toString(); private: std::vector*>*> gss; diff --git a/include/ParseAction.h b/include/ParseAction.h index 175dd61..a15aca0 100644 --- a/include/ParseAction.h +++ b/include/ParseAction.h @@ -11,6 +11,7 @@ #include #include + class ParseAction { public: enum ActionType { INVALID, REDUCE, SHIFT, ACCEPT, REJECT }; @@ -18,10 +19,11 @@ class ParseAction { ParseAction(ActionType action, ParseRule* reduceRule); ParseAction(ActionType action, int shiftState); ~ParseAction(); - bool const equalsExceptLookahead(const ParseAction &other); - bool const operator==(const ParseAction &other); - bool const operator!=(const ParseAction &other); - std::string toString(); + bool const equalsExceptLookahead(const ParseAction &other) const; + bool const operator==(const ParseAction &other) const; + bool const operator!=(const ParseAction &other) const; + bool const operator<(const ParseAction &other) const; + std::string toString(bool printRuleLookahead = true); static std::string actionToString(ActionType action); ActionType action; @@ -31,4 +33,4 @@ class ParseAction { }; -#endif \ No newline at end of file +#endif diff --git a/include/ParseRule.h b/include/ParseRule.h index dd3ac37..94d602a 100644 --- a/include/ParseRule.h +++ b/include/ParseRule.h @@ -16,10 +16,10 @@ class ParseRule { ParseRule(); ParseRule(Symbol leftHandle, int pointerIndex, std::vector &rightSide, std::vector* lookahead); ~ParseRule(); - const bool equalsExceptLookahead(const ParseRule &other); - bool const operator==(const ParseRule &other); - bool const operator!=(const ParseRule &other); - + const bool equalsExceptLookahead(const ParseRule &other) const; + bool const operator==(const ParseRule &other) const; + bool const operator!=(const ParseRule &other) const; + bool const operator<(const ParseRule &other) const; //Used for ordering so we can put ParseRule's in sets, and also so that ParseActions will have an ordering ParseRule* clone(); void setLeftHandle(Symbol leftHandle); @@ -40,7 +40,7 @@ class ParseRule { void addLookahead(std::vector* lookahead); std::vector* getLookahead(); - std::string toString(); + std::string toString(bool printLookahead = true); std::string toDOT(); private: @@ -51,4 +51,4 @@ class ParseRule { }; -#endif \ No newline at end of file +#endif diff --git a/include/Parser.h b/include/Parser.h index 6f1cc49..25daf02 100644 --- a/include/Parser.h +++ b/include/Parser.h @@ -12,6 +12,7 @@ #include "Table.h" #include +#include #include #include #include @@ -36,8 +37,13 @@ class Parser { void importTable(char* tableData); protected: - std::vector* firstSet(Symbol token); - std::vector* firstSet(Symbol token, std::vector avoidList); + std::vector firstSet(Symbol token, std::vector avoidList = std::vector(), bool addNewTokens = true); + bool isNullable(Symbol token); + bool isNullableHelper(Symbol token, std::set done); + + std::map> tokenFirstSet; + std::map tokenNullable; + std::vector* incrementiveFollowSet(ParseRule* rule); virtual void closure(State* state); virtual void addStates(std::vector< State* >* stateSets, State* state, std::queue* toDo); @@ -65,4 +71,4 @@ class Parser { NodeTree* reduceTreeCombine(Symbol newSymbol, std::vector &symbols); }; -#endif \ No newline at end of file +#endif diff --git a/include/RNGLRParser.h b/include/RNGLRParser.h index 6b285e7..74c47ef 100644 --- a/include/RNGLRParser.h +++ b/include/RNGLRParser.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include "Parser.h" #include "Symbol.h" @@ -16,6 +18,7 @@ class RNGLRParser: public Parser { RNGLRParser(); ~RNGLRParser(); NodeTree* parseInput(std::string inputString); + void printReconstructedFrontier(int frontier); private: void reducer(int i); diff --git a/include/Table.h b/include/Table.h index 6b8ce88..ca2ace9 100644 --- a/include/Table.h +++ b/include/Table.h @@ -1,5 +1,8 @@ #include +#include +#include + #include "util.h" #include "ParseRule.h" #include "ParseAction.h" @@ -20,7 +23,8 @@ class Table { void remove(int stateNum, Symbol tranSymbol); std::vector* get(int state, Symbol token); ParseAction* getShift(int state, Symbol token); - std::string toString(); + std::vector> stateAsParseActionVector(int state); + std::string toString(); private: std::vector< std::vector< std::vector* >* > table; std::vector symbolIndexVec; diff --git a/src/GraphStructuredStack.cpp b/src/GraphStructuredStack.cpp index dcdf2ff..1d117f3 100644 --- a/src/GraphStructuredStack.cpp +++ b/src/GraphStructuredStack.cpp @@ -117,6 +117,13 @@ void GraphStructuredStack::addEdge(NodeTree* start, NodeTree* end, Nod edges[std::make_pair(start, end)] = edge; } +std::vector GraphStructuredStack::getFrontier(int frontier) { + std::vector toReturn; + for (int i = 0; i < gss[frontier]->size(); i++) + toReturn.push_back((*(gss[frontier]))[i]->getData()); + return toReturn; +} + std::string GraphStructuredStack::toString() { std::string tostring = ""; for (std::vector*>*>::size_type i = 0; i < gss.size(); i++) { diff --git a/src/Importer.cpp b/src/Importer.cpp index fb45a03..1706e5b 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -66,7 +66,8 @@ NodeTree* Importer::importFirstPass(std::string fileName) { NodeTree* ast = getUnit(fileName); if (ast == NULL) { NodeTree* parseTree = parseAndTrim(fileName); - + if (!parseTree) + return NULL; //Call with ourself to allow the transformation to call us to import files that it needs ast = ASTTransformer->firstPass(fileName, parseTree); //This firstPass will register itself } @@ -160,7 +161,9 @@ NodeTree* Importer::parseAndTrim(std::string fileName) { outFile << parseTree->DOTGraphString() << std::endl; } else { std::cout << "ParseTree returned from parser for " << fileName << " is NULL!" << std::endl; - } + outFile.close(); outFileTransformed.close(); + return NULL; + } outFile.close(); //Remove Transformations diff --git a/src/ParseAction.cpp b/src/ParseAction.cpp index 64f3e95..1e21714 100644 --- a/src/ParseAction.cpp +++ b/src/ParseAction.cpp @@ -22,18 +22,33 @@ ParseAction::~ParseAction() { } -const bool ParseAction::equalsExceptLookahead(const ParseAction &other) { +const bool ParseAction::equalsExceptLookahead(const ParseAction &other) const { return( action == other.action && ( reduceRule == other.reduceRule || reduceRule->equalsExceptLookahead(*(other.reduceRule)) ) && shiftState == other.shiftState); } -const bool ParseAction::operator==(const ParseAction &other) { +const bool ParseAction::operator==(const ParseAction &other) const { return( action == other.action && ( reduceRule == other.reduceRule || *reduceRule == *(other.reduceRule) ) && shiftState == other.shiftState); } -const bool ParseAction::operator!=(const ParseAction &other) { +const bool ParseAction::operator!=(const ParseAction &other) const { return !(this->operator==(other)); } +//Exists so we can put ParseActions into sets +const bool ParseAction::operator<(const ParseAction &other) const { + if (action != other.action) + return action < other.action; + if (reduceRule != other.reduceRule) { + if (! (reduceRule && other.reduceRule)) { + return reduceRule < other.reduceRule; + } else { + return *reduceRule < *(other.reduceRule); + } + } + + return shiftState < other.shiftState; +} + std::string ParseAction::actionToString(ActionType action) { switch (action) { case REDUCE: @@ -53,12 +68,12 @@ std::string ParseAction::actionToString(ActionType action) { } } -std::string ParseAction::toString() { +std::string ParseAction::toString(bool printRuleLookahead) { std::string outputString = ""; outputString += actionToString(action); if (reduceRule != NULL) - outputString += " " + reduceRule->toString(); + outputString += " " + reduceRule->toString(printRuleLookahead); if (shiftState != -1) - outputString += " " + intToString(shiftState); + outputString += " " + intToString(shiftState); return(outputString); -} \ No newline at end of file +} diff --git a/src/ParseRule.cpp b/src/ParseRule.cpp index e27208a..2b8996c 100644 --- a/src/ParseRule.cpp +++ b/src/ParseRule.cpp @@ -16,18 +16,34 @@ ParseRule::~ParseRule() { } -const bool ParseRule::equalsExceptLookahead(const ParseRule &other) { +const bool ParseRule::equalsExceptLookahead(const ParseRule &other) const { return(leftHandle == other.leftHandle && rightSide == other.rightSide && pointerIndex == other.pointerIndex); } -const bool ParseRule::operator==(const ParseRule &other) { +const bool ParseRule::operator==(const ParseRule &other) const { return(equalsExceptLookahead(other) && (lookahead == NULL ? other.lookahead == NULL : (*lookahead) == *(other.lookahead))); } -const bool ParseRule::operator!=(const ParseRule &other) { +const bool ParseRule::operator!=(const ParseRule &other) const { return !(this->operator==(other)); } +const bool ParseRule::operator<(const ParseRule &other) const { + //Used for ordering so we can put ParseRule's in sets, and also so that ParseActions will have an ordering + if (leftHandle != other.leftHandle) + return leftHandle < other.leftHandle; + if (rightSide != other.rightSide) + return rightSide < other.rightSide; + if (lookahead != other.lookahead) { + if (! (lookahead && other.lookahead)) { + return lookahead < other.lookahead; + } else { + return *lookahead < *(other.lookahead); + } + } + return false; +} + ParseRule* ParseRule::clone() { std::vector* newLookahead = NULL; if (lookahead) { @@ -111,7 +127,7 @@ std::vector* ParseRule::getLookahead() { return lookahead; } -std::string ParseRule::toString() { +std::string ParseRule::toString(bool printLookahead) { std::string concat = leftHandle.toString() + " -> "; for (int i = 0; i < rightSide.size(); i++) { if (i == pointerIndex) @@ -120,7 +136,7 @@ std::string ParseRule::toString() { } if (pointerIndex >= rightSide.size()) concat += "(*)"; - if (lookahead != NULL) { + if (printLookahead && lookahead != NULL) { concat += "**"; for (std::vector::size_type i = 0; i < lookahead->size(); i++) concat += (*lookahead)[i].toString(); diff --git a/src/Parser.cpp b/src/Parser.cpp index 5971829..524b888 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -117,59 +117,76 @@ int Parser::stateNum(State* state) { return -1; } -std::vector* Parser::firstSet(Symbol token) { - std::vector avoidList; - return firstSet(token, avoidList); -} - -std::vector* Parser::firstSet(Symbol token, std::vector avoidList) { - //If we've already done this token, don't do it again +std::vector Parser::firstSet(Symbol token, std::vector avoidList, bool addNewTokens) { + if (tokenFirstSet.find(token) != tokenFirstSet.end()) + return tokenFirstSet[token]; + //If we've already done this token, don't do it again for (std::vector::size_type i = 0; i < avoidList.size(); i++) - if (avoidList[i] == token) { - return new std::vector(); - } + if (avoidList[i] == token) + return std::vector(); avoidList.push_back(token); - std::vector* first = new std::vector(); + + std::vector first; //First, if the symbol is a terminal, than it's first set is just itself. if (token.isTerminal()) { - first->push_back(token); + first.push_back(token); return(first); } //Otherwise.... //Ok, to make a first set, go through the grammer, if the token it's left side, add it's production's first token's first set. //If that one includes mull, do the next one too (if it exists). Symbol rightToken; - std::vector* recursiveFirstSet = NULL; + std::vector recursiveFirstSet; for (std::vector::size_type i = 0; i < loadedGrammer.size(); i++) { if (token == loadedGrammer[i]->getLeftSide()) { //Loop through the rule adding first sets for each token if the previous token contained NULL - bool recFirstSetHasNull = false; int j = 0; do { rightToken = loadedGrammer[i]->getRightSide()[j]; //Get token of the right side of this rule if (rightToken.isTerminal()) { - recursiveFirstSet = new std::vector(); - recursiveFirstSet->push_back(rightToken); + recursiveFirstSet.push_back(rightToken); } else { //Add the entire set - recursiveFirstSet = firstSet(rightToken, avoidList); + recursiveFirstSet = firstSet(rightToken, avoidList, false);//Don't add children to cache, as early termination may cause them to be incomplete } - first->insert(first->end(), recursiveFirstSet->begin(), recursiveFirstSet->end()); - //Check to see if the current recursiveFirstSet contains NULL, if so, then go through again with the next token. (if there is one) - recFirstSetHasNull = false; - for (std::vector::size_type k = 0; k < recursiveFirstSet->size(); k++) { - if ((*recursiveFirstSet)[k] == nullSymbol) { - recFirstSetHasNull = true; - } - } - delete recursiveFirstSet; + first.insert(first.end(), recursiveFirstSet.begin(), recursiveFirstSet.end()); j++; - } while (recFirstSetHasNull && loadedGrammer[i]->getRightSide().size() > j); + } while (isNullable(rightToken) && loadedGrammer[i]->getRightSide().size() > j); } } + if (addNewTokens) + tokenFirstSet[token] = first; return(first); } +bool Parser::isNullable(Symbol token) { + if (tokenNullable.find(token) != tokenNullable.end()) + return tokenNullable[token]; + bool nullable = isNullableHelper(token, std::set()); + tokenNullable[token] = nullable; + return nullable; +} +//We use this helper function to recurse because it is possible to wind up with loops, and if so we want +//early termination. However, this means that nullable determinations in the middle of the loop are inaccurate +//(since we terminated early), so we don't want to save them. Thus, for simplicity, only the main method will +//add to the cache. This is somewhat unfortunate for preformance, but the necessary additions to keep track of +//invalidated state are more complicated than it's worth. +bool Parser::isNullableHelper(Symbol token, std::set done) { + if (token.isTerminal()) + return token == nullSymbol; + if (done.find(token) != done.end()) + return false; + done.insert(token); + if (tokenNullable.find(token) != tokenNullable.end()) + return tokenNullable[token]; + //Note that we only have to check the first token on the right side, as we would only get to the other tokens if it is nullable, which is what we're checking + for (std::vector::size_type i = 0; i < loadedGrammer.size(); i++) + if (token == loadedGrammer[i]->getLeftSide()) + if (isNullableHelper(loadedGrammer[i]->getRightSide()[0], done)) + return true; + return false; +} + //Return the correct lookahead. This followSet is built based on the current rule's lookahead if at end, or the next Symbol's first set. std::vector* Parser::incrementiveFollowSet(ParseRule* rule) { //Advance the pointer past the current Symbol (the one we want the followset for) to the next symbol (which might be in our follow set, or might be the end) @@ -178,25 +195,24 @@ std::vector* Parser::incrementiveFollowSet(ParseRule* rule) { //Get the first set of the next Symbol. If it contains nullSymbol, keep doing for the next one std::vector* followSet = new std::vector(); - std::vector* symbolFirstSet; + std::vector symbolFirstSet; bool symbolFirstSetHasNull = true; while (symbolFirstSetHasNull && !rule->isAtEnd()) { symbolFirstSetHasNull = false; symbolFirstSet = firstSet(rule->getAtNextIndex()); - for (std::vector::size_type i = 0; i < symbolFirstSet->size(); i++) { - if ((*symbolFirstSet)[i] == nullSymbol) { + for (std::vector::size_type i = 0; i < symbolFirstSet.size(); i++) { + if (symbolFirstSet[i] == nullSymbol) { symbolFirstSetHasNull = true; - symbolFirstSet->erase(symbolFirstSet->begin()+i); + symbolFirstSet.erase(symbolFirstSet.begin()+i); break; } } - followSet->insert(followSet->end(), symbolFirstSet->begin(), symbolFirstSet->end()); - delete symbolFirstSet; + followSet->insert(followSet->end(), symbolFirstSet.begin(), symbolFirstSet.end()); rule->advancePointer(); } if (rule->isAtEnd()) { - symbolFirstSet = rule->getLookahead(); - followSet->insert(followSet->end(), symbolFirstSet->begin(), symbolFirstSet->end()); + symbolFirstSet = *(rule->getLookahead()); + followSet->insert(followSet->end(), symbolFirstSet.begin(), symbolFirstSet.end()); } std::vector* followSetReturn = new std::vector(); for (std::vector::size_type i = 0; i < followSet->size(); i++) { @@ -261,7 +277,7 @@ void Parser::addStates(std::vector< State* >* stateSets, State* state, std::queu //Clone the current rule ParseRule* advancedRule = (*currStateTotal)[i]->clone(); //Try to advance the pointer, if sucessful see if it is the correct next symbol - if (advancedRule->advancePointer()) { + if (advancedRule->advancePointer()) { //Technically, it should be the set of rules sharing this symbol advanced past in the basis for new state //So search our new states to see if any of them use this advanced symbol as a base. diff --git a/src/RNGLRParser.cpp b/src/RNGLRParser.cpp index cbd111f..8495042 100644 --- a/src/RNGLRParser.cpp +++ b/src/RNGLRParser.cpp @@ -8,6 +8,20 @@ RNGLRParser::~RNGLRParser() { // } +void RNGLRParser::printReconstructedFrontier(int frontier) { + std::vector lastFrontier = gss.getFrontier(frontier); + for (int j = 0; j < lastFrontier.size(); j++) { + std::cout << "State: " << lastFrontier[j] << std::endl; + std::vector> stateParseActions = table.stateAsParseActionVector(lastFrontier[j]); + std::set> noRepeats; + for (auto k : stateParseActions) + noRepeats.insert(k); + for (auto k : noRepeats) + std::cout << k.first << " " << k.second.toString(false) << std::endl; + std::cout << std::endl; + } +} + NodeTree* RNGLRParser::parseInput(std::string inputString) { input.clear(); gss.clear(); @@ -53,7 +67,7 @@ NodeTree* RNGLRParser::parseInput(std::string inputString) { // std::cout << "\nDone with Lexing, length:" << input.size() << std::endl; // std::cout << input[0].toString() << std::endl; - + // for (int i = 0; i < input.size(); i++) // std::cout << "|" << input[i]->toString() << "|"; // std::cout << std::endl; @@ -74,7 +88,6 @@ NodeTree* RNGLRParser::parseInput(std::string inputString) { else if (firstActions[i]->action == ParseAction::REDUCE && fullyReducesToNull(firstActions[i]->reduceRule)) { Reduction newReduction = {v0, firstActions[i]->reduceRule->getLeftSide(), 0, getNullableParts(firstActions[i]->reduceRule), NULL}; toReduce.push(newReduction); - //toReduce.push(std::make_pair(std::make_pair(v0, firstActions[i]->reduceRule->getLeftSide()), 0)); } } @@ -89,14 +102,21 @@ NodeTree* RNGLRParser::parseInput(std::string inputString) { std::cout << "Parsing failed on " << input[i].toString() << std::endl; std::cout << "Problem is on line: " << findLine(i) << std::endl; std::cout << "Nearby is:" << std::endl; - const int range = 10; + int range = 10; for (int j = (i-range >= 0 ? i-range : 0); j < (i+range < input.size() ? i+range : input.size()); j++) if (j == i) std::cout << "||*||*||" << input[j].toString() << "||*||*|| "; else std::cout << input[j].toString() << " "; std::cout << std::endl; - break; + range = 3; + std::cout << "\n\n\nThe states in the GSS at last frontiers:" << std::endl; + for (int j = (i-range >= 0 ? i-range : 0); j < i; j++) { + std::cout << "Frontier:" << j << " (would get): " << input[j].toString() << std::endl; + printReconstructedFrontier(j); + } + std::cout << "\n\n\n\n" << std::endl; + break; } //Clear the vector of SPPF nodes created every step @@ -186,7 +206,7 @@ void RNGLRParser::reducer(int i) { toStateNode = gss.newNode(toState); gss.addToFrontier(i, toStateNode); gss.addEdge(toStateNode, currentReached, newLabel); - + //std::cout << "Adding shifts and reductions for a state that did not exist" << std::endl; std::vector actions = *(table.get(toState, input[i])); for (std::vector::size_type k = 0; k < actions.size(); k++) { @@ -319,7 +339,7 @@ void RNGLRParser::addStates(std::vector< State* >* stateSets, State* state, std: //Clone the current rule ParseRule* advancedRule = (*currStateTotal)[i]->clone(); //Try to advance the pointer, if sucessful see if it is the correct next symbol - if (advancedRule->advancePointer()) { + if (advancedRule->advancePointer()) { //Technically, it should be the set of rules sharing this symbol advanced past in the basis for new state //So search our new states to see if any of them use this advanced symbol as a base. @@ -353,10 +373,10 @@ void RNGLRParser::addStates(std::vector< State* >* stateSets, State* state, std: stateAlreadyInAllStates = true; //If it does exist, we should add it as the shift/goto in the action table //std::cout << "newStates[" << i << "] == stateSets[" << j << "]" << std::endl; - + if (!((*stateSets)[j]->basisEquals(*(newStates[i])))) toDo->push((*stateSets)[j]); - + (*stateSets)[j]->combineStates(*(newStates[i])); //std::cout << j << "\t Hay, doing an inside loop state reductions!" << std::endl; addStateReductionsToTable((*stateSets)[j]); diff --git a/src/Table.cpp b/src/Table.cpp index 5f37e1f..e4cdfd4 100644 --- a/src/Table.cpp +++ b/src/Table.cpp @@ -251,7 +251,7 @@ void Table::add(int stateNum, Symbol tranSymbol, ParseAction* action) { //If this table slot is empty //std::cout << "table[stateNum] is " << table[stateNum] << std::endl; //std::cout << "blank is " << (*(table[stateNum]))[symbolIndex] << std::endl; - + if ( (*(table[stateNum]))[symbolIndex] == NULL ) { //std::cout << "Null, adding " << action->toString() << std::endl; std::vector* actionList = new std::vector(); @@ -262,7 +262,7 @@ void Table::add(int stateNum, Symbol tranSymbol, ParseAction* action) { //else if ( !(*(table[stateNum]))[symbolIndex]->equalsExceptLookahead(*action)) { else { //std::cout << "not Null!" << std::endl; - //std::cout << "State: " << stateNum << " Conflict between old: " << (*(table[stateNum]))[symbolIndex]->toString() << " and new: " << action->toString() << " on " << tranSymbol->toString() << std::endl; + //std::cout << "State: " << stateNum << " Conflict between old: " << (*(table[stateNum]))[symbolIndex]->toString() << " and new: " << action->toString() << " on " << tranSymbol->toString() << std::endl; //Check to see if this action is already in the list @@ -353,6 +353,17 @@ ParseAction* Table::getShift(int state, Symbol token) { return shift; } +std::vector> Table::stateAsParseActionVector(int state) { + std::vector> reconstructedState; + std::vector*>* stateVec = table[state]; + for (int i = 0; i < stateVec->size(); i++) + if (std::vector* forStateAndSymbol = (*stateVec)[i]) + for (int j = 0; j < forStateAndSymbol->size(); j++) + reconstructedState.push_back(std::make_pair(symbolIndexVec[i].toString(),*((*forStateAndSymbol)[j]))); + + return reconstructedState; +} + std::string Table::toString() { std::string concat = ""; for (std::vector::size_type i = 0; i < symbolIndexVec.size(); i++) diff --git a/stdlib/io.krak b/stdlib/io.krak index 1d079b7..9cf6dab 100644 --- a/stdlib/io.krak +++ b/stdlib/io.krak @@ -2,6 +2,10 @@ __if_comp__ __C__ __simple_passthrough__ """ #include """ +void println() { + print("\n"); +} + void print(char* toPrint) { __if_comp__ __C__ { __simple_passthrough__ """ @@ -13,7 +17,7 @@ void print(char* toPrint) { void println(char* toPrint) { print(toPrint); - print("\n"); + println(); } void print(int toPrint) { @@ -27,7 +31,7 @@ void print(int toPrint) { void println(int toPrint) { print(toPrint); - print("\n"); + println(); } void print(float toPrint) { @@ -41,6 +45,6 @@ void print(float toPrint) { void println(float toPrint) { print(toPrint); - print("\n"); + println(); } diff --git a/stdlib/mem.krak b/stdlib/mem.krak index 0e9bef1..13c4b2a 100644 --- a/stdlib/mem.krak +++ b/stdlib/mem.krak @@ -50,6 +50,12 @@ template T* new() { return new(1); } +template void delete(T* toDelete, int itemDestructCount) { + for (int i = 0; i < itemDestructCount; i++) + toDelete[i].destruct(); + delete(toDelete); +} + template void delete(T* toDelete) { free(toDelete); } diff --git a/stdlib/util.krak b/stdlib/util.krak new file mode 100644 index 0000000..02416d6 --- /dev/null +++ b/stdlib/util.krak @@ -0,0 +1,12 @@ + +template T greater(T a, T b) { + if (a > b) + return a; + return b; +} + +template T lesser(T a, T b) { + if (a > b) + return b; + return a; +} diff --git a/stdlib/vector.krak b/stdlib/vector.krak new file mode 100644 index 0000000..a8d8537 --- /dev/null +++ b/stdlib/vector.krak @@ -0,0 +1,52 @@ +import mem; +import util; + +typedef template vector { + T *data; + int size; + int available; + vector *construct() { + size = 0; + available = 8; + data = new(8); + return this; + } + + void destruct() { + //Destruction of contained data should depend on if the stored things are objects or primitives. + delete(data, size); + } + + bool resize(int newSize) { + T* newData = new(newSize); + if (!newData) + return false; + for (int i = 0; i < lesser(size, newSize); i++;) + newData[i] = data[i]; + delete(data, 0); + return true; + } + + T at(int index) { + return get(index); + } + + T get(int index) { + if (index < 0 || index >= size) + return null; + return data[index]; + } + + void set(int index, T dataIn) { + if (index < 0 || index => size) + return; + data[index] = dataIn; + } + void addEnd(T dataIn) { + if (size < available) + size++; + else + resize(size*2); + data[size-1]; + } +}; diff --git a/tests/vectorTest.expected_results b/tests/vectorTest.expected_results new file mode 100644 index 0000000..d472488 --- /dev/null +++ b/tests/vectorTest.expected_results @@ -0,0 +1,2 @@ +1337 + diff --git a/tests/vectorTest.krak b/tests/vectorTest.krak new file mode 100644 index 0000000..b55fe50 --- /dev/null +++ b/tests/vectorTest.krak @@ -0,0 +1,15 @@ +import io; +import vector; + +int main() { + vector intVec.construct(); + intVec.addBack(1); + intVec.addBack(3); + intVec.addBack(3); + intVec.addBack(7); + for (int i = 0; i < intVec.size(); i++;) + print(intVec.at(i)); + + println(); + return 0; +}