This commit is contained in:
Nathan Braswell
2014-12-07 18:52:32 -05:00
82 changed files with 2891 additions and 517 deletions

View File

@@ -2,13 +2,22 @@ cmake_minimum_required (VERSION 2.6)
project(Kraken) project(Kraken)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set( MY_INCLUDES ${PROJECT_SOURCE_DIR}/include) set( MY_INCLUDES ${PROJECT_SOURCE_DIR}/include)
set( MY_SOURCES main.cpp src/Parser.cpp src/LALRParser.cpp src/GraphStructuredStack.cpp src/RNGLRParser.cpp src/ParseAction.cpp src/ParseRule.cpp src/Symbol.cpp src/StringReader.cpp src/State.cpp src/util.cpp src/Lexer.cpp src/RegEx.cpp src/RegExState.cpp src/Table.cpp src/ASTData.cpp src/ASTTransformation.cpp src/CGenerator.cpp src/Type.cpp src/Importer.cpp ) set( MY_SOURCES main.cpp src/Parser.cpp src/LALRParser.cpp src/GraphStructuredStack.cpp src/RNGLRParser.cpp src/ParseAction.cpp src/ParseRule.cpp src/Symbol.cpp src/StringReader.cpp src/State.cpp src/util.cpp src/Lexer.cpp src/RegEx.cpp src/RegExState.cpp src/Table.cpp src/ASTData.cpp src/ASTTransformation.cpp src/CGenerator.cpp src/Type.cpp src/Importer.cpp src/Tester.cpp )
add_custom_target(STDLibCopy ALL)
add_custom_command(TARGET STDLibCopy POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"${PROJECT_SOURCE_DIR}/stdlib"
"${PROJECT_BINARY_DIR}/stdlib")
include_directories( ${MY_INCLUDES} ) include_directories( ${MY_INCLUDES} )
add_executable(kraken ${MY_SOURCES}) add_executable(kraken ${MY_SOURCES})

21
LICENCE.md Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2014 Nathan Christopher Braswell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

10
future_features.txt Normal file
View File

@@ -0,0 +1,10 @@
Declaration of a pointer and multiplication are ambigious!
( T* a; maybe either a declaration or a multiplication)
Fix destructors being placed after return.
Fix functions before declaration? (in class? (this is from an old file))
Template instantiation without explicit type param
Fix // comment right before top level function declaration. Something to do
with the return as /* comment */ does not have that problem
for in or for each loops
Traits on aliases, maybe that keep their old traits?

View File

@@ -4,6 +4,9 @@
#include <set> #include <set>
#include <map> #include <map>
#include <iterator>
#include <algorithm>
#include "Type.h" #include "Type.h"
#include "ASTData.h" #include "ASTData.h"
#include "NodeTransformation.h" #include "NodeTransformation.h"
@@ -15,17 +18,46 @@ class ASTTransformation: public NodeTransformation<Symbol,ASTData> {
public: public:
ASTTransformation(Importer* importerIn); ASTTransformation(Importer* importerIn);
~ASTTransformation(); ~ASTTransformation();
//First pass defines all type_defs (objects and ailises)
NodeTree<ASTData>* firstPass(std::string fileName, NodeTree<Symbol>* parseTree);
std::set<std::string> parseTraits(NodeTree<Symbol>* traitsNode);
//Second pass defines data inside objects, outside declaration statements, and function prototpyes (since we have type_defs now)
void secondPass(NodeTree<ASTData>* ast, NodeTree<Symbol>* parseTree);
void secondPassDoClassInsides(NodeTree<ASTData>* typeDef, std::vector<NodeTree<Symbol>*> typedefChildren, std::map<std::string, Type*> templateTypeReplacements);
NodeTree<ASTData>* secondPassDeclaration(NodeTree<Symbol>* from, NodeTree<ASTData>* scope, std::map<std::string, Type*> templateTypeReplacements);
NodeTree<ASTData>* secondPassFunction(NodeTree<Symbol>* from, NodeTree<ASTData>* scope, std::map<std::string, Type*> templateTypeReplacements);
//Third pass redoes all imports to import the new function prototypes and identifiers
void thirdPass(NodeTree<ASTData>* ast);
//The fourth pass finishes up by doing all function bodies
void fourthPass(NodeTree<ASTData>* ast, NodeTree<Symbol>* parseTree);
NodeTree<ASTData>* searchScopeForFunctionDef(NodeTree<ASTData>* scope, NodeTree<Symbol>* parseTree, std::map<std::string, Type*> templateTypeReplacements);
void fourthPassFunction(NodeTree<Symbol>* from, NodeTree<ASTData>* functionDef, std::map<std::string, Type*> templateTypeReplacements);
virtual NodeTree<ASTData>* transform(NodeTree<Symbol>* from); virtual NodeTree<ASTData>* transform(NodeTree<Symbol>* from);
NodeTree<ASTData>* transform(NodeTree<Symbol>* from, NodeTree<ASTData>* scope, std::vector<Type> types = std::vector<Type>()); NodeTree<ASTData>* transform(NodeTree<Symbol>* from, NodeTree<ASTData>* scope, std::vector<Type> types, std::map<std::string, Type*> templateTypeReplacements);
std::vector<NodeTree<ASTData>*> transformChildren(std::vector<NodeTree<Symbol>*> children, std::set<int> skipChildren, NodeTree<ASTData>* scope, std::vector<Type> types); std::vector<NodeTree<ASTData>*> transformChildren(std::vector<NodeTree<Symbol>*> children, std::set<int> skipChildren, NodeTree<ASTData>* scope, std::vector<Type> types, std::map<std::string, Type*> templateTypeReplacements);
std::vector<Type> mapNodesToTypes(std::vector<NodeTree<ASTData>*> nodes); std::vector<Type> mapNodesToTypes(std::vector<NodeTree<ASTData>*> nodes);
std::string concatSymbolTree(NodeTree<Symbol>* root); std::string concatSymbolTree(NodeTree<Symbol>* root);
NodeTree<ASTData>* scopeLookup(NodeTree<ASTData>* scope, std::string lookup, std::vector<NodeTree<ASTData>*> nodes); NodeTree<ASTData>* doFunction(NodeTree<ASTData>* scope, std::string lookup, std::vector<NodeTree<ASTData>*> nodes, std::map<std::string, Type*> templateTypeReplacements);
NodeTree<ASTData>* scopeLookup(NodeTree<ASTData>* scope, std::string lookup, std::vector<Type> types = std::vector<Type>());
Type* typeFromString(std::string type, NodeTree<ASTData>* scope); NodeTree<ASTData>* functionLookup(NodeTree<ASTData>* scope, std::string lookup, std::vector<Type> types);
NodeTree<ASTData>* templateFunctionLookup(NodeTree<ASTData>* scope, std::string lookup, std::vector<Type*> templateInstantiationTypes, std::vector<Type> types);
std::vector<NodeTree<ASTData>*> scopeLookup(NodeTree<ASTData>* scope, std::string lookup, bool includeModules = false);
Type* typeFromTypeNode(NodeTree<Symbol>* typeNode, NodeTree<ASTData>* scope, std::map<std::string, Type*> templateTypeReplacements);
NodeTree<ASTData>* templateClassLookup(NodeTree<ASTData>* scope, std::string name, std::vector<Type*> templateInstantiationTypes);
NodeTree<ASTData>* findOrInstantiateFunctionTemplate(std::vector<NodeTree<Symbol>*> children, NodeTree<ASTData>* scope, std::vector<Type> types, std::map<std::string, Type*> templateTypeReplacements);
std::map<std::string, Type*> makeTemplateFunctionTypeMap(NodeTree<Symbol>* templateNode, std::vector<Type*> types);
std::vector<std::pair<std::string, std::set<std::string>>> makeTemplateNameTraitPairs(NodeTree<Symbol>* templateNode);
private: private:
Importer * importer; Importer * importer;
std::map<std::string, std::vector<NodeTree<ASTData>*>> languageLevelScope; std::map<std::string, std::vector<NodeTree<ASTData>*>> languageLevelReservedWords;
std::map<std::string, std::vector<NodeTree<ASTData>*>> languageLevelOperators;
NodeTree<ASTData>* topScope; //maintained for templates that need to add themselves to the top scope no matter where they are instantiated
}; };
#endif #endif

View File

@@ -10,6 +10,7 @@
#include "Type.h" #include "Type.h"
#include "util.h" #include "util.h"
#include "Poset.h"
class CGenerator { class CGenerator {
@@ -17,12 +18,14 @@ class CGenerator {
CGenerator(); CGenerator();
~CGenerator(); ~CGenerator();
void generateCompSet(std::map<std::string, NodeTree<ASTData>*> ASTs, std::string outputName); void generateCompSet(std::map<std::string, NodeTree<ASTData>*> ASTs, std::string outputName);
std::string generateClassStruct(NodeTree<ASTData>* from);
std::string generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enclosingObject = NULL); std::string generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enclosingObject = NULL);
std::string generateAliasChains(NodeTree<ASTData>* scopeNode, NodeTree<ASTData>* definition);
static std::string ValueTypeToCType(Type *type); static std::string ValueTypeToCType(Type *type);
static std::string ValueTypeToCTypeDecoration(Type *type); static std::string ValueTypeToCTypeDecoration(Type *type);
static std::string CifyFunctionName(std::string name); static std::string CifyName(std::string name);
std::string generateObjectMethod(NodeTree<ASTData>* enclosingObject, NodeTree<ASTData>* from); std::string generateObjectMethod(NodeTree<ASTData>* enclosingObject, NodeTree<ASTData>* from, std::string *functionPrototype);
NodeTree<ASTData>* getMethodsObjectType(NodeTree<ASTData>* scope, std::string functionName);
std::string generatorString; std::string generatorString;
private: private:
std::string tabs(); std::string tabs();

View File

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

View File

@@ -14,13 +14,27 @@
#include "CollapseTransformation.h" #include "CollapseTransformation.h"
#include "ASTTransformation.h" #include "ASTTransformation.h"
class ASTTransformation;
class Importer { class Importer {
public: public:
Importer(Parser* parserIn); Importer(Parser* parserIn, std::vector<std::string> includePaths);
~Importer(); ~Importer();
NodeTree<ASTData>* import(std::string fileName); void import(std::string fileName);
NodeTree<ASTData>* getUnit(std::string fileName);
NodeTree<ASTData>* importFirstPass(std::string fileName);
NodeTree<Symbol>* parseAndTrim(std::string fileName);
void registerAST(std::string name, NodeTree<ASTData>* ast, NodeTree<Symbol>* syntaxTree);
std::map<std::string, NodeTree<ASTData>*> getASTMap(); std::map<std::string, NodeTree<ASTData>*> getASTMap();
private: private:
ASTTransformation *ASTTransformer;
struct importTriplet {
std::string name;
NodeTree<ASTData>* ast;
NodeTree<Symbol>* syntaxTree;
};
std::vector<importTriplet> importedTrips;
std::vector<std::string> includePaths;
Parser* parser; Parser* parser;
std::vector<Symbol> removeSymbols; std::vector<Symbol> removeSymbols;
std::vector<Symbol> collapseSymbols; std::vector<Symbol> collapseSymbols;

View File

@@ -11,6 +11,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
class ParseAction { class ParseAction {
public: public:
enum ActionType { INVALID, REDUCE, SHIFT, ACCEPT, REJECT }; enum ActionType { INVALID, REDUCE, SHIFT, ACCEPT, REJECT };
@@ -18,10 +19,11 @@ class ParseAction {
ParseAction(ActionType action, ParseRule* reduceRule); ParseAction(ActionType action, ParseRule* reduceRule);
ParseAction(ActionType action, int shiftState); ParseAction(ActionType action, int shiftState);
~ParseAction(); ~ParseAction();
bool const equalsExceptLookahead(const ParseAction &other); bool const equalsExceptLookahead(const ParseAction &other) const;
bool const operator==(const ParseAction &other); bool const operator==(const ParseAction &other) const;
bool const operator!=(const ParseAction &other); bool const operator!=(const ParseAction &other) const;
std::string toString(); bool const operator<(const ParseAction &other) const;
std::string toString(bool printRuleLookahead = true);
static std::string actionToString(ActionType action); static std::string actionToString(ActionType action);
ActionType action; ActionType action;

View File

@@ -16,10 +16,10 @@ class ParseRule {
ParseRule(); ParseRule();
ParseRule(Symbol leftHandle, int pointerIndex, std::vector<Symbol> &rightSide, std::vector<Symbol>* lookahead); ParseRule(Symbol leftHandle, int pointerIndex, std::vector<Symbol> &rightSide, std::vector<Symbol>* lookahead);
~ParseRule(); ~ParseRule();
const bool equalsExceptLookahead(const ParseRule &other); const bool equalsExceptLookahead(const ParseRule &other) const;
bool const operator==(const ParseRule &other); bool const operator==(const ParseRule &other) const;
bool const operator!=(const ParseRule &other); 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(); ParseRule* clone();
void setLeftHandle(Symbol leftHandle); void setLeftHandle(Symbol leftHandle);
@@ -40,7 +40,7 @@ class ParseRule {
void addLookahead(std::vector<Symbol>* lookahead); void addLookahead(std::vector<Symbol>* lookahead);
std::vector<Symbol>* getLookahead(); std::vector<Symbol>* getLookahead();
std::string toString(); std::string toString(bool printLookahead = true);
std::string toDOT(); std::string toDOT();
private: private:

View File

@@ -12,6 +12,7 @@
#include "Table.h" #include "Table.h"
#include <queue> #include <queue>
#include <set>
#include <map> #include <map>
#include <vector> #include <vector>
#include <algorithm> #include <algorithm>
@@ -36,8 +37,13 @@ class Parser {
void importTable(char* tableData); void importTable(char* tableData);
protected: protected:
std::vector<Symbol>* firstSet(Symbol token); std::vector<Symbol> firstSet(Symbol token, std::vector<Symbol> avoidList = std::vector<Symbol>(), bool addNewTokens = true);
std::vector<Symbol>* firstSet(Symbol token, std::vector<Symbol> avoidList); 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); std::vector<Symbol>* incrementiveFollowSet(ParseRule* rule);
virtual void closure(State* state); virtual void closure(State* state);
virtual void addStates(std::vector< State* >* stateSets, State* state, std::queue<State*>* toDo); virtual void addStates(std::vector< State* >* stateSets, State* state, std::queue<State*>* toDo);

126
include/Poset.h Normal file
View File

@@ -0,0 +1,126 @@
#ifndef POSET_H
#define POSET_H
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <cassert>
#include "util.h"
template <class T>
class Poset {
public:
Poset();
~Poset();
void addRelationship(T first, T second);
void addVertex(T vertex);
bool zeroDependencies(T vertex);
std::set<T> getDependsOn(T dependency);
std::vector<T> getTopoSort();
static void test();
private:
//backing data structures
std::map<T, std::map<T,bool>> adjMatrix;
std::set<T> verticies;
};
template <class T>
Poset<T>::Poset() {
//Nothing needed
}
template <class T>
Poset<T>::~Poset() {
//Ditto
}
template <class T>
void Poset<T>::addRelationship(T first, T second) {
verticies.insert(first);
verticies.insert(second);
adjMatrix[first][second] = true;
}
template <class T>
void Poset<T>::addVertex(T vertex) {
verticies.insert(vertex);
}
template <class T>
bool Poset<T>::zeroDependencies(T vertex) {
auto depMapItr = adjMatrix.find(vertex);
if (depMapItr == adjMatrix.end())
return true;
for (auto i : depMapItr->second)
if (i.second == true)
return false;
return true;
}
template <class T>
std::set<T> Poset<T>::getDependsOn(T dependency) {
std::set<T> vertsThatDependOn;
for (auto i : adjMatrix) {
auto depItr = i.second.find(dependency);
if (depItr != i.second.end() && depItr->second)
vertsThatDependOn.insert(i.first);
}
return vertsThatDependOn;
}
template <class T>
std::vector<T> Poset<T>::getTopoSort() {
std::vector<T> sorted;
std::queue<T> toDo;
for (auto i : verticies)
if (zeroDependencies(i))
toDo.push(i);
while(!toDo.empty()) {
T current = toDo.front(); toDo.pop();
sorted.push_back(current);
for (T depOnCurrent : getDependsOn(current)) {
adjMatrix[depOnCurrent][current] = false; //Remove the edge to current, since current's now been taken care of
if (zeroDependencies(depOnCurrent))
toDo.push(depOnCurrent);
}
}
return sorted;
}
//would make it just an int specilization, but then we get multiple definition complaints....
template<class T>
void Poset<T>::test() {
std::string result;
{
Poset<int> poset;
poset.addVertex(1000);
for (int i = 0; i < 20; i++)
poset.addRelationship(i,i+1);
result = "";
for (int i : poset.getTopoSort())
result += intToString(i) + " ";
//std::cout << result << std::endl;
assert(result == "20 1000 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 "); //Note that sets do not have a set order, so this could change
//This is why the 1000 is in an odd, yet valid, position
}
{
Poset<int> poset;
for (int i = 0; i < 20; i+=2)
poset.addRelationship(i,i+1);
result = "";
for (int i : poset.getTopoSort())
result += intToString(i) + " ";
//std::cout << result << std::endl;
assert(result == "1 3 5 7 9 11 13 15 17 19 0 2 4 6 8 10 12 14 16 18 ");
}
std::cout << "Poset tests passed" << std::endl;
}
#endif

View File

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

View File

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

31
include/Tester.h Normal file
View File

@@ -0,0 +1,31 @@
#include <iostream>
#include <string>
#include <stdlib.h>
#include "util.h"
#ifndef TESTER_H
#define TESTER_H
class Tester {
public:
Tester(std::string krakenInvocation, std::string krakenGrammerLocation);
~Tester();
int ssystem(std::string command);
bool run(std::string fileName);
bool compareFiles(std::string file1Path, std::string file2Path);
void cleanExtras(std::string fileName);
private:
std::string krakenInvocation;
std::string krakenGrammerLocation;
std::string removeCmd;
std::string resultsExtention;
std::string expectedExtention;
std::string krakenExtention;
std::string shell;
std::string changePermissions;
std::string redirect;
};
#endif

View File

@@ -7,31 +7,43 @@
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <set>
//Circular dependency //Circular dependency
class ASTData; class ASTData;
#include "ASTData.h" #include "ASTData.h"
#include "util.h" #include "util.h"
enum ValueType {none, void_type, boolean, integer, floating, double_percision, character }; enum ValueType {none, template_type, template_type_type, void_type, boolean, integer, floating, double_percision, character };
class Type { class Type {
public: public:
Type(); Type();
Type(ValueType typeIn, int indirectionIn); Type(ValueType typeIn, int indirectionIn = 0);
Type(ValueType typeIn); Type(ValueType typeIn, std::set<std::string> traitsIn); //Mostly for template type type's
Type(NodeTree<ASTData>* typeDefinitionIn); Type(NodeTree<ASTData>* typeDefinitionIn, int indirectionIn = 0);
Type(NodeTree<ASTData>* typeDefinitionIn, int indirectionIn); Type(NodeTree<ASTData>* typeDefinitionIn, std::set<std::string> traitsIn);
Type(ValueType typeIn, NodeTree<ASTData>* typeDefinitionIn, int indirectionIn); Type(ValueType typeIn, NodeTree<ASTData>* typeDefinitionIn, int indirectionIn, std::set<std::string> traitsIn);
Type(ValueType typeIn, NodeTree<Symbol>* templateDefinitionIn, std::set<std::string> traitsIn = std::set<std::string>());
~Type(); ~Type();
bool const operator==(const Type &other)const; bool const operator==(const Type &other)const;
bool const operator!=(const Type &other)const; bool const operator!=(const Type &other)const;
std::string toString(); Type* clone();
ValueType baseType; std::string toString(bool showTraits = true);
int getIndirection();
void setIndirection(int indirectionIn);
void increaseIndirection();
void decreaseIndirection();
void modifyIndirection(int mod);
ValueType baseType;
NodeTree<ASTData>* typeDefinition; NodeTree<ASTData>* typeDefinition;
NodeTree<Symbol>* templateDefinition;
std::map<std::string, Type*> templateTypeReplacement;
std::set<std::string> traits;
private:
int indirection; int indirection;
private:
}; };
#endif #endif

View File

@@ -9,6 +9,9 @@
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
#include <set>
#include <fstream>
#include <cstring>
std::string intToString(int theInt); std::string intToString(int theInt);
std::string replaceExEscape(std::string first, std::string search, std::string replace); std::string replaceExEscape(std::string first, std::string search, std::string replace);
@@ -16,6 +19,9 @@ std::string strSlice(std::string str, int begin, int end);
int findPerenEnd(std::string str, int i); int findPerenEnd(std::string str, int i);
std::vector<std::string> split(const std::string &str, char delim); std::vector<std::string> split(const std::string &str, char delim);
std::string join(const std::vector<std::string> &strVec, std::string joinStr); std::string join(const std::vector<std::string> &strVec, std::string joinStr);
std::string readFile(std::istream &file);
template <typename T> template <typename T>
bool contains(std::vector<T> vec, T item) { bool contains(std::vector<T> vec, T item) {
for (auto i : vec) for (auto i : vec)
@@ -25,15 +31,32 @@ bool contains(std::vector<T> vec, T item) {
} }
template <typename T> template <typename T>
std::vector<T> slice(std::vector<T> vec, int begin, int end) { std::vector<T> slice(std::vector<T> vec, int begin, int end, int step = 1) {
std::vector<T> toReturn; std::vector<T> toReturn;
if (begin < 0) if (begin < 0)
begin += vec.size()+1; begin += vec.size()+1;
if (end < 0) if (end < 0)
end += vec.size()+1; end += vec.size()+1;
for (int i = begin; i < end; i++) for (int i = begin; i < end; i += step)
toReturn.push_back(vec[i]); toReturn.push_back(vec[i]);
return toReturn; return toReturn;
} }
template <typename T>
bool subset(std::set<T> a, std::set<T> b) {
for (auto i : a)
if (b.find(i) == b.end())
return false;
return true;
}
/*
std::vector<std::string> split(std::string str, char delim) {
std::stringstream stream(str);
std::string item;
std::vector<std::string> results;
while(std::getline(stream, item, delim))
results.push_back(item);
return results;
}
*/
#endif #endif

View File

@@ -2,10 +2,19 @@ Goal = translation_unit ;
translation_unit = interpreter_directive WS unorderd_list_part WS ; translation_unit = interpreter_directive WS unorderd_list_part WS ;
unorderd_list_part = import WS unorderd_list_part | function WS unorderd_list_part | type_def WS ";" WS unorderd_list_part | if_comp WS unorderd_list_part | simple_passthrough WS unorderd_list_part | declaration_statement WS ";" WS unorderd_list_part | import | function | type_def WS ";" | if_comp | simple_passthrough | declaration_statement WS ";" ; unorderd_list_part = import WS unorderd_list_part | function WS unorderd_list_part | type_def WS ";" WS unorderd_list_part | if_comp WS unorderd_list_part | simple_passthrough WS unorderd_list_part | declaration_statement WS ";" WS unorderd_list_part | import | function | type_def WS ";" | if_comp | simple_passthrough | declaration_statement WS ";" ;
type = type WS "\*" | "void" | "int" | "float" | "double" | "char" | identifier ; type = type WS "\*" | "void" | "int" | "float" | "double" | "char" | identifier | identifier WS template_inst ;
dec_type = "\|" WS type WS "\|" ;
template_inst = "<" WS type_list WS ">" ;
type_list = type_list WS "," WS type | type ;
template_dec = "template" WS "<" WS template_param_list WS ">" ;
template_param_list = template_param_list WS "," WS template_param | template_param ;
template_param = identifier WS traits | identifier ;
import = "import" WS identifier WS ";" ; import = "import" WS identifier WS ";" ;
interpreter_directive = "#!" WS path | ; interpreter_directive = "#!" WS path | ;
path = path path_part | path_part ; path = path path_part | path_part ;
path_part = forward_slash alphanumeric | back_slash alphanumeric ; path_part = forward_slash alphanumeric | back_slash alphanumeric ;
@@ -29,24 +38,33 @@ triple_quoted_string = "\"\"\"((\"\"(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i
identifier = alpha | alpha alphanumeric ; identifier = alpha | alpha alphanumeric ;
overloadable_operator = "\+" | "-" | "\*" | "/" | "%" | "^" | "&" | "\|" | "~" | "\!" | "," | "=" | "\+\+" | "--" | "<<" | ">>" | "==" | "!=" | "&&" | "\|\|" | "\+=" | "-=" | "/=" | "%=" | "^=" | "&=" | "\|=" | "\*=" | "<<=" | ">>=" | "->" ; #Note that to prevent confilct with nested templates (T<A<B>>) it is a nonterminal contructed as follows
right_shift = ">" ">" ;
overloadable_operator = "\+" | "-" | "\*" | "/" | "%" | "^" | "&" | "\|" | "~" | "!" | "," | "=" | "\+\+" | "--" | "<<" | right_shift | "==" | "!=" | "&&" | "\|\|" | "\+=" | "-=" | "/=" | "%=" | "^=" | "&=" | "\|=" | "\*=" | "<<=" | ">>=" | "->" ;
func_identifier = identifier | identifier overloadable_operator ; func_identifier = identifier | identifier overloadable_operator ;
function = type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block ; function = template_dec WS dec_type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block | dec_type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block ;
opt_typed_parameter_list = typed_parameter_list | ; opt_typed_parameter_list = typed_parameter_list | ;
typed_parameter_list = typed_parameter_list WS "," WS typed_parameter | typed_parameter ; typed_parameter_list = typed_parameter_list WS "," WS typed_parameter | typed_parameter ;
typed_parameter = type WS identifier ; typed_parameter = dec_type WS identifier ;
opt_parameter_list = parameter_list | ; opt_parameter_list = parameter_list | ;
parameter_list = parameter_list WS "," WS parameter | parameter ; parameter_list = parameter_list WS "," WS parameter | parameter ;
parameter = boolean_expression ; parameter = boolean_expression ;
type_def = "typedef" WS identifier WS type | "typedef" WS identifier WS "{" WS class_innerds WS "}" | "typedef" WS identifier WS "{" WS declaration_block WS "}" ; type_def = "typedef" WS identifier WS type | "typedef" WS template_dec WS identifier WS "{" WS declaration_block WS "}" | "typedef" WS identifier WS "{" WS declaration_block WS "}" | "typedef" WS template_dec WS identifier WS traits WS "{" WS declaration_block WS "}" | "typedef" WS identifier WS traits WS "{" WS declaration_block WS "}" ;
class_innerds = visibility_block WS class_innerds | visibility_block ;
visibility_block = "public:" WS declaration_block | "protected:" WS declaration_block | "private:" WS declaration_block ;
declaration_block = declaration_statement WS ";" WS declaration_block | function WS declaration_block | declaration_statement WS ";" | function ;
if_statement = "if" WS "\(" WS boolean_expression WS "\)" WS statement ; declaration_block = declaration_statement WS ";" WS declaration_block | function WS declaration_block | declaration_statement WS ";" | function | ;
traits = "\(" WS trait_list WS "\)" ;
trait_list = trait_list WS "," WS identifier | identifier ;
#Older rule for stuff with visibility labels - this should be added sometime
#type_def = "typedef" WS identifier WS type | "typedef" WS template_dec WS identifier WS "{" WS class_innerds WS "}" | "typedef" WS identifier WS "{" WS class_innerds WS "}" | "typedef" WS template_dec WS identifier WS "{" WS declaration_block WS "}" | "typedef" WS identifier WS "{" WS declaration_block WS "}" ;
#class_innerds = visibility_block WS class_innerds | visibility_block ;
#visibility_block = "public:" WS declaration_block | "protected:" WS declaration_block | "private:" WS declaration_block ;
if_statement = "if" WS "\(" WS boolean_expression WS "\)" WS statement | "if" WS "\(" WS boolean_expression WS "\)" WS statement WS "else" WS statement ;
while_loop = "while" WS boolean_expression WS statement ; while_loop = "while" WS boolean_expression WS statement ;
@@ -54,7 +72,7 @@ for_loop = "for" WS "\(" WS statement WS boolean_expression WS ";" WS statement
return_statement = "return" | "return" WS boolean_expression ; return_statement = "return" | "return" WS boolean_expression ;
code_block = "{" WS statement_list WS "}" ; code_block = "{" WS statement_list WS "}" | "{" WS "}" ;
statement_list = statement_list WS statement | statement ; statement_list = statement_list WS statement | statement ;
statement = if_statement | while_loop | for_loop | return_statement WS ";" | boolean_expression WS ";" | assignment_statement WS ";" | declaration_statement WS ";" | code_block | if_comp | simple_passthrough ; statement = if_statement | while_loop | for_loop | return_statement WS ";" | boolean_expression WS ";" | assignment_statement WS ";" | declaration_statement WS ";" | code_block | if_comp | simple_passthrough ;
@@ -62,26 +80,25 @@ function_call = unarad "\(" WS opt_parameter_list WS "\)" ;
boolean_expression = boolean_expression WS "\|\|" WS and_boolean_expression | and_boolean_expression ; boolean_expression = boolean_expression WS "\|\|" WS and_boolean_expression | and_boolean_expression ;
and_boolean_expression = and_boolean_expression "&&" bool_exp | bool_exp ; and_boolean_expression = and_boolean_expression "&&" bool_exp | bool_exp ;
bool_exp = "!" WS bool_exp | expression WS comparator WS expression | bool | expression ; bool_exp = expression WS comparator WS expression | expression ;
comparator = "==" | "<=" | ">=" | "!=" | "<" | ">" ; comparator = "==" | "<=" | ">=" | "!=" | "<" | ">" ;
expression = expression WS "<<" WS term | expression WS ">>" WS shiftand | shiftand ; expression = expression WS "<<" WS term | expression WS right_shift WS shiftand | shiftand ;
shiftand = shiftand WS "-" WS term | shiftand WS "\+" WS term | term ; shiftand = shiftand WS "-" WS term | shiftand WS "\+" WS term | term ;
term = term WS forward_slash WS factor | term WS "\*" WS factor | term WS "%" WS factor | factor ; term = term WS forward_slash WS factor | term WS "\*" WS factor | term WS "%" WS factor | factor ;
factor = "\+\+" WS unarad | unarad WS "\+\+" | "--" WS unarad | unarad WS "--" | "\+" WS unarad | "-" WS unarad | "!" WS unarad | "~" WS unarad | "\(" WS type WS "\)" WS unarad | "\*" WS unarad | "&" WS unarad | unarad ; factor = "\+\+" WS unarad | unarad WS "\+\+" | "--" WS unarad | unarad WS "--" | "\+" WS unarad | "-" WS unarad | "!" WS unarad | "~" WS unarad | "\(" WS type WS "\)" WS unarad | "\*" WS unarad | "&" WS unarad | unarad ;
unarad = number | identifier | function_call | bool | string | character | "\(" WS boolean_expression WS "\)" | access_operation ; unarad = number | identifier | identifier WS template_inst | function_call | bool | string | character | "\(" WS boolean_expression WS "\)" | access_operation | unarad WS "[" WS expression WS "]" ;
number = integer | float | double ; number = integer | floating_literal ;
access_operation = unarad "." identifier | unarad "->" identifier ; access_operation = unarad "." identifier | unarad "->" identifier ;
assignment_statement = factor WS "=" WS boolean_expression | factor WS "\+=" WS boolean_expression | factor WS "-=" WS boolean_expression | factor WS "\*=" WS boolean_expression | factor WS "/=" WS boolean_expression ; assignment_statement = factor WS "=" WS boolean_expression | factor WS "\+=" WS boolean_expression | factor WS "-=" WS boolean_expression | factor WS "\*=" WS boolean_expression | factor WS "/=" WS boolean_expression ;
declaration_statement = type WS identifier WS "=" WS boolean_expression | type WS identifier ; declaration_statement = dec_type WS identifier WS "=" WS boolean_expression | dec_type WS identifier | dec_type WS identifier WS "." WS identifier WS "\(" WS opt_parameter_list WS "\)" ;
alphanumeric = alphanumeric numeric | alphanumeric alpha | numeric | alpha ; alphanumeric = alphanumeric numeric | alphanumeric alpha | numeric | alpha ;
hexadecimal = "0x(1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)+" ; hexadecimal = "0x(1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)+" ;
sign = "\+|-" WS | ; sign = "\+|-" WS | ;
integer = sign numeric | sign hexadecimal | "null" ; integer = sign numeric | sign hexadecimal ;
float = sign numeric "." numeric "f" ; floating_literal = sign numeric "." numeric | sign numeric "." numeric alpha ;
double = sign numeric "." numeric | sign numeric "." numeric "d" ;
bool = "true" | "false" | "True" | "False" ; bool = "true" | "false" | "True" | "False" ;
character = "'(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'| character = "'(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'|
|z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|\"|Z|X|C|V|B|N|M|<|>|\?| )'" ; |z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|\"|Z|X|C|V|B|N|M|<|>|\?| )'" ;

View File

@@ -14,24 +14,56 @@
#include "Importer.h" #include "Importer.h"
#include "ASTData.h" #include "ASTData.h"
#include "CGenerator.h" #include "CGenerator.h"
#include "Poset.h"
#include "util.h" #include "util.h"
#include "Tester.h"
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
if (argc == 2 && std::string(argv[1]) == "--test") { std::vector<std::string> includePaths;
includePaths.push_back(""); //Local
if (argc <= 1) {
std::cout << "Kraken invocation: kraken sourceFile.krak grammerFile.kgm outputName" << std::endl;
std::cout << "Or for testing do: kraken --test [optional list of names of file (.krak .expected_results) without extentions to run]" << std::endl;
return 0;
}
if (argc >= 2 && std::string(argv[1]) == "--test") {
StringReader::test(); StringReader::test();
RegEx::test(); RegEx::test();
Lexer::test(); Lexer::test();
//std::cout << strSlice("123", 0, -1) << std::endl; //std::cout << strSlice("123", 0, -1) << std::endl;
Poset<int>::test();
if (argc >= 3) {
std::string testResults, line;
int passed = 0, failed = 0;
Tester test(argv[0], "../krakenGrammer.kgm");
for (int i = 2; i < argc; i++) {
bool result = test.run(argv[i]);
if (result)
line = std::string(argv[i]) + "\t\tpassed!\n", passed++;
else
line = std::string(argv[i]) + "\t\tFAILED!\n", failed++;
std::cout << line << std::endl;
testResults += line;
}
std::cout << "===========Done Testing===========" << std::endl;
std::cout << testResults << std::endl;
std::cout << "Test results: " << passed << "/" << passed+failed << std::endl;
}
return 0; return 0;
} }
std::string krakenDir = argv[0];
krakenDir = strSlice(krakenDir, 0, -(std::string("kraken").length()+1));
includePaths.push_back(krakenDir + "stdlib/"); //Add the stdlib directory that exists in the same directory as the kraken executable to the path
std::string programName = argv[1]; std::string programName = argv[1];
std::string grammerFileString = argv[2]; std::string grammerFileString = argv[2];
std::string outputName = argv[3]; std::string outputName = argv[3];
std::ifstream grammerInFile, compiledGrammerInFile; std::ifstream grammerInFile, compiledGrammerInFile;
std::ofstream /*outFileC,*/ compiledGrammerOutFile; std::ofstream compiledGrammerOutFile;
grammerInFile.open(grammerFileString); grammerInFile.open(grammerFileString);
if (!grammerInFile.is_open()) { if (!grammerInFile.is_open()) {
@@ -40,17 +72,9 @@ int main(int argc, char* argv[]) {
} }
compiledGrammerInFile.open(grammerFileString + ".comp", std::ios::binary | std::ios::ate); compiledGrammerInFile.open(grammerFileString + ".comp", std::ios::binary | std::ios::ate);
if (!compiledGrammerInFile.is_open()) { if (!compiledGrammerInFile.is_open())
std::cout << "Problem opening compiledGrammerInFile " << grammerFileString + ".comp" << "\n"; std::cout << "Problem opening compiledGrammerInFile " << grammerFileString + ".comp" << "\n";
//return(1);
}
/*
outFileC.open((outputName + ".c").c_str());
if (!outFileC.is_open()) {
std::cout << "Probelm opening third output file " << outputName + ".c" << "\n";
return(1);
}
*/
//Read the input file into a string //Read the input file into a string
std::string grammerInputFileString; std::string grammerInputFileString;
std::string line; std::string line;
@@ -63,8 +87,6 @@ int main(int argc, char* argv[]) {
//LALRParser parser; //LALRParser parser;
RNGLRParser parser; RNGLRParser parser;
parser.loadGrammer(grammerInputFileString); parser.loadGrammer(grammerInputFileString);
//std::cout << "Creating State Set from Main" << std::endl;
//std::cout << "\nState Set" << std::endl;
//Start binary stuff //Start binary stuff
bool compGramGood = false; bool compGramGood = false;
@@ -88,7 +110,6 @@ int main(int argc, char* argv[]) {
} else { } else {
compGramGood = true; compGramGood = true;
std::cout << "Grammer file is up to date." << std::endl; std::cout << "Grammer file is up to date." << std::endl;
//int tableLength = *((int*)(binaryTablePointer + 4 + sizeof(int) + gramStringLength));
parser.importTable(binaryTablePointer + 4 + sizeof(int) + gramStringLength); //Load table starting at the table section parser.importTable(binaryTablePointer + 4 + sizeof(int) + gramStringLength); //Load table starting at the table section
} }
} else { } else {
@@ -118,40 +139,23 @@ int main(int argc, char* argv[]) {
} }
//End binary stuff //End binary stuff
//std::cout << "finished State Set from Main" << std::endl;
//std::cout << "Doing stateSetToString from Main" << std::endl;
// std::cout << "\n\n\n\n\n\n\n\n\n\nState Set toString" << std::endl;
// std::cout << parser.stateSetToString() << std::endl;
// std::cout << "finished stateSetToString from Main" << std::endl;
// std::cout << "\n\n\n\n\n\n\n\n\n\nTable" << std::endl;
// std::cout << parser.tableToString() << std::endl;
// std::cout << "\n\n\n\n\n\n\n\n\n\nGrammer Input File" << std::endl;
// std::cout << grammerInputFileString << std::endl;
// std::cout << "\n\n\n\n\n\n\n\n\n\nGrammer toString" << std::endl;
// std::cout << parser.grammerToString() << std::endl;
//std::cout << parser.grammerToDOT() << std::endl;
//outFile << parser.grammerToDOT() << std::endl;
std::cout << "\nParsing" << std::endl; std::cout << "\nParsing" << std::endl;
Importer importer(&parser); Importer importer(&parser, includePaths);
for (auto i : includePaths)
std::cout << i << std::endl;
/*NodeTree<ASTData>* AST =*/
importer.import(programName); importer.import(programName);
std::map<std::string, NodeTree<ASTData>*> ASTs = importer.getASTMap(); std::map<std::string, NodeTree<ASTData>*> ASTs = importer.getASTMap();
//Do optomization, etc. here. //Do optimization, etc. here.
//None at this time, instead going straight to C in this first (more naive) version //None at this time, instead going straight to C in this first (more naive) version
//Code generation //Code generation
//For right now, just C //For right now, just C
CGenerator().generateCompSet(ASTs, outputName); CGenerator().generateCompSet(ASTs, outputName);
/*
std::string c_code = CGenerator().generate(AST);
outFileC << c_code << std::endl;
outFileC.close();
*/
return(0); return(0);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -15,7 +15,8 @@ void CGenerator::generateCompSet(std::map<std::string, NodeTree<ASTData>*> ASTs,
std::ofstream outputCFile; std::ofstream outputCFile;
outputCFile.open(i->first + ".c"); outputCFile.open(i->first + ".c");
if (outputCFile.is_open()) { if (outputCFile.is_open()) {
outputCFile << generate(i->second); // Prequel common to all files
outputCFile << "#include <stdbool.h>\n#include <stdlib.h>\n#include <stdio.h>\n" << generate(i->second);
} else { } else {
std::cout << "Cannot open file " << i->first << ".c" << std::endl; std::cout << "Cannot open file " << i->first << ".c" << std::endl;
} }
@@ -35,59 +36,163 @@ std::string CGenerator::tabs() {
return returnTabs; return returnTabs;
} }
std::string CGenerator::generateClassStruct(NodeTree<ASTData>* from) {
auto data = from->getData();
auto children = from->getChildren();
std::string objectString = "struct __struct_dummy_" + CifyName(data.symbol.getName()) + "__ {\n";
tabLevel++;
for (int i = 0; i < children.size(); i++) {
std::cout << children[i]->getName() << std::endl;
if (children[i]->getName() != "function")
objectString += tabs() + generate(children[i], nullptr) + "\n";
}
tabLevel--;
objectString += "};";
return objectString;
}
// This method recurseivly generates all aliases of some definition
std::string CGenerator::generateAliasChains(NodeTree<ASTData>* scopeNode, NodeTree<ASTData>* definition) {
auto scope = scopeNode->getDataRef()->scope;
std::string output;
for (auto i = scope.begin(); i != scope.end(); i++) {
for (auto declaration : i->second) {
auto declarationData = declaration->getDataRef();
if (declarationData->type == type_def
&& declarationData->valueType->typeDefinition != declaration
&& declarationData->valueType->typeDefinition == definition) {
output += "typedef " + CifyName(definition->getDataRef()->symbol.getName()) + " " + CifyName(declarationData->symbol.getName()) + ";\n";
// Recursively add the ones that depend on this one
output += generateAliasChains(scopeNode, declaration);
}
}
}
return output;
}
//The enclosing object is for when we're generating the inside of object methods. They allow us to check scope lookups against the object we're in //The enclosing object is for when we're generating the inside of object methods. They allow us to check scope lookups against the object we're in
std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enclosingObject) { std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enclosingObject) {
ASTData data = from->getData(); ASTData data = from->getData();
std::vector<NodeTree<ASTData>*> children = from->getChildren(); std::vector<NodeTree<ASTData>*> children = from->getChildren();
std::string output = ""; std::string output;
switch (data.type) { switch (data.type) {
case translation_unit: case translation_unit:
//Do here because we may need the typedefs before the declarations of variables {
for (int i = 0; i < children.size(); i++) // Ok, so we've got to do this in passes to preserve mututally recursive definitions.
if (children[i]->getDataRef()->type == type_def) //
output += generate(children[i], enclosingObject) + "\n"; // First Pass: All classes get "struct dummy_thing; typedef struct dummy_thing thing;".
// Also, other typedefs follow after their naming.
// Second Pass: All top level variable declarations
// Third Pass: Define all actual structs of a class, in correct order (done with posets)
// Fourth Pass: Declare all function prototypes (as functions may be mutually recursive too).
// (this includes object methods)
// Fifth Pass: Define all functions (including object methods).
// However, most of these do not actually have to be done as separate passes. First, second, fourth, and fifth
// are done simultanously, but append to different strings that are then concatinated properly, in order.
std::string plainTypedefs = "/**\n * Plain Typedefs\n */\n\n";
std::string variableDeclarations = "/**\n * Variable Declarations \n */\n\n";
std::string classStructs = "/**\n * Class Structs\n */\n\n";
std::string functionPrototypes = "/**\n * Function Prototypes\n */\n\n";
std::string functionDefinitions = "/**\n * Function Definitions\n */\n\n";
Poset<NodeTree<ASTData>*> typedefPoset;
for (int i = 0; i < children.size(); i++) {
if (children[i]->getDataRef()->type == type_def) {
// If we're an alias type, continue. We handle those differently
if (children[i]->getDataRef()->valueType->typeDefinition != children[i])
continue;
typedefPoset.addVertex(children[i]); // We add this definition by itself just in case there are no dependencies.
// If it has dependencies, there's no harm in adding it here
// Go through every child in the class looking for declaration statements. For each of these that is not a primitive type
// we will add a dependency from this definition to that definition in the poset.
std::vector<NodeTree<ASTData>*> classChildren = children[i]->getChildren();
for (auto j : classChildren) {
if (j->getDataRef()->type == declaration_statement) {
Type* decType = j->getChildren()[0]->getDataRef()->valueType; // Type of the declaration
if (decType->typeDefinition && decType->getIndirection() == 0) // If this is a custom type and not a pointer
typedefPoset.addRelationship(children[i], decType->typeDefinition); // Add a dependency
}
}
}
}
//Now generate the typedef's in the correct, topological order
for (NodeTree<ASTData>* i : typedefPoset.getTopoSort())
classStructs += generateClassStruct(i) + "\n";
//Declare everything in translation unit scope here. (allows stuff from other files, automatic forward declarations) //Declare everything in translation unit scope here. (allows stuff from other files, automatic forward declarations)
for (auto i = data.scope.begin(); i != data.scope.end(); i++) { for (auto i = data.scope.begin(); i != data.scope.end(); i++) {
for (auto overloadedMembers : i->second) { for (auto declaration : i->second) {
NodeTree<ASTData>* declaration = overloadedMembers;
std::vector<NodeTree<ASTData>*> decChildren = declaration->getChildren(); std::vector<NodeTree<ASTData>*> decChildren = declaration->getChildren();
ASTData declarationData = declaration->getData(); ASTData declarationData = declaration->getData();
switch(declarationData.type) { switch(declarationData.type) {
case identifier: case identifier:
output += ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "; /*identifier*/\n"; variableDeclarations += ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "; /*identifier*/\n";
break; break;
case function: case function:
{ {
if (decChildren.size() == 0) { //Not a real function, must be a built in passthrough { if (declarationData.valueType->baseType == template_type)
output += "/* built in function: " + declarationData.toString() + " */\n"; functionPrototypes += "/* template function " + declarationData.symbol.toString() + " */\n";
break; else if (decChildren.size() == 0) //Not a real function, must be a built in passthrough
functionPrototypes += "/* built in function: " + declarationData.symbol.toString() + " */\n";
else {
functionPrototypes += "\n" + ValueTypeToCType(declarationData.valueType) + " ";
std::string nameDecoration, parameters;
for (int j = 0; j < decChildren.size()-1; j++) {
if (j > 0)
parameters += ", ";
parameters += ValueTypeToCType(decChildren[j]->getData().valueType) + " " + generate(decChildren[j], enclosingObject);
nameDecoration += "_" + ValueTypeToCTypeDecoration(decChildren[j]->getData().valueType);
}
functionPrototypes += CifyName(declarationData.symbol.getName() + nameDecoration) + "(" + parameters + "); /*func*/\n";
// Only generate function if this is the unit it was defined in
std::cout << "Generating " << CifyName(declarationData.symbol.getName()) << std::endl;
if (contains(children, declaration))
functionDefinitions += generate(declaration, enclosingObject);
} }
output += "\n" + ValueTypeToCType(declarationData.valueType) + " ";
std::string nameDecoration, parameters;
for (int j = 0; j < decChildren.size()-1; j++) {
if (j > 0)
parameters += ", ";
parameters += ValueTypeToCType(decChildren[j]->getData().valueType) + " " + generate(decChildren[j], enclosingObject);
nameDecoration += "_" + ValueTypeToCTypeDecoration(decChildren[j]->getData().valueType);
}
output += CifyFunctionName(declarationData.symbol.getName()) + nameDecoration + "(" + parameters + "); /*func*/\n";
break;
} }
case type_def:
//type
output += "/*typedef " + declarationData.symbol.getName() + " */\n";
break; break;
case type_def:
//type
plainTypedefs += "/*typedef " + declarationData.symbol.getName() + " */\n";
if (declarationData.valueType->baseType == template_type) {
plainTypedefs += "/* non instantiated template " + declarationData.symbol.getName() + " */";
} else if (declarationData.valueType->typeDefinition != declaration) {
if (declarationData.valueType->typeDefinition)
continue; // Aliases of objects are done with the thing it alises
// Otherwise, we're actually a renaming of a primitive, can generate here
plainTypedefs += "typedef " + ValueTypeToCType(declarationData.valueType) + " " + CifyName(declarationData.symbol.getName()) + ";\n";
plainTypedefs += generateAliasChains(from, declaration);
} else {
plainTypedefs += "typedef struct __struct_dummy_" + CifyName(declarationData.symbol.getName()) + "__ " + CifyName(declarationData.symbol.getName()) + ";\n";
functionPrototypes += "/* Method Prototypes for " + declarationData.symbol.getName() + " */\n";
// We use a seperate string for this because we only include it if this is the file we're defined in
std::string objectFunctionDefinitions = "/* Method Definitions for " + declarationData.symbol.getName() + " */\n";
for (int j = 0; j < decChildren.size(); j++) {
std::cout << decChildren[j]->getName() << std::endl;
if (decChildren[j]->getName() == "function") //If object method
objectFunctionDefinitions += generateObjectMethod(declaration, decChildren[j], &functionPrototypes) + "\n";
}
// Add all aliases to the plain typedefs. This will add any alias that aliases to this object, and any alias that aliases to that, and so on
plainTypedefs += generateAliasChains(from, declaration);
functionPrototypes += "/* Done with " + declarationData.symbol.getName() + " */\n";
// If this is the file the object is defined in, include methods
if (contains(children, declaration))
functionDefinitions += objectFunctionDefinitions + "/* Done with " + declarationData.symbol.getName() + " */\n";
}
break;
default: default:
//std::cout << "Declaration? named " << declaration->getName() << " of unknown type " << ASTData::ASTTypeToString(declarationData.type) << " in translation unit scope" << std::endl; //std::cout << "Declaration? named " << declaration->getName() << " of unknown type " << ASTData::ASTTypeToString(declarationData.type) << " in translation unit scope" << std::endl;
output += "/*unknown declaration named " + declaration->getName() + "*/\n"; output += "/*unknown declaration named " + declaration->getName() + "*/\n";
} }
} }
} }
//Do here because we need the newlines output += plainTypedefs + variableDeclarations + classStructs + functionPrototypes + functionDefinitions;
for (int i = 0; i < children.size(); i++)
if (children[i]->getDataRef()->type != type_def)
output += generate(children[i], enclosingObject) + "\n";
return output; return output;
}
break; break;
case interpreter_directive: case interpreter_directive:
//Do nothing //Do nothing
@@ -97,33 +202,22 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
//return "#include <" + data.symbol.getName() + ">\n"; //return "#include <" + data.symbol.getName() + ">\n";
case identifier: case identifier:
{ {
//If we're in an object method, and our enclosing scope is that object, we're a member of the object and should use the self reference. //but first, if we're this, we should just emit. (assuming enclosing object) (note that technically this would fall through, but for errors)
if (data.symbol.getName() == "this")
if (enclosingObject)
return "this";
else
std::cout << "Error: this used in non-object scope" << std::endl;
//If we're in an object method, and our enclosing scope is that object, we're a member of the object and should use the this reference.
std::string preName; std::string preName;
if (enclosingObject && enclosingObject->getDataRef()->scope.find(data.symbol.getName()) != enclosingObject->getDataRef()->scope.end()) if (enclosingObject && enclosingObject->getDataRef()->scope.find(data.symbol.getName()) != enclosingObject->getDataRef()->scope.end())
preName += "self->"; preName += "this->";
if (false) return preName + CifyName(data.symbol.getName()); //Cifying does nothing if not an operator overload
for (int j = 0; j < children.size()-1; j++)
preName += ValueTypeToCType(children[j]->getData().valueType) + "_";
return preName + CifyFunctionName(data.symbol.getName()); //Cifying does nothing if not an operator overload
} }
case type_def:
if (children.size() == 0) {
return "typedef " + ValueTypeToCType(data.valueType) + " " + data.symbol.getName() + ";";
} else {
std::string objectString = "typedef struct __struct_dummy_" + data.symbol.getName() + "__ {\n";
std::string postString; //The functions have to be outside the struct definition
for (int i = 0; i < children.size(); i++) {
std::cout << children[i]->getName() << std::endl;
if (children[i]->getName() == "function") //If object method
postString += generateObjectMethod(from, children[i]) + "\n";
else
objectString += generate(children[i], enclosingObject) + "\n";
}
objectString += "} " + data.symbol.getName() + ";";
return objectString + postString; //Functions come after the declaration of the struct
}
case function: case function:
{ {
if (data.valueType->baseType == template_type)
return "/* template function: " + data.symbol.getName() + " */";
output += "\n" + ValueTypeToCType(data.valueType) + " "; output += "\n" + ValueTypeToCType(data.valueType) + " ";
std::string nameDecoration, parameters; std::string nameDecoration, parameters;
for (int j = 0; j < children.size()-1; j++) { for (int j = 0; j < children.size()-1; j++) {
@@ -132,22 +226,39 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
parameters += ValueTypeToCType(children[j]->getData().valueType) + " " + generate(children[j], enclosingObject); parameters += ValueTypeToCType(children[j]->getData().valueType) + " " + generate(children[j], enclosingObject);
nameDecoration += "_" + ValueTypeToCTypeDecoration(children[j]->getData().valueType); nameDecoration += "_" + ValueTypeToCTypeDecoration(children[j]->getData().valueType);
} }
output += CifyFunctionName(data.symbol.getName()) + nameDecoration + "(" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); output += CifyName(data.symbol.getName() + nameDecoration) + "(" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject);
return output; return output;
} }
case code_block: case code_block:
{
output += "{\n"; output += "{\n";
tabLevel++; std::string destructorString = "";
tabLevel++;
for (int i = 0; i < children.size(); i++) { for (int i = 0; i < children.size(); i++) {
//std::cout << "Line " << i << std::endl; //std::cout << "Line " << i << std::endl;
std::string line = generate(children[i], enclosingObject); std::string line = generate(children[i], enclosingObject);
//std::cout << line << std::endl; //std::cout << line << std::endl;
output += line; output += line;
} if (children[i]->getChildren().size() && children[i]->getChildren()[0]->getDataRef()->type == declaration_statement) {
tabLevel--; NodeTree<ASTData> *identifier = children[i]->getChildren()[0]->getChildren()[0];
Type* declarationType = identifier->getDataRef()->valueType;
if (declarationType->getIndirection())
continue;
NodeTree<ASTData> *typeDefinition = declarationType->typeDefinition;
if (!typeDefinition)
continue;
if (typeDefinition->getDataRef()->scope.find("destruct") == typeDefinition->getDataRef()->scope.end())
continue;
destructorString += tabs() + CifyName(typeDefinition->getDataRef()->symbol.getName())
+ "__" + "destruct" + "(&" + generate(identifier, enclosingObject) + ");\n";//Call the destructor
}
}
output += destructorString;
tabLevel--;
output += tabs() + "}"; output += tabs() + "}";
return output; return output;
case expression: }
case expression:
output += " " + data.symbol.getName() + ", "; output += " " + data.symbol.getName() + ", ";
case boolean_expression: case boolean_expression:
output += " " + data.symbol.getName() + " "; output += " " + data.symbol.getName() + " ";
@@ -175,7 +286,12 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
case declaration_statement: case declaration_statement:
if (children.size() == 1) if (children.size() == 1)
return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + ";"; return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + ";";
else else if (children[1]->getChildren().size() && children[1]->getChildren()[0]->getChildren().size() > 1
&& children[1]->getChildren()[0]->getChildren()[1] == children[0]) {
//That is, if we're a declaration with an init position call (Object a.construct())
//We can tell if our function call (children[1])'s access operation([0])'s lhs ([1]) is the thing we just declared (children[0])
return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + "; " + generate(children[1]) + "/*Init Position Call*/";
} else
return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + " = " + generate(children[1], enclosingObject) + ";"; return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + " = " + generate(children[1], enclosingObject) + ";";
case if_comp: case if_comp:
if (generate(children[0], enclosingObject) == generatorString) if (generate(children[0], enclosingObject) == generatorString)
@@ -198,11 +314,13 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
if (funcType == function) { if (funcType == function) {
if (name == "++" || name == "--") if (name == "++" || name == "--")
return generate(children[1], enclosingObject) + name; return generate(children[1], enclosingObject) + name;
if (name == "*" && children.size() == 2) //Is dereference, not multiplication if ( (name == "*" || name == "&" || name == "!" ) && children.size() == 2) //Is dereference, not multiplication, address-of, or other unary operator
return "*(" + generate(children[1], enclosingObject) + ")"; return name + "(" + generate(children[1], enclosingObject) + ")";
if (name == "[]")
return "(" + generate(children[1], enclosingObject) + ")[" +generate(children[2],enclosingObject) + "]";
if (name == "+" || name == "-" || name == "*" || name == "/" || name == "==" || name == ">=" || name == "<=" || name == "!=" if (name == "+" || name == "-" || name == "*" || name == "/" || name == "==" || name == ">=" || name == "<=" || name == "!="
|| name == "<" || name == ">" || name == "%" || name == "+=" || name == "-=" || name == "*=" || name == "/=" || name == "||" || name == "<" || name == ">" || name == "%" || name == "+=" || name == "-=" || name == "*=" || name == "/=" || name == "||"
|| name == "&&" || name == "!" ) || name == "&&")
return "((" + generate(children[1], enclosingObject) + ")" + name + "(" + generate(children[2], enclosingObject) + "))"; return "((" + generate(children[1], enclosingObject) + ")" + name + "(" + generate(children[2], enclosingObject) + "))";
else if (name == "." || name == "->") { else if (name == "." || name == "->") {
if (children.size() == 1) if (children.size() == 1)
@@ -212,18 +330,24 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
std::string functionName = children[2]->getDataRef()->symbol.getName(); std::string functionName = children[2]->getDataRef()->symbol.getName();
NodeTree<ASTData>* possibleObjectType = children[1]->getDataRef()->valueType->typeDefinition; NodeTree<ASTData>* possibleObjectType = children[1]->getDataRef()->valueType->typeDefinition;
//If is an object method, generate it like one. Needs extension/modification for inheritence //If is an object method, generate it like one. Needs extension/modification for inheritence
if (possibleObjectType && possibleObjectType->getDataRef()->scope.find(functionName) != possibleObjectType->getDataRef()->scope.end()) { if (possibleObjectType) {
std::string nameDecoration; NodeTree<ASTData>* unaliasedTypeDef = getMethodsObjectType(possibleObjectType, functionName);
std::vector<NodeTree<ASTData>*> functionDefChildren = children[2]->getChildren(); //The function def is the rhs of the access operation if (unaliasedTypeDef) { //Test to see if the function's a member of this type_def, or if this is an alias, of the original type. Get this original type if it exists.
std::cout << "Decorating (in access-should be object) " << name << " " << functionDefChildren.size() << std::endl; std::string nameDecoration;
for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++) std::vector<NodeTree<ASTData>*> functionDefChildren = children[2]->getChildren(); //The function def is the rhs of the access operation
nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType); std::cout << "Decorating (in access-should be object) " << name << " " << functionDefChildren.size() << std::endl;
/*HERE*/ return possibleObjectType->getDataRef()->symbol.getName() +"__" + CifyFunctionName(functionName) + nameDecoration + "(" + (name == "." ? "&" : "") + generate(children[1], enclosingObject) + ","; for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++)
//The comma lets the upper function call know we already started the param list nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType);
//Note that we got here from a function call. We just pass up this special case and let them finish with the perentheses /*HERE*/ return CifyName(unaliasedTypeDef->getDataRef()->symbol.getName()) +"__" + CifyName(functionName + nameDecoration) + "(" + (name == "." ? "&" : "") + generate(children[1], enclosingObject) + ",";
} else { //The comma lets the upper function call know we already started the param list
std::cout << "Is not in scope or not type" << std::endl; //Note that we got here from a function call. We just pass up this special case and let them finish with the perentheses
return "((" + generate(children[1], enclosingObject) + ")" + name + functionName + ")"; } else {
std::cout << "Is not in scope or not type" << std::endl;
return "((" + generate(children[1], enclosingObject) + ")" + name + functionName + ")";
}
} else {
std::cout << "Is not in scope or not type" << std::endl;
return "((" + generate(children[1], enclosingObject) + ")" + name + functionName + ")";
} }
} else { } else {
//return "((" + generate(children[1], enclosingObject) + ")" + name + generate(children[2], enclosingObject) + ")"; //return "((" + generate(children[1], enclosingObject) + ")" + name + generate(children[2], enclosingObject) + ")";
@@ -239,10 +363,10 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
//Check to see if we're inside of an object and this is a method call //Check to see if we're inside of an object and this is a method call
bool isSelfObjectMethod = enclosingObject && contains(enclosingObject->getChildren(), children[0]); bool isSelfObjectMethod = enclosingObject && contains(enclosingObject->getChildren(), children[0]);
if (isSelfObjectMethod) if (isSelfObjectMethod)
output += enclosingObject->getDataRef()->symbol.getName() +"__"; output += CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__";
/*HERE*/ output += CifyFunctionName(name) + nameDecoration + "("; /*HERE*/ output += CifyName(name + nameDecoration) + "(";
if (isSelfObjectMethod) if (isSelfObjectMethod)
output += children.size() > 1 ? "self," : "self"; output += children.size() > 1 ? "this," : "this";
} }
} else { } else {
//This part handles cases where our definition isn't the function definition (that is, it is probabally the return from another function) //This part handles cases where our definition isn't the function definition (that is, it is probabally the return from another function)
@@ -272,22 +396,29 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
return output; return output;
} }
NodeTree<ASTData>* CGenerator::getMethodsObjectType(NodeTree<ASTData>* scope, std::string functionName) {
//check the thing
while (scope != scope->getDataRef()->valueType->typeDefinition) //type is an alias, follow it to the definition
scope = scope->getDataRef()->valueType->typeDefinition;
return (scope->getDataRef()->scope.find(functionName) != scope->getDataRef()->scope.end()) ? scope : NULL;
}
std::string CGenerator::generateObjectMethod(NodeTree<ASTData>* enclosingObject, NodeTree<ASTData>* from) { // Returns the function prototype in the out param and the full definition normally
std::string output; std::string CGenerator::generateObjectMethod(NodeTree<ASTData>* enclosingObject, NodeTree<ASTData>* from, std::string *functionPrototype) {
ASTData data = from->getData(); ASTData data = from->getData();
Type enclosingObjectType = *(enclosingObject->getDataRef()->valueType); //Copy a new type so we can turn it into a pointer if we need to Type enclosingObjectType = *(enclosingObject->getDataRef()->valueType); //Copy a new type so we can turn it into a pointer if we need to
enclosingObjectType.indirection++; enclosingObjectType.increaseIndirection();
std::vector<NodeTree<ASTData>*> children = from->getChildren(); std::vector<NodeTree<ASTData>*> children = from->getChildren();
std::string nameDecoration, parameters; std::string nameDecoration, parameters;
for (int i = 0; i < children.size()-1; i++) { for (int i = 0; i < children.size()-1; i++) {
parameters += ", " + ValueTypeToCType(children[i]->getData().valueType) + " " + generate(children[i]); parameters += ", " + ValueTypeToCType(children[i]->getData().valueType) + " " + generate(children[i]);
nameDecoration += "_" + ValueTypeToCTypeDecoration(children[i]->getData().valueType); nameDecoration += "_" + ValueTypeToCTypeDecoration(children[i]->getData().valueType);
} }
output += "\n" + ValueTypeToCType(data.valueType) + " " + enclosingObject->getDataRef()->symbol.getName() +"__" std::string functionSignature = "\n" + ValueTypeToCType(data.valueType) + " " + CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__"
+ CifyFunctionName(data.symbol.getName()) + nameDecoration + "(" + ValueTypeToCType(&enclosingObjectType) + CifyName(data.symbol.getName()) + nameDecoration + "(" + ValueTypeToCType(&enclosingObjectType)
+ " self" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); //Pass in the object so we can properly handle access to member stuff + " this" + parameters + ")";
return output; *functionPrototype += functionSignature + ";\n";
return functionSignature + "\n" + generate(children[children.size()-1], enclosingObject); //Pass in the object so we can properly handle access to member stuff
} }
std::string CGenerator::ValueTypeToCType(Type *type) { std::string CGenerator::ValueTypeToCType(Type *type) {
@@ -295,7 +426,7 @@ std::string CGenerator::ValueTypeToCType(Type *type) {
switch (type->baseType) { switch (type->baseType) {
case none: case none:
if (type->typeDefinition) if (type->typeDefinition)
return_type = type->typeDefinition->getDataRef()->symbol.getName(); return_type = CifyName(type->typeDefinition->getDataRef()->symbol.getName());
else else
return_type = "none"; return_type = "none";
break; break;
@@ -321,7 +452,7 @@ std::string CGenerator::ValueTypeToCType(Type *type) {
return_type = "unknown_ValueType"; return_type = "unknown_ValueType";
break; break;
} }
for (int i = 0; i < type->indirection; i++) for (int i = 0; i < type->getIndirection(); i++)
return_type += "*"; return_type += "*";
return return_type; return return_type;
} }
@@ -331,7 +462,7 @@ std::string CGenerator::ValueTypeToCTypeDecoration(Type *type) {
switch (type->baseType) { switch (type->baseType) {
case none: case none:
if (type->typeDefinition) if (type->typeDefinition)
return_type = type->typeDefinition->getDataRef()->symbol.getName(); return_type = CifyName(type->typeDefinition->getDataRef()->symbol.getName());
else else
return_type = "none"; return_type = "none";
break; break;
@@ -357,12 +488,12 @@ std::string CGenerator::ValueTypeToCTypeDecoration(Type *type) {
return_type = "unknown_ValueType"; return_type = "unknown_ValueType";
break; break;
} }
for (int i = 0; i < type->indirection; i++) for (int i = 0; i < type->getIndirection(); i++)
return_type += "_P__"; return_type += "_P__";
return return_type; return return_type;
} }
std::string CGenerator::CifyFunctionName(std::string name) { std::string CGenerator::CifyName(std::string name) {
std::string operatorsToReplace[] = { "+", "plus", std::string operatorsToReplace[] = { "+", "plus",
"-", "minus", "-", "minus",
"*", "star", "*", "star",
@@ -392,7 +523,14 @@ std::string CGenerator::CifyFunctionName(std::string name) {
"|=", "pipeequals", "|=", "pipeequals",
"*=", "starequals", "*=", "starequals",
"<<=", "doublerightequals", "<<=", "doublerightequals",
"<", "lessthan",
">", "greaterthan",
">>=", "doubleleftequals", ">>=", "doubleleftequals",
"(", "openparen",
")", "closeparen",
"[", "openbracket",
"]", "closebracket",
" ", "space",
"->", "arrow" }; "->", "arrow" };
int length = sizeof(operatorsToReplace)/sizeof(std::string); int length = sizeof(operatorsToReplace)/sizeof(std::string);
//std::cout << "Length is " << length << std::endl; //std::cout << "Length is " << length << std::endl;

View File

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

View File

@@ -1,9 +1,12 @@
#include "Importer.h" #include "Importer.h"
Importer::Importer(Parser* parserIn) { Importer::Importer(Parser* parserIn, std::vector<std::string> includePaths) {
//constructor //constructor
parser = parserIn; parser = parserIn;
this->includePaths = includePaths;
ASTTransformer = new ASTTransformation(this);
removeSymbols.push_back(Symbol("$NULL$", true));
removeSymbols.push_back(Symbol("WS", false)); removeSymbols.push_back(Symbol("WS", false));
removeSymbols.push_back(Symbol("\\(", true)); removeSymbols.push_back(Symbol("\\(", true));
removeSymbols.push_back(Symbol("\\)", true)); removeSymbols.push_back(Symbol("\\)", true));
@@ -13,13 +16,15 @@ Importer::Importer(Parser* parserIn) {
removeSymbols.push_back(Symbol("}", true)); removeSymbols.push_back(Symbol("}", true));
removeSymbols.push_back(Symbol("(", true)); removeSymbols.push_back(Symbol("(", true));
removeSymbols.push_back(Symbol(")", true)); removeSymbols.push_back(Symbol(")", true));
removeSymbols.push_back(Symbol("import", true)); //Don't need the actual text of the symbol removeSymbols.push_back(Symbol("import", true));
removeSymbols.push_back(Symbol("interpreter_directive", false)); removeSymbols.push_back(Symbol("interpreter_directive", false));
removeSymbols.push_back(Symbol("if", true)); removeSymbols.push_back(Symbol("if", true));
removeSymbols.push_back(Symbol("while", true)); removeSymbols.push_back(Symbol("while", true));
removeSymbols.push_back(Symbol("__if_comp__", true)); removeSymbols.push_back(Symbol("__if_comp__", true));
removeSymbols.push_back(Symbol("comp_simple_passthrough", true)); removeSymbols.push_back(Symbol("comp_simple_passthrough", true));
removeSymbols.push_back(Symbol("typedef", true)); removeSymbols.push_back(Symbol("typedef", true));
removeSymbols.push_back(Symbol("template", true));
removeSymbols.push_back(Symbol("\\|", true));
collapseSymbols.push_back(Symbol("opt_typed_parameter_list", false)); collapseSymbols.push_back(Symbol("opt_typed_parameter_list", false));
collapseSymbols.push_back(Symbol("opt_parameter_list", false)); collapseSymbols.push_back(Symbol("opt_parameter_list", false));
@@ -31,23 +36,102 @@ Importer::Importer(Parser* parserIn) {
collapseSymbols.push_back(Symbol("unorderd_list_part", false)); collapseSymbols.push_back(Symbol("unorderd_list_part", false));
collapseSymbols.push_back(Symbol("if_comp_pred", false)); collapseSymbols.push_back(Symbol("if_comp_pred", false));
collapseSymbols.push_back(Symbol("declaration_block", false)); collapseSymbols.push_back(Symbol("declaration_block", false));
collapseSymbols.push_back(Symbol("type_list", false));
collapseSymbols.push_back(Symbol("template_param_list", false));
collapseSymbols.push_back(Symbol("trait_list", false));
collapseSymbols.push_back(Symbol("dec_type", false));
} }
Importer::~Importer() { Importer::~Importer() {
//destructor //destructor
delete ASTTransformer;
} }
NodeTree<ASTData>* Importer::import(std::string fileName) { void Importer::registerAST(std::string name, NodeTree<ASTData>* ast, NodeTree<Symbol>* syntaxTree) {
imported[name] = ast;
importedTrips.push_back({name, ast, syntaxTree});
std::cout << "REGISTERD " << name << std::endl;
}
NodeTree<ASTData>* Importer::getUnit(std::string fileName) {
std::cout << "\n\nImporting " << fileName << " ";
//Check to see if we've already done it //Check to see if we've already done it
if (imported.find(fileName) != imported.end()) if (imported.find(fileName) != imported.end()) {
std::cout << "Already Imported!" << std::endl;
return imported[fileName]; return imported[fileName];
}
std::cout << "Not yet imported" << std::endl;
return NULL;
}
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
}
return ast;
}
void Importer::import(std::string fileName) {
//Start the ball rolling by importing and running the first pass on the first file.
//This will import, first pass and register all the other files too.
std::cout << "\n\n =====FIRST PASS===== \n\n" << std::endl;
importFirstPass(fileName); //First pass defines all objects
std::cout << "\n\n =====SECOND PASS===== \n\n" << std::endl;
for (importTriplet i : importedTrips) //Second pass defines data inside objects, outside declaration statements,
std::cout << "\n\nSecond pass for: " << i.name << std::endl, ASTTransformer->secondPass(i.ast, i.syntaxTree); //function prototypes, and identifiers (as we now have all type defs)
std::cout << "\n\n =====THIRD PASS===== \n\n" << std::endl;
for (importTriplet i : importedTrips) //Third pass redoes all imports to import the new function prototypes and identifiers
std::cout << "\n\nThird pass for: " << i.name << std::endl, ASTTransformer->thirdPass(i.ast);
std::cout << "\n\n =====FOURTH PASS===== \n\n" << std::endl;
for (importTriplet i : importedTrips) //Fourth pass finishes up by doing all function bodies
std::cout << "\n\nFourth pass for: " << i.name << std::endl, ASTTransformer->fourthPass(i.ast, i.syntaxTree); //With that, we're done
//Note that class template instantiation can happen in the second or fourth passes and that function template instantion
//can happen in the fourth pass.
std::ofstream outFileAST;
for (importTriplet i : importedTrips) {
std::string outputName = i.name + "out";
outFileAST.open((outputName + ".AST.dot").c_str());
if (!outFileAST.is_open()) {
std::cout << "Problem opening second output file " << outputName + ".AST.dot" << "\n";
return;
}
if (i.ast) {
outFileAST << i.ast->DOTGraphString() << std::endl;
} else {
std::cout << "Tree returned from ASTTransformation for " << fileName << " is NULL!" << std::endl;
}
outFileAST.close();
}
}
NodeTree<Symbol>* Importer::parseAndTrim(std::string fileName) {
std::ifstream programInFile; std::ifstream programInFile;
std::ofstream outFile, outFileTransformed, outFileAST; std::ofstream outFile, outFileTransformed;
std::string outputName = fileName + "out"; std::string outputName = fileName + "out";
programInFile.open(fileName); for (auto i : includePaths) {
programInFile.open(i+fileName);
if (programInFile.is_open())
break;
else
std::cout << i+fileName << " is no good" << std::endl;
}
if (!programInFile.is_open()) { if (!programInFile.is_open()) {
std::cout << "Problem opening programInFile " << fileName << "\n"; std::cout << "Problem opening programInFile " << fileName << "\n";
return NULL; return NULL;
@@ -65,12 +149,6 @@ NodeTree<ASTData>* Importer::import(std::string fileName) {
return NULL; return NULL;
} }
outFileAST.open((outputName + ".AST.dot").c_str());
if (!outFileAST.is_open()) {
std::cout << "Probelm opening second output file " << outputName + ".AST.dot" << "\n";
return NULL;
}
std::string programInputFileString, line; std::string programInputFileString, line;
while(programInFile.good()) { while(programInFile.good()) {
getline(programInFile, line); getline(programInFile, line);
@@ -85,8 +163,10 @@ NodeTree<ASTData>* Importer::import(std::string fileName) {
//std::cout << parseTree->DOTGraphString() << std::endl; //std::cout << parseTree->DOTGraphString() << std::endl;
outFile << parseTree->DOTGraphString() << std::endl; outFile << parseTree->DOTGraphString() << std::endl;
} else { } else {
std::cout << "ParseTree returned from parser is NULL!" << std::endl; std::cout << "ParseTree returned from parser for " << fileName << " is NULL!" << std::endl;
} outFile.close(); outFileTransformed.close();
return NULL;
}
outFile.close(); outFile.close();
//Remove Transformations //Remove Transformations
@@ -106,19 +186,7 @@ NodeTree<ASTData>* Importer::import(std::string fileName) {
} }
outFileTransformed.close(); outFileTransformed.close();
//Call with ourself to allow the transformation to call us to import files that it needs return parseTree;
NodeTree<ASTData>* AST = ASTTransformation(this).transform(parseTree);
if (AST) {
outFileAST << AST->DOTGraphString() << std::endl;
} else {
std::cout << "Tree returned from ASTTransformation is NULL!" << std::endl;
}
outFileAST.close();
imported[fileName] = AST;
return AST;
} }
std::map<std::string, NodeTree<ASTData>*> Importer::getASTMap() { std::map<std::string, NodeTree<ASTData>*> Importer::getASTMap() {

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); 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); 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)); 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) { std::string ParseAction::actionToString(ActionType action) {
switch (action) { switch (action) {
case REDUCE: case REDUCE:
@@ -53,11 +68,11 @@ std::string ParseAction::actionToString(ActionType action) {
} }
} }
std::string ParseAction::toString() { std::string ParseAction::toString(bool printRuleLookahead) {
std::string outputString = ""; std::string outputString = "";
outputString += actionToString(action); outputString += actionToString(action);
if (reduceRule != NULL) if (reduceRule != NULL)
outputString += " " + reduceRule->toString(); outputString += " " + reduceRule->toString(printRuleLookahead);
if (shiftState != -1) if (shiftState != -1)
outputString += " " + intToString(shiftState); outputString += " " + intToString(shiftState);
return(outputString); 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); 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))); 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)); 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() { ParseRule* ParseRule::clone() {
std::vector<Symbol>* newLookahead = NULL; std::vector<Symbol>* newLookahead = NULL;
if (lookahead) { if (lookahead) {
@@ -111,7 +127,7 @@ std::vector<Symbol>* ParseRule::getLookahead() {
return lookahead; return lookahead;
} }
std::string ParseRule::toString() { std::string ParseRule::toString(bool printLookahead) {
std::string concat = leftHandle.toString() + " -> "; std::string concat = leftHandle.toString() + " -> ";
for (int i = 0; i < rightSide.size(); i++) { for (int i = 0; i < rightSide.size(); i++) {
if (i == pointerIndex) if (i == pointerIndex)
@@ -120,7 +136,7 @@ std::string ParseRule::toString() {
} }
if (pointerIndex >= rightSide.size()) if (pointerIndex >= rightSide.size())
concat += "(*)"; concat += "(*)";
if (lookahead != NULL) { if (printLookahead && lookahead != NULL) {
concat += "**"; concat += "**";
for (std::vector<Symbol>::size_type i = 0; i < lookahead->size(); i++) for (std::vector<Symbol>::size_type i = 0; i < lookahead->size(); i++)
concat += (*lookahead)[i].toString(); concat += (*lookahead)[i].toString();

View File

@@ -32,10 +32,22 @@ Symbol Parser::getOrAddSymbol(std::string symbolString, bool isTerminal) {
void Parser::loadGrammer(std::string grammerInputString) { void Parser::loadGrammer(std::string grammerInputString) {
reader.setString(grammerInputString); reader.setString(grammerInputString);
std::string currToken = reader.word(); std::string currToken = reader.word(false); //Don't truncate so we can find the newline correctly (needed for comments)
while(currToken != "") { while(currToken != "") {
//Load the left of the rule //First, if this starts with a '#', skip this
if (currToken.front() == '#') {
//If this line is more than one token long, eat it
std::cout << "Ate: " << currToken << std::endl;
if (currToken.back() != '\n')
std::cout << "Eating " << reader.line() << " b/c grammer comment" << std::endl;
currToken = reader.word(false);
continue;
}
if (currToken.back() == '\n' || currToken.back() == ' ' || currToken.back() == '\t')
currToken.erase(currToken.size()-1);
//Load the left of the rule
ParseRule* currentRule = new ParseRule(); ParseRule* currentRule = new ParseRule();
Symbol leftSide = getOrAddSymbol(currToken, false); //Left handle is never a terminal Symbol leftSide = getOrAddSymbol(currToken, false); //Left handle is never a terminal
currentRule->setLeftHandle(leftSide); currentRule->setLeftHandle(leftSide);
@@ -76,7 +88,7 @@ void Parser::loadGrammer(std::string grammerInputString) {
loadedGrammer.push_back(currentRule); loadedGrammer.push_back(currentRule);
//Get next token //Get next token
currToken = reader.word(); currToken = reader.word(false);
} }
//std::cout << "Parsed!\n"; //std::cout << "Parsed!\n";
@@ -117,59 +129,86 @@ int Parser::stateNum(State* state) {
return -1; return -1;
} }
std::vector<Symbol>* Parser::firstSet(Symbol token) { std::vector<Symbol> Parser::firstSet(Symbol token, std::vector<Symbol> avoidList, bool addNewTokens) {
std::vector<Symbol> avoidList; if (tokenFirstSet.find(token) != tokenFirstSet.end())
return firstSet(token, avoidList); return tokenFirstSet[token];
} //If we've already done this token, don't do it again
std::vector<Symbol>* Parser::firstSet(Symbol token, std::vector<Symbol> avoidList) {
//If we've already done this token, don't do it again
for (std::vector<Symbol>::size_type i = 0; i < avoidList.size(); i++) for (std::vector<Symbol>::size_type i = 0; i < avoidList.size(); i++)
if (avoidList[i] == token) { if (avoidList[i] == token)
return new std::vector<Symbol>(); return std::vector<Symbol>();
}
avoidList.push_back(token); 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. //First, if the symbol is a terminal, than it's first set is just itself.
if (token.isTerminal()) { if (token.isTerminal()) {
first->push_back(token); first.push_back(token);
return(first); return(first);
} }
//Otherwise.... //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. //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). //If that one includes mull, do the next one too (if it exists).
Symbol rightToken; Symbol rightToken;
std::vector<Symbol>* recursiveFirstSet = NULL; std::vector<Symbol> recursiveFirstSet;
for (std::vector<ParseRule*>::size_type i = 0; i < loadedGrammer.size(); i++) { for (std::vector<ParseRule*>::size_type i = 0; i < loadedGrammer.size(); i++) {
if (token == loadedGrammer[i]->getLeftSide()) { if (token == loadedGrammer[i]->getLeftSide()) {
//Loop through the rule adding first sets for each token if the previous token contained NULL //Loop through the rule adding first sets for each token if the previous token contained NULL
bool recFirstSetHasNull = false;
int j = 0; int j = 0;
do { do {
rightToken = loadedGrammer[i]->getRightSide()[j]; //Get token of the right side of this rule rightToken = loadedGrammer[i]->getRightSide()[j]; //Get token of the right side of this rule
if (rightToken.isTerminal()) { if (rightToken.isTerminal()) {
recursiveFirstSet = new std::vector<Symbol>(); recursiveFirstSet.push_back(rightToken);
recursiveFirstSet->push_back(rightToken);
} else { } else {
//Add the entire set //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()); 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;
j++; j++;
} while (recFirstSetHasNull && loadedGrammer[i]->getRightSide().size() > j); } while (isNullable(rightToken) && loadedGrammer[i]->getRightSide().size() > j);
} }
} }
if (addNewTokens)
tokenFirstSet[token] = first;
return(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];
for (std::vector<ParseRule*>::size_type i = 0; i < loadedGrammer.size(); i++) {
if (token == loadedGrammer[i]->getLeftSide()) {
auto rightSide = loadedGrammer[i]->getRightSide();
bool ruleNullable = true;
for (int j = 0; j < rightSide.size(); j++) {
if (!isNullableHelper(rightSide[j], done)) {
ruleNullable = false;
break;
}
}
if (ruleNullable)
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. //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) { 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) //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 +217,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 //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>* followSet = new std::vector<Symbol>();
std::vector<Symbol>* symbolFirstSet; std::vector<Symbol> symbolFirstSet;
bool symbolFirstSetHasNull = true; bool symbolFirstSetHasNull = true;
while (symbolFirstSetHasNull && !rule->isAtEnd()) { while (symbolFirstSetHasNull && !rule->isAtEnd()) {
symbolFirstSetHasNull = false; symbolFirstSetHasNull = false;
symbolFirstSet = firstSet(rule->getAtNextIndex()); symbolFirstSet = firstSet(rule->getAtNextIndex());
for (std::vector<Symbol>::size_type i = 0; i < symbolFirstSet->size(); i++) { for (std::vector<Symbol>::size_type i = 0; i < symbolFirstSet.size(); i++) {
if ((*symbolFirstSet)[i] == nullSymbol) { if (symbolFirstSet[i] == nullSymbol) {
symbolFirstSetHasNull = true; symbolFirstSetHasNull = true;
symbolFirstSet->erase(symbolFirstSet->begin()+i); symbolFirstSet.erase(symbolFirstSet.begin()+i);
break; break;
} }
} }
followSet->insert(followSet->end(), symbolFirstSet->begin(), symbolFirstSet->end()); followSet->insert(followSet->end(), symbolFirstSet.begin(), symbolFirstSet.end());
delete symbolFirstSet;
rule->advancePointer(); rule->advancePointer();
} }
if (rule->isAtEnd()) { if (rule->isAtEnd()) {
symbolFirstSet = rule->getLookahead(); symbolFirstSet = *(rule->getLookahead());
followSet->insert(followSet->end(), symbolFirstSet->begin(), symbolFirstSet->end()); followSet->insert(followSet->end(), symbolFirstSet.begin(), symbolFirstSet.end());
} }
std::vector<Symbol>* followSetReturn = new std::vector<Symbol>(); std::vector<Symbol>* followSetReturn = new std::vector<Symbol>();
for (std::vector<Symbol>::size_type i = 0; i < followSet->size(); i++) { for (std::vector<Symbol>::size_type i = 0; i < followSet->size(); i++) {

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) { NodeTree<Symbol>* RNGLRParser::parseInput(std::string inputString) {
input.clear(); input.clear();
gss.clear(); gss.clear();
@@ -74,7 +88,6 @@ NodeTree<Symbol>* RNGLRParser::parseInput(std::string inputString) {
else if (firstActions[i]->action == ParseAction::REDUCE && fullyReducesToNull(firstActions[i]->reduceRule)) { else if (firstActions[i]->action == ParseAction::REDUCE && fullyReducesToNull(firstActions[i]->reduceRule)) {
Reduction newReduction = {v0, firstActions[i]->reduceRule->getLeftSide(), 0, getNullableParts(firstActions[i]->reduceRule), NULL}; Reduction newReduction = {v0, firstActions[i]->reduceRule->getLeftSide(), 0, getNullableParts(firstActions[i]->reduceRule), NULL};
toReduce.push(newReduction); 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 << "Parsing failed on " << input[i].toString() << std::endl;
std::cout << "Problem is on line: " << findLine(i) << std::endl; std::cout << "Problem is on line: " << findLine(i) << std::endl;
std::cout << "Nearby is:" << 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++) for (int j = (i-range >= 0 ? i-range : 0); j < (i+range < input.size() ? i+range : input.size()); j++)
if (j == i) if (j == i)
std::cout << "||*||*||" << input[j].toString() << "||*||*|| "; std::cout << "||*||*||" << input[j].toString() << "||*||*|| ";
else else
std::cout << input[j].toString() << " "; std::cout << input[j].toString() << " ";
std::cout << std::endl; std::cout << std::endl;
break; range = 1;
/* 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 //Clear the vector of SPPF nodes created every step

View File

@@ -353,6 +353,17 @@ ParseAction* Table::getShift(int state, Symbol token) {
return shift; 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 Table::toString() {
std::string concat = ""; std::string concat = "";
for (std::vector<Symbol>::size_type i = 0; i < symbolIndexVec.size(); i++) for (std::vector<Symbol>::size_type i = 0; i < symbolIndexVec.size(); i++)

69
src/Tester.cpp Normal file
View File

@@ -0,0 +1,69 @@
#include "Tester.h"
Tester::Tester(std::string krakenInvocation, std::string krakenGrammerLocation) : krakenInvocation(krakenInvocation), krakenGrammerLocation(krakenGrammerLocation) {
//initlization list
removeCmd = "rm";
resultsExtention = ".results";
expectedExtention = ".expected_results";
krakenExtention = ".krak";
changePermissions = "chmod 755";
shell = "sh";
redirect = ">";
}
Tester::~Tester() {
//Nothing
}
int Tester::ssystem(std::string command) {
return system(command.c_str());
}
void Tester::cleanExtras(std::string fileName) {
ssystem(removeCmd + " " + fileName);
ssystem(removeCmd + " " + fileName + krakenExtention + "out*");
ssystem(removeCmd + " " + fileName + krakenExtention + ".c");
ssystem(removeCmd + " " + fileName + ".sh");
ssystem(removeCmd + " " + fileName + resultsExtention);
}
bool Tester::run(std::string fileName) {
std::cout << "Testing: " << fileName << " with " << krakenInvocation << " and " << krakenGrammerLocation << std::endl;
cleanExtras(fileName);
ssystem(changePermissions + " " + fileName);
ssystem(krakenInvocation + " " + fileName + krakenExtention + " " + krakenGrammerLocation + " " + fileName);
ssystem(shell + " " + fileName + ".sh");
ssystem(fileName + " " + redirect + " " + fileName + resultsExtention);
bool result = compareFiles(fileName + expectedExtention, fileName + resultsExtention);
//If the test was succesful, we don't need all the extra files
if (result)
cleanExtras(fileName);
return result;
}
bool Tester::compareFiles(std::string file1Path, std::string file2Path) {
std::ifstream file1, file2;
file1.open(file1Path);
if (!file1.is_open()) {
std::cout << file1Path << " could not be opened!" << std::endl;
return false;
}
file2.open(file2Path);
if (!file2.is_open()) {
std::cout << file2Path << " could not be opened!" << std::endl;
return false;
}
std::string file1contents = readFile(file1);
std::string file2contents = readFile(file2);
// std::cout << "file1: " << file1contents << std::endl;
// std::cout << "file2: " << file2contents << std::endl;
// std::cout << "comp: " << file1contents.compare(file2contents) << std::endl;
return file1contents.compare(file2contents) == 0;
}

View File

@@ -4,49 +4,68 @@ Type::Type() {
indirection = 0; indirection = 0;
baseType = none; baseType = none;
typeDefinition = NULL; typeDefinition = NULL;
} templateDefinition = NULL;
Type::Type(ValueType typeIn) {
indirection = 0;
baseType = typeIn;
typeDefinition = NULL;
} }
Type::Type(ValueType typeIn, int indirectionIn) { Type::Type(ValueType typeIn, int indirectionIn) {
indirection = indirectionIn; indirection = indirectionIn;
baseType = typeIn; baseType = typeIn;
typeDefinition = NULL; typeDefinition = NULL;
templateDefinition = NULL;
} }
Type::Type(NodeTree<ASTData>* typeDefinitionIn) { Type::Type(ValueType typeIn, std::set<std::string> traitsIn) {
indirection = 0; indirection = 0;
baseType = none; baseType = typeIn;
typeDefinition = typeDefinitionIn; traits = traitsIn;
typeDefinition = NULL;
templateDefinition = NULL;
} }
Type::Type(NodeTree<ASTData>* typeDefinitionIn, int indirectionIn) { Type::Type(NodeTree<ASTData>* typeDefinitionIn, int indirectionIn) {
indirection = indirectionIn; indirection = indirectionIn;
baseType = none; baseType = none;
typeDefinition = typeDefinitionIn; typeDefinition = typeDefinitionIn;
templateDefinition = NULL;
} }
Type::Type(ValueType typeIn, NodeTree<ASTData>* typeDefinitionIn, int indirectionIn) { Type::Type(NodeTree<ASTData>* typeDefinitionIn, std::set<std::string> traitsIn) {
indirection = 0;
baseType = none;
typeDefinition = typeDefinitionIn;
traits = traitsIn;
templateDefinition = NULL;
}
Type::Type(ValueType typeIn, NodeTree<ASTData>* typeDefinitionIn, int indirectionIn, std::set<std::string> traitsIn) {
baseType = typeIn; baseType = typeIn;
indirection = indirectionIn; indirection = indirectionIn;
typeDefinition = typeDefinitionIn; typeDefinition = typeDefinitionIn;
traits = traitsIn;
templateDefinition = NULL;
} }
Type::Type(ValueType typeIn, NodeTree<Symbol>* templateDefinitionIn, std::set<std::string> traitsIn) {
indirection = 0;
baseType = typeIn;
typeDefinition = NULL;
templateDefinition = templateDefinitionIn;
traits = traitsIn;
}
Type::~Type() { Type::~Type() {
} }
const bool Type::operator==(const Type &other) const { const bool Type::operator==(const Type &other) const {
return( baseType == other.baseType && indirection == other.indirection && typeDefinition == other.typeDefinition); return( baseType == other.baseType && indirection == other.indirection && typeDefinition == other.typeDefinition && templateDefinition == other.templateDefinition && other.traits == traits);
} }
const bool Type::operator!=(const Type &other) const { const bool Type::operator!=(const Type &other) const {
return(!this->operator==(other)); return(!this->operator==(other));
} }
std::string Type::toString() { std::string Type::toString(bool showTraits) {
std::string typeString; std::string typeString;
switch (baseType) { switch (baseType) {
case none: case none:
@@ -55,6 +74,12 @@ std::string Type::toString() {
else else
typeString = "none"; typeString = "none";
break; break;
case template_type:
typeString = "template: " + templateDefinition->getDataRef()->toString();
break;
case template_type_type:
typeString = "template_type_type";
break;
case void_type: case void_type:
typeString = "void"; typeString = "void";
break; break;
@@ -81,5 +106,35 @@ std::string Type::toString() {
} }
for (int i = 0; i < indirection; i++) for (int i = 0; i < indirection; i++)
typeString += "*"; typeString += "*";
if (traits.size() && showTraits) {
typeString += "[ ";
for (auto i : traits)
typeString += i + " ";
typeString += "]";
}
//std::cout << "Extra components of " << typeString << " are " << indirection << " " << typeDefinition << " " << templateDefinition << std::endl;
return typeString; return typeString;
} }
Type* Type::clone() {
return new Type(baseType, typeDefinition, indirection, traits);
}
int Type::getIndirection() {
return indirection;
}
void Type::setIndirection(int indirectionIn) {
indirection = indirectionIn;
}
void Type::increaseIndirection() {
setIndirection(indirection+1);
}
void Type::decreaseIndirection() {
setIndirection(indirection-1);
}
void Type::modifyIndirection(int mod) {
setIndirection(indirection + mod);
}

View File

@@ -71,4 +71,13 @@ std::string join(const std::vector<std::string> &strVec, std::string joinStr) {
return joinedStr; return joinedStr;
} }
std::string readFile(std::istream &file) {
std::string line, contents;
while(file.good()) {
getline(file, line);
contents.append(line+"\n");
}
return contents;
}

59
stdlib/io.krak Normal file
View File

@@ -0,0 +1,59 @@
__if_comp__ __C__ __simple_passthrough__ """
#include <stdio.h>
"""
|void| println() {
print("\n");
}
|void| print(|char*| toPrint) {
__if_comp__ __C__ {
__simple_passthrough__ """
printf(toPrint);
"""
}
return;
}
|void| println(|char*| toPrint) {
print(toPrint);
println();
}
|void| print(|int| toPrint) {
__if_comp__ __C__ {
__simple_passthrough__ """
printf("%d", toPrint);
"""
}
return;
}
|void| println(|int| toPrint) {
print(toPrint);
println();
}
|void| print(|float| toPrint) {
__if_comp__ __C__ {
__simple_passthrough__ """
printf("%f", toPrint);
"""
}
return;
}
|void| print(|double| toPrint) {
__if_comp__ __C__ {
__simple_passthrough__ """
printf("%f", toPrint);
"""
}
return;
}
|void| println(|float| toPrint) {
print(toPrint);
println();
}

9
stdlib/math.krak Normal file
View File

@@ -0,0 +1,9 @@
|int| NotPi = 3;
|float| Pi = 3.141592654;
|int| fibanacci(|int| num) {
if (num < 2)
return 1;
return fibanacci(num-1) + fibanacci(num-2);
}

64
stdlib/mem.krak Normal file
View File

@@ -0,0 +1,64 @@
__if_comp__ __C__ __simple_passthrough__ """
#include <stdlib.h>
"""
/* we have a template versions so we don't have to cast (because we don't have that yet) */
template <T> |T*| malloc(|int| size) {
|T*| memPtr = 0;
__if_comp__ __C__ {
__simple_passthrough__ """
memPtr = malloc(size);
"""
}
return memPtr;
}
template <T> |void| free(|T*| memPtr) {
__if_comp__ __C__ {
__simple_passthrough__ """
free(memPtr);
"""
}
}
template <T> |int| sizeof() {
|int| result = 0;
|T| testObj;
__if_comp__ __C__ {
__simple_passthrough__ """
result = sizeof(testObj);
"""
}
return result;
}
template <T> |T*| new(|int| count) {
return malloc<T>( sizeof<T>() * count );
}
template <T> |T*| new() {
return new<T>(1);
}
/* We specilize on the trait Destructable to decide on whether or not the destructor should be called */
template <T> |void| delete(|T*| toDelete, |int| itemCount) {
delete<T>(toDelete);
}
/* Calling this with itemCount = 0 allows you to delete destructable objects without calling their destructors. */
template <T(Destructable)> |void| delete(|T*| toDelete, |int| itemCount) {
for (|int| i = 0; i < itemCount; i++;)
toDelete[i].destruct();
delete<T>(toDelete);
}
/* We specilize on the trait Destructable to decide on whether or not the destructor should be called */
template <T> |void| delete(|T*| toDelete) {
free(toDelete);
}
template <T(Destructable)> |void| delete(|T*| toDelete) {
toDelete->destruct();
free(toDelete);
}

View File

@@ -0,0 +1,9 @@
import io;
typedef template <T> trivialContainer {
|T| data;
|void| print() {
print(data);
}
};

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

55
stdlib/vector.krak Normal file
View File

@@ -0,0 +1,55 @@
import mem;
import util;
import io;
typedef template<T> vector (Destructable) {
|T*| data;
|int| size;
|int| available;
|vector<T>*| construct() {
size = 0;
available = 8;
data = new<T>(8);
return this;
}
|void| destruct() {
delete<T>(data);
}
|bool| resize(|int| newSize) {
|T*| newData = new<T>(newSize);
if (!newData)
return false;
for (|int| i = 0; i < lesser<int>(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) {
println("Vector access out of bounds! Retuning 0th element as sanest option");
return data[0];
}
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] = dataIn;
}
};

View File

@@ -0,0 +1,5 @@
3 9
6 18
Subtraction
3 9
-97 -61

View File

@@ -0,0 +1,64 @@
import io;
typedef Vec2 {
|int| x;
|int| y;
|void| print() {
print(x);
print(" ");
print(y);
}
|Vec2| add(|Vec2| other) {
|Vec2| toReturn;
toReturn.x = x + other.x;
toReturn.y = y + other.y;
print();
return toReturn;
}
|Vec2| subtract(|Vec2| other) {
|Vec2| toReturn;
toReturn.x = x - other.x;
toReturn.y = y - other.y;
print();
return toReturn;
}
|Vec2| operator+(|Vec2| other) {
return add(other);
}
};
|Vec2| operator-(|Vec2| lhs, |Vec2| rhs) {
return lhs.subtract(rhs);
}
|int| main() {
|Vec2| vector1;
|Vec2| vector2;
vector1.x = 3;
vector1.y = 9;
vector2 = vector1;
/* NOTE COMMENT
|Vec2| vector3;
vector3.x = vector1.x + vector2.x;
vector3.y = vector1.y + vector2.y;
vector2.print();
*/
|Vec2| addition = vector1 + vector2;
print("\n");
addition.print();
print("\nSubtraction\n");
vector2.x = 100;
vector2.y = 70;
|Vec2| subtraction = vector1 - vector2;
print("\n");
print(subtraction.x); print(" "); print(subtraction.y);
print("\n");
return 0;
}

View File

@@ -0,0 +1 @@
5

14
tests/RecursiveTest.krak Normal file
View File

@@ -0,0 +1,14 @@
import io;
|int| fibanacci(|int| num) {
if (num < 2)
return 1;
return fibanacci(num-1) + fibanacci(num-2);
}
|int| main() {
print(fibanacci(4));
print("\n");
return 0;
}

View File

@@ -0,0 +1 @@
1337

View File

@@ -0,0 +1,7 @@
/* Comment first! */
import io;
|int| main() {
println(1337);
return 0;
}

View File

@@ -0,0 +1,3 @@
4
8
11

View File

@@ -0,0 +1,26 @@
import io;
import mem;
typedef ClassWithConstructor {
|int| data;
|ClassWithConstructor*| construct(|int| inData) {
data = inData;
return this;
}
|void| printData() {
println(data);
}
};
|int| main() {
|ClassWithConstructor| object.construct(4);
//ClassWithConstructor object;
//object.construct(4);
object.printData();
|int| a = 8;
println(a);
|ClassWithConstructor*| objPtr = new<ClassWithConstructor>()->construct(11);
objPtr->printData();
delete<ClassWithConstructor>(objPtr);
return 0;
}

View File

@@ -0,0 +1 @@
Hello Destructors!

28
tests/destructorTest.krak Normal file
View File

@@ -0,0 +1,28 @@
import io;
typedef DestructorPrint {
|char*| myStr;
|DestructorPrint*| construct(|char*| str) {
myStr = str;
return this;
}
|void| destruct() {
println(myStr);
}
};
typedef NoDistruction {
|int| a;
|void| dummyFunc() {}
};
|void| indirPrint() {
|DestructorPrint| testObj.construct("Hello Destructors!");
|NoDistruction| dummy;
}
|int| main() {
indirPrint();
return 0;
}

View File

@@ -0,0 +1 @@
It was nothing

View File

@@ -0,0 +1,9 @@
import io;
|void| nothing() {}
|int| main() {
nothing();
println("It was nothing");
return 0;
}

View File

@@ -0,0 +1 @@
22.141590

View File

@@ -0,0 +1,13 @@
import io;
template <T,J> |void| addAndPrint(|T| a, |J| b) {
print(a+b);
}
|int| main() {
addAndPrint<int,double>(10,12.14159);
print("\n");
return 0;
}

View File

@@ -0,0 +1 @@
12

View File

@@ -0,0 +1,17 @@
import io;
|int| ret1() {
return ret2() / 2;
}
|int| main() {
print(ret1());
print(ret2());
print("\n");
return 0;
}
|int| ret2() {
return 2;
}

View File

@@ -0,0 +1 @@
22

View File

@@ -0,0 +1,13 @@
import io;
template <T> |T| addAndPrint(|T| a, |T| b) {
print(a+b);
return a+b;
}
|int| main() {
addAndPrint<int>(10,12);
print("\n");
return 0;
}

View File

@@ -0,0 +1,3 @@
11
Hello decent memory! Quite a nice feeling

27
tests/memTest.krak Normal file
View File

@@ -0,0 +1,27 @@
import mem;
import io;
typedef AnObject {
|int| a;
|int| b;
|char*| c;
|void| print() {
print(a+b);
print("\n");
print(c);
print("\n");
}
};
|int| main() {
|AnObject*| ptr = new<AnObject>();
ptr->a = 4;
ptr->b = 7;
ptr->c = "Hello decent memory! Quite a nice feeling\n";
ptr->print();
delete<AnObject>(ptr);
return 0;
}

View File

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

View File

@@ -0,0 +1,29 @@
import io;
typedef firstObject {
|int| objectNum;
|int| other;
|void| print() {
print(other);
}
|void| printInd() {
print();
}
};
typedef Int int;
|Int| aliasNum;
|int| main() {
|firstObject| wooObject;
wooObject.objectNum = 7;
print(wooObject.objectNum);
|firstObject*| objPtr = &wooObject;
objPtr->objectNum = 42;
print(objPtr->objectNum);
print("\n");
objPtr->other = 1337;
objPtr->printInd();
print("\n");
}

View File

@@ -0,0 +1 @@
45Hello!Hello!Hello!

View File

@@ -0,0 +1,37 @@
import io;
import trivial_container;
typedef RegularObject {
|int| num;
|trivialContainer<char*>| innerContainer;
|void| set(|char*| message, |int| number) {
innerContainer.data = message;
num = number;
}
|char*| get() {
return innerContainer.data;
}
|void| print() {
print(num);
innerContainer.print();
}
};
typedef MyIntContainer trivialContainer<int>;
|MyIntContainer| roundabout;
|RegularObject| outsideDec;
|void| print(|trivialContainer<char*>| toPrint) {
print(toPrint.data);
}
|int| main() {
roundabout.data = 4;
outsideDec.set("Hello!", 5);
roundabout.print();
outsideDec.print();
print(outsideDec.get());
print(outsideDec.innerContainer);
print("\n");
return 0;
}

View File

@@ -0,0 +1 @@
12

View File

@@ -0,0 +1,27 @@
import io;
typedef objectA {
|int| a;
};
typedef BigObject {
|objectA| a;
|objectB| b;
|int| add() {
return a.a + b.b;
}
};
typedef objectB {
|int| b;
};
|int| main() {
|BigObject| c;
c.a.a = 4;
c.b.b = 8;
print(c.add());
print("\n");
return 0;
}

14
tests/runTests.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
krakenPath="../build/kraken"
testDir=${1:-"../tests"}
ext=${2:-"krak"}
fileList=""
for dir in `find ${testDir} -type f -name "*.${ext}"`; do
filename=$(basename ${dir})
filename="${filename%.*}"
fileList+=\ $testDir\/$filename
done
${krakenPath} "--test" ${fileList}

View File

@@ -0,0 +1 @@
1919

View File

@@ -0,0 +1,14 @@
import io;
|int| addAndPrintInt(|int| a, |int| b) {
print(a+b);
return a+b;
}
|int| main() {
print(addAndPrintInt(7,12));
print("\n");
return 0;
}

View File

@@ -0,0 +1,4 @@
a: 24
b: Hello World
a: Pi incoming
b: 3.14159 - Fooled you! txt pi. C is being weird with floats. Not a Kraken problem. Ahh Well.

View File

@@ -0,0 +1,30 @@
import io;
typedef template <T,J> TemplateTest {
|T| a;
|J| b;
|void| print() {
print("a: ");
print(a);
print("\n");
print("b: ");
print(b);
print("\n");
}
};
|int| main() {
|TemplateTest<int, char*>| test;
|TemplateTest<char*, char*>| test2;
test.a = 24;
test.b = "Hello World";
test2.a = "Pi incoming";
test2.b = "3.14159 - Fooled you! txt pi. C is being weird with floats. Not a Kraken problem. Ahh Well.";
test.print();
test2.print();
return 0;
}

View File

@@ -0,0 +1,4 @@
a: 5
b: 7
a: 9
b: Hello Templates!

View File

@@ -0,0 +1,30 @@
import io;
typedef template <T> TemplateTest {
|int| a;
|T| b;
|void| print() {
print("a: ");
print(a);
print("\n");
print("b: ");
print(b);
print("\n");
}
};
|int| main() {
|TemplateTest<int>| test;
|TemplateTest<char*>| test2;
test.a = 5;
test.b = 7;
test2.a = 9;
test2.b = "Hello Templates!";
test.print();
test2.print();
return 0;
}

View File

@@ -0,0 +1 @@
57

View File

@@ -0,0 +1,18 @@
import io;
typedef FirstObject {
|int| objectNum;
|void| PrintSelf(|int| a) {
print(objectNum);
print(a);
}
};
|int| main() {
|FirstObject| wooObject;
wooObject.objectNum = 5;
wooObject.PrintSelf(7);
print("\n");
return 0;
}

View File

@@ -0,0 +1,8 @@
a: 5
b: 7
1337
a: 9
b: Hello Templates!
Woooo nesting!
From another file! Whoh!
1919

52
tests/templateTest.krak Normal file
View File

@@ -0,0 +1,52 @@
import io;
import trivial_container;
typedef template <T> TemplateTest {
|int| a;
|T| b;
|trivialContainer<T>| c;
|void| print() {
print("a: ");
print(a);
print("\n");
print("b: ");
print(b);
print("\n");
c.print();
print("\n");
}
};
typedef MyInt int;
|MyInt| c;
template <T> |T| addAndPrint(|T| a, |T| b) {
print(a+b);
return a+b;
}
|int| main() {
|TemplateTest<int>| test;
|TemplateTest<char*>| test2;
test.a = 5;
test.b = 7;
test.c.data = 1337;
test2.a = 9;
test2.b = "Hello Templates!";
test2.c.data = "Woooo nesting!";
test.print();
test2.print();
|trivialContainer<char*>| testImport;
testImport.data = "From another file! Whoh!";
testImport.print();
print("\n");
print(addAndPrint<int>(7,12));
print("\n");
return 0;
}

View File

@@ -0,0 +1 @@
777

View File

@@ -0,0 +1,13 @@
import io;
import mem;
|int| main() {
|int| b;
|int*| a = &b;
a [ 0 ] = 7;
print(a [ 0 ] );
print(*a);
print(b);
print("\n");
return 0;
}

View File

@@ -0,0 +1,9 @@
No Traits
First Trait
Second Trait
Both Traits
First Trait
Second Trait
Both Traits
No Traits

75
tests/traitsTest.krak Normal file
View File

@@ -0,0 +1,75 @@
import io;
typedef NoTraits {};
typedef Trait1 (FirstTrait) {};
typedef Trait2 (SecondTrait) {};
typedef TwoTrait (FirstTrait, SecondTrait) {};
typedef AlreadySpecilized (FirstTrait, SecondTrait) {};
template <T> |void| OneTwoFunc(|T| obj) {
println("No Traits");
}
template <T(FirstTrait)> |void| OneTwoFunc(|T| obj) {
println("First Trait");
}
template <T(SecondTrait)> |void| OneTwoFunc(|T| obj) {
println("Second Trait");
}
template <T(FirstTrait, SecondTrait)> |void| OneTwoFunc(|T| obj) {
println("Both Traits");
}
/*
template <AlreadySpecilized> |void| OneTwoFunc(|AlreadySpecilized| obj) {
println("Already Specilized");
}
*/
//This should work for objects too!
//To test, we cycle the mapping of traits
typedef template<T> OneTwoObj (FirstTrait) {};
typedef template<T(FirstTrait)> OneTwoObj (SecondTrait) {};
typedef template<T(SecondTrait)> OneTwoObj (FirstTrait, SecondTrait) {};
typedef template<T(FirstTrait, SecondTrait)> OneTwoObj {};
/*
*typedef template<AlreadySpecilized> OneTwoObj {
* void proveSpecilized() {
* println("I'm specilized!");
* }
*};
*/
|int| main() {
|NoTraits| a;
|Trait1| b;
|Trait2| c;
|TwoTrait| d;
|AlreadySpecilized| e;
OneTwoFunc<NoTraits>(a);
OneTwoFunc<Trait1>(b);
OneTwoFunc<Trait2>(c);
OneTwoFunc<TwoTrait>(d);
// OneTwoFunc<AlreadySpecilized>(e);
println();
|OneTwoObj<NoTraits>| alpha;
|OneTwoObj<Trait1>| beta;
|OneTwoObj<Trait2>| gamma;
|OneTwoObj<TwoTrait>| delta;
// |OneTwoObj<AlreadySpecilized>| epsilon;
OneTwoFunc<OneTwoObj<NoTraits>>(alpha);
OneTwoFunc<OneTwoObj<Trait1>>(beta);
OneTwoFunc<OneTwoObj<Trait2>>(gamma);
OneTwoFunc<OneTwoObj<TwoTrait>>(delta);
//We can't pass along our inner part, so let's just make sure that it is the right object.
//epsilon.proveSpecilized();
return 0;
}

View File

@@ -0,0 +1,2 @@
4
8

20
tests/typeExpr.krak Normal file
View File

@@ -0,0 +1,20 @@
import io;
typedef ClassWithConstructor {
|int| data;
|ClassWithConstructor*| construct(|int| inData) {
data = inData;
return this;
}
|void| printData() {
println(data);
}
};
|int| main() {
|ClassWithConstructor| object.construct(4);
object.printData();
|int| a = 8;
println(a);
return 0;
}

View File

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

28
tests/vectorTest.krak Normal file
View File

@@ -0,0 +1,28 @@
import io;
import mem;
import vector;
typedef AbleToBeDestroyed (Destructable) {
|void| destruct() {
println("Destroyed!");
}
};
|int| main() {
|vector<int>| intVec.construct();
intVec.addEnd(1);
intVec.addEnd(3);
intVec.addEnd(3);
intVec.addEnd(7);
for (|int| i = 0; i < intVec.size; i++;)
print(intVec.at(i));
println();
|vector<AbleToBeDestroyed>*| desVec = new<vector<AbleToBeDestroyed>>()->construct();
|AbleToBeDestroyed| testDestruct;
desVec->addEnd(testDestruct);
delete<vector<AbleToBeDestroyed>>(desVec);
return 0;
}

View File

@@ -1,9 +0,0 @@
This is the true regex for triple quoted strings, but it segfaults my regex code....
triple_quoted_string = "\"\"\"((\"\"(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'|
|z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|Z|X|C|V|B|N|M|<|>|\?| )+)|(\"(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'|
|z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|Z|X|C|V|B|N|M|<|>|\?| )+))*(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'|
|z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|Z|X|C|V|B|N|M|<|>|\?| )*(((`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'|
|z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|Z|X|C|V|B|N|M|<|>|\?| )+\")|((`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'|
|z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|Z|X|C|V|B|N|M|<|>|\?| )+\"\")|((`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'|
|z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|Z|X|C|V|B|N|M|<|>|\?| )+))*\"\"\"" ;