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.

This commit is contained in:
Nathan Braswell
2014-06-30 01:57:50 -07:00
parent 12f57f8ce8
commit 03770028ad
19 changed files with 273 additions and 78 deletions

View File

@@ -27,6 +27,7 @@ class GraphStructuredStack {
void addEdge(NodeTree<int>* start, NodeTree<int>* end, NodeTree<Symbol>* edge);
void clear();
std::vector<int> getFrontier(int frontier);
std::string toString();
private:
std::vector<std::vector<NodeTree<int>*>*> gss;

View File

@@ -11,6 +11,7 @@
#include <vector>
#include <string>
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
#endif

View File

@@ -16,10 +16,10 @@ class ParseRule {
ParseRule();
ParseRule(Symbol leftHandle, int pointerIndex, std::vector<Symbol> &rightSide, std::vector<Symbol>* 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<Symbol>* lookahead);
std::vector<Symbol>* getLookahead();
std::string toString();
std::string toString(bool printLookahead = true);
std::string toDOT();
private:
@@ -51,4 +51,4 @@ class ParseRule {
};
#endif
#endif

View File

@@ -12,6 +12,7 @@
#include "Table.h"
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <algorithm>
@@ -36,8 +37,13 @@ class Parser {
void importTable(char* tableData);
protected:
std::vector<Symbol>* firstSet(Symbol token);
std::vector<Symbol>* firstSet(Symbol token, std::vector<Symbol> avoidList);
std::vector<Symbol> firstSet(Symbol token, std::vector<Symbol> avoidList = std::vector<Symbol>(), bool addNewTokens = true);
bool isNullable(Symbol token);
bool isNullableHelper(Symbol token, std::set<Symbol> done);
std::map<Symbol, std::vector<Symbol>> tokenFirstSet;
std::map<Symbol, bool> tokenNullable;
std::vector<Symbol>* incrementiveFollowSet(ParseRule* rule);
virtual void closure(State* state);
virtual void addStates(std::vector< State* >* stateSets, State* state, std::queue<State*>* toDo);
@@ -65,4 +71,4 @@ class Parser {
NodeTree<Symbol>* reduceTreeCombine(Symbol newSymbol, std::vector<Symbol> &symbols);
};
#endif
#endif

View File

@@ -5,6 +5,8 @@
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <utility>
#include <algorithm>
#include "Parser.h"
#include "Symbol.h"
@@ -16,6 +18,7 @@ class RNGLRParser: public Parser {
RNGLRParser();
~RNGLRParser();
NodeTree<Symbol>* parseInput(std::string inputString);
void printReconstructedFrontier(int frontier);
private:
void reducer(int i);

View File

@@ -1,5 +1,8 @@
#include <fstream>
#include <string>
#include <utility>
#include "util.h"
#include "ParseRule.h"
#include "ParseAction.h"
@@ -20,7 +23,8 @@ class Table {
void remove(int stateNum, Symbol tranSymbol);
std::vector<ParseAction*>* get(int state, Symbol token);
ParseAction* getShift(int state, Symbol token);
std::string toString();
std::vector<std::pair<std::string, ParseAction>> stateAsParseActionVector(int state);
std::string toString();
private:
std::vector< std::vector< std::vector<ParseAction*>* >* > table;
std::vector<Symbol> symbolIndexVec;

View File

@@ -117,6 +117,13 @@ void GraphStructuredStack::addEdge(NodeTree<int>* start, NodeTree<int>* end, Nod
edges[std::make_pair(start, end)] = edge;
}
std::vector<int> GraphStructuredStack::getFrontier(int frontier) {
std::vector<int> 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<std::vector<NodeTree<int>*>*>::size_type i = 0; i < gss.size(); i++) {

View File

@@ -66,7 +66,8 @@ NodeTree<ASTData>* Importer::importFirstPass(std::string fileName) {
NodeTree<ASTData>* ast = getUnit(fileName);
if (ast == NULL) {
NodeTree<Symbol>* 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<Symbol>* 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

View File

@@ -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);
}
}

View File

@@ -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<Symbol>* newLookahead = NULL;
if (lookahead) {
@@ -111,7 +127,7 @@ std::vector<Symbol>* 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<Symbol>::size_type i = 0; i < lookahead->size(); i++)
concat += (*lookahead)[i].toString();

View File

@@ -117,59 +117,76 @@ int Parser::stateNum(State* state) {
return -1;
}
std::vector<Symbol>* Parser::firstSet(Symbol token) {
std::vector<Symbol> avoidList;
return firstSet(token, avoidList);
}
std::vector<Symbol>* Parser::firstSet(Symbol token, std::vector<Symbol> avoidList) {
//If we've already done this token, don't do it again
std::vector<Symbol> Parser::firstSet(Symbol token, std::vector<Symbol> 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<Symbol>::size_type i = 0; i < avoidList.size(); i++)
if (avoidList[i] == token) {
return new std::vector<Symbol>();
}
if (avoidList[i] == token)
return std::vector<Symbol>();
avoidList.push_back(token);
std::vector<Symbol>* first = new std::vector<Symbol>();
std::vector<Symbol> 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<Symbol>* recursiveFirstSet = NULL;
std::vector<Symbol> recursiveFirstSet;
for (std::vector<ParseRule*>::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<Symbol>();
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<Symbol>::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<Symbol>());
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<Symbol> 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<ParseRule*>::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<Symbol>* 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<Symbol>* Parser::incrementiveFollowSet(ParseRule* rule) {
//Get the first set of the next Symbol. If it contains nullSymbol, keep doing for the next one
std::vector<Symbol>* followSet = new std::vector<Symbol>();
std::vector<Symbol>* symbolFirstSet;
std::vector<Symbol> symbolFirstSet;
bool symbolFirstSetHasNull = true;
while (symbolFirstSetHasNull && !rule->isAtEnd()) {
symbolFirstSetHasNull = false;
symbolFirstSet = firstSet(rule->getAtNextIndex());
for (std::vector<Symbol>::size_type i = 0; i < symbolFirstSet->size(); i++) {
if ((*symbolFirstSet)[i] == nullSymbol) {
for (std::vector<Symbol>::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<Symbol>* followSetReturn = new std::vector<Symbol>();
for (std::vector<Symbol>::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.

View File

@@ -8,6 +8,20 @@ RNGLRParser::~RNGLRParser() {
//
}
void RNGLRParser::printReconstructedFrontier(int frontier) {
std::vector<int> lastFrontier = gss.getFrontier(frontier);
for (int j = 0; j < lastFrontier.size(); j++) {
std::cout << "State: " << lastFrontier[j] << std::endl;
std::vector<std::pair<std::string, ParseAction>> stateParseActions = table.stateAsParseActionVector(lastFrontier[j]);
std::set<std::pair<std::string, ParseAction>> 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<Symbol>* RNGLRParser::parseInput(std::string inputString) {
input.clear();
gss.clear();
@@ -53,7 +67,7 @@ NodeTree<Symbol>* 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<Symbol>* 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<Symbol>* 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<ParseAction*> actions = *(table.get(toState, input[i]));
for (std::vector<ParseAction*>::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]);

View File

@@ -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<ParseAction*>* actionList = new std::vector<ParseAction*>();
@@ -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<std::pair<std::string, ParseAction>> Table::stateAsParseActionVector(int state) {
std::vector<std::pair<std::string, ParseAction>> reconstructedState;
std::vector<std::vector<ParseAction*>*>* stateVec = table[state];
for (int i = 0; i < stateVec->size(); i++)
if (std::vector<ParseAction*>* 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<Symbol>::size_type i = 0; i < symbolIndexVec.size(); i++)

View File

@@ -2,6 +2,10 @@ __if_comp__ __C__ __simple_passthrough__ """
#include <stdio.h>
"""
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();
}

View File

@@ -50,6 +50,12 @@ template <T> T* new() {
return new<T>(1);
}
template <T> void delete(T* toDelete, int itemDestructCount) {
for (int i = 0; i < itemDestructCount; i++)
toDelete[i].destruct();
delete(toDelete);
}
template <T> void delete(T* toDelete) {
free<T>(toDelete);
}

12
stdlib/util.krak Normal file
View File

@@ -0,0 +1,12 @@
template<T> T greater(T a, T b) {
if (a > b)
return a;
return b;
}
template<T> T lesser(T a, T b) {
if (a > b)
return b;
return a;
}

52
stdlib/vector.krak Normal file
View File

@@ -0,0 +1,52 @@
import mem;
import util;
typedef template<T> vector {
T *data;
int size;
int available;
vector<T> *construct() {
size = 0;
available = 8;
data = new<T>(8);
return this;
}
void destruct() {
//Destruction of contained data should depend on if the stored things are objects or primitives.
delete<T>(data, size);
}
bool resize(int newSize) {
T* newData = new<T>(newSize);
if (!newData)
return false;
for (int i = 0; i < lesser(size, newSize); i++;)
newData[i] = data[i];
delete<T>(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];
}
};

View File

@@ -0,0 +1,2 @@
1337

15
tests/vectorTest.krak Normal file
View File

@@ -0,0 +1,15 @@
import io;
import vector;
int main() {
vector<int> 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;
}