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)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
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} )
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 <map>
#include <iterator>
#include <algorithm>
#include "Type.h"
#include "ASTData.h"
#include "NodeTransformation.h"
@@ -15,17 +18,46 @@ class ASTTransformation: public NodeTransformation<Symbol,ASTData> {
public:
ASTTransformation(Importer* importerIn);
~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);
NodeTree<ASTData>* transform(NodeTree<Symbol>* from, NodeTree<ASTData>* scope, std::vector<Type> types = std::vector<Type>());
std::vector<NodeTree<ASTData>*> transformChildren(std::vector<NodeTree<Symbol>*> children, std::set<int> skipChildren, NodeTree<ASTData>* scope, std::vector<Type> types);
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::map<std::string, Type*> templateTypeReplacements);
std::vector<Type> mapNodesToTypes(std::vector<NodeTree<ASTData>*> nodes);
std::string concatSymbolTree(NodeTree<Symbol>* root);
NodeTree<ASTData>* scopeLookup(NodeTree<ASTData>* scope, std::string lookup, std::vector<NodeTree<ASTData>*> nodes);
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>* doFunction(NodeTree<ASTData>* scope, std::string lookup, std::vector<NodeTree<ASTData>*> nodes, std::map<std::string, Type*> templateTypeReplacements);
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:
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

View File

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

View File

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

View File

@@ -14,13 +14,27 @@
#include "CollapseTransformation.h"
#include "ASTTransformation.h"
class ASTTransformation;
class Importer {
public:
Importer(Parser* parserIn);
Importer(Parser* parserIn, std::vector<std::string> includePaths);
~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();
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;
std::vector<Symbol> removeSymbols;
std::vector<Symbol> collapseSymbols;

View File

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

View File

@@ -16,10 +16,10 @@ class ParseRule {
ParseRule();
ParseRule(Symbol leftHandle, int pointerIndex, std::vector<Symbol> &rightSide, std::vector<Symbol>* lookahead);
~ParseRule();
const bool equalsExceptLookahead(const ParseRule &other);
bool const operator==(const ParseRule &other);
bool const operator!=(const ParseRule &other);
const bool equalsExceptLookahead(const ParseRule &other) const;
bool const operator==(const ParseRule &other) const;
bool const operator!=(const ParseRule &other) const;
bool const operator<(const ParseRule &other) const; //Used for ordering so we can put ParseRule's in sets, and also so that ParseActions will have an ordering
ParseRule* clone();
void setLeftHandle(Symbol leftHandle);
@@ -40,7 +40,7 @@ class ParseRule {
void addLookahead(std::vector<Symbol>* lookahead);
std::vector<Symbol>* getLookahead();
std::string toString();
std::string toString(bool printLookahead = true);
std::string toDOT();
private:

View File

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

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

View File

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

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 <iostream>
#include <set>
//Circular dependency
class ASTData;
#include "ASTData.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 {
public:
Type();
Type(ValueType typeIn, int indirectionIn);
Type(ValueType typeIn);
Type(NodeTree<ASTData>* typeDefinitionIn);
Type(NodeTree<ASTData>* typeDefinitionIn, int indirectionIn);
Type(ValueType typeIn, NodeTree<ASTData>* typeDefinitionIn, int indirectionIn);
Type(ValueType typeIn, int indirectionIn = 0);
Type(ValueType typeIn, std::set<std::string> traitsIn); //Mostly for template type type's
Type(NodeTree<ASTData>* typeDefinitionIn, int indirectionIn = 0);
Type(NodeTree<ASTData>* typeDefinitionIn, std::set<std::string> traitsIn);
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();
bool const operator==(const Type &other)const;
bool const operator!=(const Type &other)const;
std::string toString();
Type* clone();
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;
int indirection;
NodeTree<Symbol>* templateDefinition;
std::map<std::string, Type*> templateTypeReplacement;
std::set<std::string> traits;
private:
int indirection;
};
#endif

View File

@@ -9,6 +9,9 @@
#include <string>
#include <sstream>
#include <vector>
#include <set>
#include <fstream>
#include <cstring>
std::string intToString(int theInt);
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);
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 readFile(std::istream &file);
template <typename T>
bool contains(std::vector<T> vec, T item) {
for (auto i : vec)
@@ -25,15 +31,32 @@ bool contains(std::vector<T> vec, T item) {
}
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;
if (begin < 0)
begin += vec.size()+1;
if (end < 0)
end += vec.size()+1;
for (int i = begin; i < end; i++)
for (int i = begin; i < end; i += step)
toReturn.push_back(vec[i]);
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

View File

@@ -2,10 +2,19 @@ Goal = translation_unit ;
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 ";" ;
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 ";" ;
interpreter_directive = "#!" WS path | ;
path = path path_part | path_part ;
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 ;
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 ;
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 | ;
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 | ;
parameter_list = parameter_list WS "," WS parameter | parameter ;
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 "}" ;
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 ;
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 "}" ;
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 ;
@@ -54,7 +72,7 @@ for_loop = "for" WS "\(" WS statement WS boolean_expression WS ";" WS statement
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 = 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 ;
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 = "==" | "<=" | ">=" | "!=" | "<" | ">" ;
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 ;
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 ;
unarad = number | identifier | function_call | bool | string | character | "\(" WS boolean_expression WS "\)" | access_operation ;
number = integer | float | double ;
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 | floating_literal ;
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 ;
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 ;
hexadecimal = "0x(1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)+" ;
sign = "\+|-" WS | ;
integer = sign numeric | sign hexadecimal | "null" ;
float = sign numeric "." numeric "f" ;
double = sign numeric "." numeric | sign numeric "." numeric "d" ;
integer = sign numeric | sign hexadecimal ;
floating_literal = sign numeric "." numeric | sign numeric "." numeric alpha ;
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|;|'|
|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 "ASTData.h"
#include "CGenerator.h"
#include "Poset.h"
#include "util.h"
#include "Tester.h"
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();
RegEx::test();
Lexer::test();
//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;
}
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 grammerFileString = argv[2];
std::string outputName = argv[3];
std::ifstream grammerInFile, compiledGrammerInFile;
std::ofstream /*outFileC,*/ compiledGrammerOutFile;
std::ofstream compiledGrammerOutFile;
grammerInFile.open(grammerFileString);
if (!grammerInFile.is_open()) {
@@ -40,17 +72,9 @@ int main(int argc, char* argv[]) {
}
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";
//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
std::string grammerInputFileString;
std::string line;
@@ -63,8 +87,6 @@ int main(int argc, char* argv[]) {
//LALRParser parser;
RNGLRParser parser;
parser.loadGrammer(grammerInputFileString);
//std::cout << "Creating State Set from Main" << std::endl;
//std::cout << "\nState Set" << std::endl;
//Start binary stuff
bool compGramGood = false;
@@ -88,7 +110,6 @@ int main(int argc, char* argv[]) {
} else {
compGramGood = true;
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
}
} else {
@@ -118,40 +139,23 @@ int main(int argc, char* argv[]) {
}
//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;
Importer importer(&parser);
Importer importer(&parser, includePaths);
for (auto i : includePaths)
std::cout << i << std::endl;
/*NodeTree<ASTData>* AST =*/
importer.import(programName);
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
//Code generation
//For right now, just C
CGenerator().generateCompSet(ASTs, outputName);
/*
std::string c_code = CGenerator().generate(AST);
outFileC << c_code << std::endl;
outFileC.close();
*/
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;
outputCFile.open(i->first + ".c");
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 {
std::cout << "Cannot open file " << i->first << ".c" << std::endl;
}
@@ -35,34 +36,109 @@ std::string CGenerator::tabs() {
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
std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enclosingObject) {
ASTData data = from->getData();
std::vector<NodeTree<ASTData>*> children = from->getChildren();
std::string output = "";
std::string output;
switch (data.type) {
case translation_unit:
//Do here because we may need the typedefs before the declarations of variables
for (int i = 0; i < children.size(); i++)
if (children[i]->getDataRef()->type == type_def)
output += generate(children[i], enclosingObject) + "\n";
{
// Ok, so we've got to do this in passes to preserve mututally recursive definitions.
//
// 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)
for (auto i = data.scope.begin(); i != data.scope.end(); i++) {
for (auto overloadedMembers : i->second) {
NodeTree<ASTData>* declaration = overloadedMembers;
for (auto declaration : i->second) {
std::vector<NodeTree<ASTData>*> decChildren = declaration->getChildren();
ASTData declarationData = declaration->getData();
switch(declarationData.type) {
case identifier:
output += ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "; /*identifier*/\n";
variableDeclarations += ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "; /*identifier*/\n";
break;
case function:
{
if (decChildren.size() == 0) { //Not a real function, must be a built in passthrough {
output += "/* built in function: " + declarationData.toString() + " */\n";
break;
}
output += "\n" + ValueTypeToCType(declarationData.valueType) + " ";
if (declarationData.valueType->baseType == template_type)
functionPrototypes += "/* template function " + declarationData.symbol.toString() + " */\n";
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)
@@ -70,12 +146,43 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
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;
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);
}
}
break;
case type_def:
//type
output += "/*typedef " + declarationData.symbol.getName() + " */\n";
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:
//std::cout << "Declaration? named " << declaration->getName() << " of unknown type " << ASTData::ASTTypeToString(declarationData.type) << " in translation unit scope" << std::endl;
@@ -83,11 +190,9 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
}
}
}
//Do here because we need the newlines
for (int i = 0; i < children.size(); i++)
if (children[i]->getDataRef()->type != type_def)
output += generate(children[i], enclosingObject) + "\n";
output += plainTypedefs + variableDeclarations + classStructs + functionPrototypes + functionDefinitions;
return output;
}
break;
case interpreter_directive:
//Do nothing
@@ -97,33 +202,22 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
//return "#include <" + data.symbol.getName() + ">\n";
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;
if (enclosingObject && enclosingObject->getDataRef()->scope.find(data.symbol.getName()) != enclosingObject->getDataRef()->scope.end())
preName += "self->";
if (false)
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
preName += "this->";
return preName + CifyName(data.symbol.getName()); //Cifying does nothing if not an operator overload
}
case function:
{
if (data.valueType->baseType == template_type)
return "/* template function: " + data.symbol.getName() + " */";
output += "\n" + ValueTypeToCType(data.valueType) + " ";
std::string nameDecoration, parameters;
for (int j = 0; j < children.size()-1; j++) {
@@ -132,21 +226,38 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
parameters += ValueTypeToCType(children[j]->getData().valueType) + " " + generate(children[j], enclosingObject);
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;
}
case code_block:
{
output += "{\n";
std::string destructorString = "";
tabLevel++;
for (int i = 0; i < children.size(); i++) {
//std::cout << "Line " << i << std::endl;
std::string line = generate(children[i], enclosingObject);
//std::cout << line << std::endl;
output += line;
if (children[i]->getChildren().size() && children[i]->getChildren()[0]->getDataRef()->type == declaration_statement) {
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() + "}";
return output;
}
case expression:
output += " " + data.symbol.getName() + ", ";
case boolean_expression:
@@ -175,7 +286,12 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
case declaration_statement:
if (children.size() == 1)
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) + ";";
case if_comp:
if (generate(children[0], enclosingObject) == generatorString)
@@ -198,11 +314,13 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
if (funcType == function) {
if (name == "++" || name == "--")
return generate(children[1], enclosingObject) + name;
if (name == "*" && children.size() == 2) //Is dereference, not multiplication
return "*(" + generate(children[1], enclosingObject) + ")";
if ( (name == "*" || name == "&" || name == "!" ) && children.size() == 2) //Is dereference, not multiplication, address-of, or other unary operator
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 == "!="
|| name == "<" || name == ">" || name == "%" || name == "+=" || name == "-=" || name == "*=" || name == "/=" || name == "||"
|| name == "&&" || name == "!" )
|| name == "&&")
return "((" + generate(children[1], enclosingObject) + ")" + name + "(" + generate(children[2], enclosingObject) + "))";
else if (name == "." || name == "->") {
if (children.size() == 1)
@@ -212,15 +330,21 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
std::string functionName = children[2]->getDataRef()->symbol.getName();
NodeTree<ASTData>* possibleObjectType = children[1]->getDataRef()->valueType->typeDefinition;
//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) {
NodeTree<ASTData>* unaliasedTypeDef = getMethodsObjectType(possibleObjectType, functionName);
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::string nameDecoration;
std::vector<NodeTree<ASTData>*> functionDefChildren = children[2]->getChildren(); //The function def is the rhs of the access operation
std::cout << "Decorating (in access-should be object) " << name << " " << functionDefChildren.size() << std::endl;
for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++)
nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType);
/*HERE*/ return possibleObjectType->getDataRef()->symbol.getName() +"__" + CifyFunctionName(functionName) + nameDecoration + "(" + (name == "." ? "&" : "") + generate(children[1], enclosingObject) + ",";
/*HERE*/ return CifyName(unaliasedTypeDef->getDataRef()->symbol.getName()) +"__" + CifyName(functionName + nameDecoration) + "(" + (name == "." ? "&" : "") + generate(children[1], enclosingObject) + ",";
//The comma lets the upper function call know we already started the param list
//Note that we got here from a function call. We just pass up this special case and let them finish with the perentheses
} 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 + ")";
@@ -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
bool isSelfObjectMethod = enclosingObject && contains(enclosingObject->getChildren(), children[0]);
if (isSelfObjectMethod)
output += enclosingObject->getDataRef()->symbol.getName() +"__";
/*HERE*/ output += CifyFunctionName(name) + nameDecoration + "(";
output += CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__";
/*HERE*/ output += CifyName(name + nameDecoration) + "(";
if (isSelfObjectMethod)
output += children.size() > 1 ? "self," : "self";
output += children.size() > 1 ? "this," : "this";
}
} else {
//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;
}
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) {
std::string output;
// Returns the function prototype in the out param and the full definition normally
std::string CGenerator::generateObjectMethod(NodeTree<ASTData>* enclosingObject, NodeTree<ASTData>* from, std::string *functionPrototype) {
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
enclosingObjectType.indirection++;
enclosingObjectType.increaseIndirection();
std::vector<NodeTree<ASTData>*> children = from->getChildren();
std::string nameDecoration, parameters;
for (int i = 0; i < children.size()-1; i++) {
parameters += ", " + ValueTypeToCType(children[i]->getData().valueType) + " " + generate(children[i]);
nameDecoration += "_" + ValueTypeToCTypeDecoration(children[i]->getData().valueType);
}
output += "\n" + ValueTypeToCType(data.valueType) + " " + enclosingObject->getDataRef()->symbol.getName() +"__"
+ CifyFunctionName(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
return output;
std::string functionSignature = "\n" + ValueTypeToCType(data.valueType) + " " + CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__"
+ CifyName(data.symbol.getName()) + nameDecoration + "(" + ValueTypeToCType(&enclosingObjectType)
+ " this" + parameters + ")";
*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) {
@@ -295,7 +426,7 @@ std::string CGenerator::ValueTypeToCType(Type *type) {
switch (type->baseType) {
case none:
if (type->typeDefinition)
return_type = type->typeDefinition->getDataRef()->symbol.getName();
return_type = CifyName(type->typeDefinition->getDataRef()->symbol.getName());
else
return_type = "none";
break;
@@ -321,7 +452,7 @@ std::string CGenerator::ValueTypeToCType(Type *type) {
return_type = "unknown_ValueType";
break;
}
for (int i = 0; i < type->indirection; i++)
for (int i = 0; i < type->getIndirection(); i++)
return_type += "*";
return return_type;
}
@@ -331,7 +462,7 @@ std::string CGenerator::ValueTypeToCTypeDecoration(Type *type) {
switch (type->baseType) {
case none:
if (type->typeDefinition)
return_type = type->typeDefinition->getDataRef()->symbol.getName();
return_type = CifyName(type->typeDefinition->getDataRef()->symbol.getName());
else
return_type = "none";
break;
@@ -357,12 +488,12 @@ std::string CGenerator::ValueTypeToCTypeDecoration(Type *type) {
return_type = "unknown_ValueType";
break;
}
for (int i = 0; i < type->indirection; i++)
for (int i = 0; i < type->getIndirection(); i++)
return_type += "_P__";
return return_type;
}
std::string CGenerator::CifyFunctionName(std::string name) {
std::string CGenerator::CifyName(std::string name) {
std::string operatorsToReplace[] = { "+", "plus",
"-", "minus",
"*", "star",
@@ -392,7 +523,14 @@ std::string CGenerator::CifyFunctionName(std::string name) {
"|=", "pipeequals",
"*=", "starequals",
"<<=", "doublerightequals",
"<", "lessthan",
">", "greaterthan",
">>=", "doubleleftequals",
"(", "openparen",
")", "closeparen",
"[", "openbracket",
"]", "closebracket",
" ", "space",
"->", "arrow" };
int length = sizeof(operatorsToReplace)/sizeof(std::string);
//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;
}
std::vector<int> GraphStructuredStack::getFrontier(int frontier) {
std::vector<int> toReturn;
for (int i = 0; i < gss[frontier]->size(); i++)
toReturn.push_back((*(gss[frontier]))[i]->getData());
return toReturn;
}
std::string GraphStructuredStack::toString() {
std::string tostring = "";
for (std::vector<std::vector<NodeTree<int>*>*>::size_type i = 0; i < gss.size(); i++) {

View File

@@ -1,9 +1,12 @@
#include "Importer.h"
Importer::Importer(Parser* parserIn) {
Importer::Importer(Parser* parserIn, std::vector<std::string> includePaths) {
//constructor
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("\\(", 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("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("if", true));
removeSymbols.push_back(Symbol("while", true));
removeSymbols.push_back(Symbol("__if_comp__", true));
removeSymbols.push_back(Symbol("comp_simple_passthrough", 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_parameter_list", false));
@@ -31,23 +36,102 @@ Importer::Importer(Parser* parserIn) {
collapseSymbols.push_back(Symbol("unorderd_list_part", false));
collapseSymbols.push_back(Symbol("if_comp_pred", 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() {
//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
if (imported.find(fileName) != imported.end())
if (imported.find(fileName) != imported.end()) {
std::cout << "Already Imported!" << std::endl;
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::ofstream outFile, outFileTransformed, outFileAST;
std::ofstream outFile, outFileTransformed;
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()) {
std::cout << "Problem opening programInFile " << fileName << "\n";
return NULL;
@@ -65,12 +149,6 @@ NodeTree<ASTData>* Importer::import(std::string fileName) {
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;
while(programInFile.good()) {
getline(programInFile, line);
@@ -85,7 +163,9 @@ NodeTree<ASTData>* Importer::import(std::string fileName) {
//std::cout << parseTree->DOTGraphString() << std::endl;
outFile << parseTree->DOTGraphString() << std::endl;
} 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();
@@ -106,19 +186,7 @@ NodeTree<ASTData>* Importer::import(std::string fileName) {
}
outFileTransformed.close();
//Call with ourself to allow the transformation to call us to import files that it needs
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;
return parseTree;
}
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);
}
const bool ParseAction::operator==(const ParseAction &other) {
const bool ParseAction::operator==(const ParseAction &other) const {
return( action == other.action && ( reduceRule == other.reduceRule || *reduceRule == *(other.reduceRule) ) && shiftState == other.shiftState);
}
const bool ParseAction::operator!=(const ParseAction &other) {
const bool ParseAction::operator!=(const ParseAction &other) const {
return !(this->operator==(other));
}
//Exists so we can put ParseActions into sets
const bool ParseAction::operator<(const ParseAction &other) const {
if (action != other.action)
return action < other.action;
if (reduceRule != other.reduceRule) {
if (! (reduceRule && other.reduceRule)) {
return reduceRule < other.reduceRule;
} else {
return *reduceRule < *(other.reduceRule);
}
}
return shiftState < other.shiftState;
}
std::string ParseAction::actionToString(ActionType action) {
switch (action) {
case REDUCE:
@@ -53,11 +68,11 @@ std::string ParseAction::actionToString(ActionType action) {
}
}
std::string ParseAction::toString() {
std::string ParseAction::toString(bool printRuleLookahead) {
std::string outputString = "";
outputString += actionToString(action);
if (reduceRule != NULL)
outputString += " " + reduceRule->toString();
outputString += " " + reduceRule->toString(printRuleLookahead);
if (shiftState != -1)
outputString += " " + intToString(shiftState);
return(outputString);

View File

@@ -16,18 +16,34 @@ ParseRule::~ParseRule() {
}
const bool ParseRule::equalsExceptLookahead(const ParseRule &other) {
const bool ParseRule::equalsExceptLookahead(const ParseRule &other) const {
return(leftHandle == other.leftHandle && rightSide == other.rightSide && pointerIndex == other.pointerIndex);
}
const bool ParseRule::operator==(const ParseRule &other) {
const bool ParseRule::operator==(const ParseRule &other) const {
return(equalsExceptLookahead(other) && (lookahead == NULL ? other.lookahead == NULL : (*lookahead) == *(other.lookahead)));
}
const bool ParseRule::operator!=(const ParseRule &other) {
const bool ParseRule::operator!=(const ParseRule &other) const {
return !(this->operator==(other));
}
const bool ParseRule::operator<(const ParseRule &other) const {
//Used for ordering so we can put ParseRule's in sets, and also so that ParseActions will have an ordering
if (leftHandle != other.leftHandle)
return leftHandle < other.leftHandle;
if (rightSide != other.rightSide)
return rightSide < other.rightSide;
if (lookahead != other.lookahead) {
if (! (lookahead && other.lookahead)) {
return lookahead < other.lookahead;
} else {
return *lookahead < *(other.lookahead);
}
}
return false;
}
ParseRule* ParseRule::clone() {
std::vector<Symbol>* newLookahead = NULL;
if (lookahead) {
@@ -111,7 +127,7 @@ std::vector<Symbol>* ParseRule::getLookahead() {
return lookahead;
}
std::string ParseRule::toString() {
std::string ParseRule::toString(bool printLookahead) {
std::string concat = leftHandle.toString() + " -> ";
for (int i = 0; i < rightSide.size(); i++) {
if (i == pointerIndex)
@@ -120,7 +136,7 @@ std::string ParseRule::toString() {
}
if (pointerIndex >= rightSide.size())
concat += "(*)";
if (lookahead != NULL) {
if (printLookahead && lookahead != NULL) {
concat += "**";
for (std::vector<Symbol>::size_type i = 0; i < lookahead->size(); i++)
concat += (*lookahead)[i].toString();

View File

@@ -32,9 +32,21 @@ Symbol Parser::getOrAddSymbol(std::string symbolString, bool isTerminal) {
void Parser::loadGrammer(std::string 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 != "") {
//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();
Symbol leftSide = getOrAddSymbol(currToken, false); //Left handle is never a terminal
@@ -76,7 +88,7 @@ void Parser::loadGrammer(std::string grammerInputString) {
loadedGrammer.push_back(currentRule);
//Get next token
currToken = reader.word();
currToken = reader.word(false);
}
//std::cout << "Parsed!\n";
@@ -117,59 +129,86 @@ int Parser::stateNum(State* state) {
return -1;
}
std::vector<Symbol>* Parser::firstSet(Symbol token) {
std::vector<Symbol> avoidList;
return firstSet(token, avoidList);
}
std::vector<Symbol>* Parser::firstSet(Symbol token, std::vector<Symbol> avoidList) {
std::vector<Symbol> Parser::firstSet(Symbol token, std::vector<Symbol> avoidList, bool addNewTokens) {
if (tokenFirstSet.find(token) != tokenFirstSet.end())
return tokenFirstSet[token];
//If we've already done this token, don't do it again
for (std::vector<Symbol>::size_type i = 0; i < avoidList.size(); i++)
if (avoidList[i] == token) {
return new std::vector<Symbol>();
}
if (avoidList[i] == token)
return std::vector<Symbol>();
avoidList.push_back(token);
std::vector<Symbol>* first = new std::vector<Symbol>();
std::vector<Symbol> first;
//First, if the symbol is a terminal, than it's first set is just itself.
if (token.isTerminal()) {
first->push_back(token);
first.push_back(token);
return(first);
}
//Otherwise....
//Ok, to make a first set, go through the grammer, if the token it's left side, add it's production's first token's first set.
//If that one includes mull, do the next one too (if it exists).
Symbol rightToken;
std::vector<Symbol>* recursiveFirstSet = NULL;
std::vector<Symbol> recursiveFirstSet;
for (std::vector<ParseRule*>::size_type i = 0; i < loadedGrammer.size(); i++) {
if (token == loadedGrammer[i]->getLeftSide()) {
//Loop through the rule adding first sets for each token if the previous token contained NULL
bool recFirstSetHasNull = false;
int j = 0;
do {
rightToken = loadedGrammer[i]->getRightSide()[j]; //Get token of the right side of this rule
if (rightToken.isTerminal()) {
recursiveFirstSet = new std::vector<Symbol>();
recursiveFirstSet->push_back(rightToken);
recursiveFirstSet.push_back(rightToken);
} else {
//Add the entire set
recursiveFirstSet = firstSet(rightToken, avoidList);
recursiveFirstSet = firstSet(rightToken, avoidList, false);//Don't add children to cache, as early termination may cause them to be incomplete
}
first->insert(first->end(), recursiveFirstSet->begin(), recursiveFirstSet->end());
//Check to see if the current recursiveFirstSet contains NULL, if so, then go through again with the next token. (if there is one)
recFirstSetHasNull = false;
for (std::vector<Symbol>::size_type k = 0; k < recursiveFirstSet->size(); k++) {
if ((*recursiveFirstSet)[k] == nullSymbol) {
recFirstSetHasNull = true;
}
}
delete recursiveFirstSet;
first.insert(first.end(), recursiveFirstSet.begin(), recursiveFirstSet.end());
j++;
} while (recFirstSetHasNull && loadedGrammer[i]->getRightSide().size() > j);
} while (isNullable(rightToken) && loadedGrammer[i]->getRightSide().size() > j);
}
}
if (addNewTokens)
tokenFirstSet[token] = first;
return(first);
}
bool Parser::isNullable(Symbol token) {
if (tokenNullable.find(token) != tokenNullable.end())
return tokenNullable[token];
bool nullable = isNullableHelper(token, std::set<Symbol>());
tokenNullable[token] = nullable;
return nullable;
}
//We use this helper function to recurse because it is possible to wind up with loops, and if so we want
//early termination. However, this means that nullable determinations in the middle of the loop are inaccurate
//(since we terminated early), so we don't want to save them. Thus, for simplicity, only the main method will
//add to the cache. This is somewhat unfortunate for preformance, but the necessary additions to keep track of
//invalidated state are more complicated than it's worth.
bool Parser::isNullableHelper(Symbol token, std::set<Symbol> done) {
if (token.isTerminal())
return token == nullSymbol;
if (done.find(token) != done.end())
return false;
done.insert(token);
if (tokenNullable.find(token) != tokenNullable.end())
return tokenNullable[token];
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.
std::vector<Symbol>* Parser::incrementiveFollowSet(ParseRule* rule) {
//Advance the pointer past the current Symbol (the one we want the followset for) to the next symbol (which might be in our follow set, or might be the end)
@@ -178,25 +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
std::vector<Symbol>* followSet = new std::vector<Symbol>();
std::vector<Symbol>* symbolFirstSet;
std::vector<Symbol> symbolFirstSet;
bool symbolFirstSetHasNull = true;
while (symbolFirstSetHasNull && !rule->isAtEnd()) {
symbolFirstSetHasNull = false;
symbolFirstSet = firstSet(rule->getAtNextIndex());
for (std::vector<Symbol>::size_type i = 0; i < symbolFirstSet->size(); i++) {
if ((*symbolFirstSet)[i] == nullSymbol) {
for (std::vector<Symbol>::size_type i = 0; i < symbolFirstSet.size(); i++) {
if (symbolFirstSet[i] == nullSymbol) {
symbolFirstSetHasNull = true;
symbolFirstSet->erase(symbolFirstSet->begin()+i);
symbolFirstSet.erase(symbolFirstSet.begin()+i);
break;
}
}
followSet->insert(followSet->end(), symbolFirstSet->begin(), symbolFirstSet->end());
delete symbolFirstSet;
followSet->insert(followSet->end(), symbolFirstSet.begin(), symbolFirstSet.end());
rule->advancePointer();
}
if (rule->isAtEnd()) {
symbolFirstSet = rule->getLookahead();
followSet->insert(followSet->end(), symbolFirstSet->begin(), symbolFirstSet->end());
symbolFirstSet = *(rule->getLookahead());
followSet->insert(followSet->end(), symbolFirstSet.begin(), symbolFirstSet.end());
}
std::vector<Symbol>* followSetReturn = new std::vector<Symbol>();
for (std::vector<Symbol>::size_type i = 0; i < followSet->size(); i++) {

View File

@@ -8,6 +8,20 @@ RNGLRParser::~RNGLRParser() {
//
}
void RNGLRParser::printReconstructedFrontier(int frontier) {
std::vector<int> lastFrontier = gss.getFrontier(frontier);
for (int j = 0; j < lastFrontier.size(); j++) {
std::cout << "State: " << lastFrontier[j] << std::endl;
std::vector<std::pair<std::string, ParseAction>> stateParseActions = table.stateAsParseActionVector(lastFrontier[j]);
std::set<std::pair<std::string, ParseAction>> noRepeats;
for (auto k : stateParseActions)
noRepeats.insert(k);
for (auto k : noRepeats)
std::cout << k.first << " " << k.second.toString(false) << std::endl;
std::cout << std::endl;
}
}
NodeTree<Symbol>* RNGLRParser::parseInput(std::string inputString) {
input.clear();
gss.clear();
@@ -74,7 +88,6 @@ NodeTree<Symbol>* RNGLRParser::parseInput(std::string inputString) {
else if (firstActions[i]->action == ParseAction::REDUCE && fullyReducesToNull(firstActions[i]->reduceRule)) {
Reduction newReduction = {v0, firstActions[i]->reduceRule->getLeftSide(), 0, getNullableParts(firstActions[i]->reduceRule), NULL};
toReduce.push(newReduction);
//toReduce.push(std::make_pair(std::make_pair(v0, firstActions[i]->reduceRule->getLeftSide()), 0));
}
}
@@ -89,14 +102,21 @@ NodeTree<Symbol>* RNGLRParser::parseInput(std::string inputString) {
std::cout << "Parsing failed on " << input[i].toString() << std::endl;
std::cout << "Problem is on line: " << findLine(i) << std::endl;
std::cout << "Nearby is:" << std::endl;
const int range = 10;
int range = 10;
for (int j = (i-range >= 0 ? i-range : 0); j < (i+range < input.size() ? i+range : input.size()); j++)
if (j == i)
std::cout << "||*||*||" << input[j].toString() << "||*||*|| ";
else
std::cout << input[j].toString() << " ";
std::cout << std::endl;
break;
range = 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

View File

@@ -353,6 +353,17 @@ ParseAction* Table::getShift(int state, Symbol token) {
return shift;
}
std::vector<std::pair<std::string, ParseAction>> Table::stateAsParseActionVector(int state) {
std::vector<std::pair<std::string, ParseAction>> reconstructedState;
std::vector<std::vector<ParseAction*>*>* stateVec = table[state];
for (int i = 0; i < stateVec->size(); i++)
if (std::vector<ParseAction*>* forStateAndSymbol = (*stateVec)[i])
for (int j = 0; j < forStateAndSymbol->size(); j++)
reconstructedState.push_back(std::make_pair(symbolIndexVec[i].toString(),*((*forStateAndSymbol)[j])));
return reconstructedState;
}
std::string Table::toString() {
std::string concat = "";
for (std::vector<Symbol>::size_type i = 0; i < symbolIndexVec.size(); i++)

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;
baseType = none;
typeDefinition = NULL;
}
Type::Type(ValueType typeIn) {
indirection = 0;
baseType = typeIn;
typeDefinition = NULL;
templateDefinition = NULL;
}
Type::Type(ValueType typeIn, int indirectionIn) {
indirection = indirectionIn;
baseType = typeIn;
typeDefinition = NULL;
templateDefinition = NULL;
}
Type::Type(NodeTree<ASTData>* typeDefinitionIn) {
Type::Type(ValueType typeIn, std::set<std::string> traitsIn) {
indirection = 0;
baseType = none;
typeDefinition = typeDefinitionIn;
baseType = typeIn;
traits = traitsIn;
typeDefinition = NULL;
templateDefinition = NULL;
}
Type::Type(NodeTree<ASTData>* typeDefinitionIn, int indirectionIn) {
indirection = indirectionIn;
baseType = none;
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;
indirection = indirectionIn;
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() {
}
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 {
return(!this->operator==(other));
}
std::string Type::toString() {
std::string Type::toString(bool showTraits) {
std::string typeString;
switch (baseType) {
case none:
@@ -55,6 +74,12 @@ std::string Type::toString() {
else
typeString = "none";
break;
case template_type:
typeString = "template: " + templateDefinition->getDataRef()->toString();
break;
case template_type_type:
typeString = "template_type_type";
break;
case void_type:
typeString = "void";
break;
@@ -81,5 +106,35 @@ std::string Type::toString() {
}
for (int i = 0; i < indirection; i++)
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;
}
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;
}
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|<|>|\?| )+))*\"\"\"" ;