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

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,59 +36,163 @@ 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;
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)
parameters += ", ";
parameters += ValueTypeToCType(decChildren[j]->getData().valueType) + " " + generate(decChildren[j], enclosingObject);
nameDecoration += "_" + ValueTypeToCTypeDecoration(decChildren[j]->getData().valueType);
}
functionPrototypes += CifyName(declarationData.symbol.getName() + nameDecoration) + "(" + parameters + "); /*func*/\n";
// Only generate function if this is the unit it was defined in
std::cout << "Generating " << CifyName(declarationData.symbol.getName()) << std::endl;
if (contains(children, declaration))
functionDefinitions += generate(declaration, enclosingObject);
}
output += "\n" + ValueTypeToCType(declarationData.valueType) + " ";
std::string nameDecoration, parameters;
for (int j = 0; j < decChildren.size()-1; j++) {
if (j > 0)
parameters += ", ";
parameters += ValueTypeToCType(decChildren[j]->getData().valueType) + " " + generate(decChildren[j], enclosingObject);
nameDecoration += "_" + ValueTypeToCTypeDecoration(decChildren[j]->getData().valueType);
}
output += CifyFunctionName(declarationData.symbol.getName()) + nameDecoration + "(" + parameters + "); /*func*/\n";
break;
}
case type_def:
//type
output += "/*typedef " + declarationData.symbol.getName() + " */\n";
break;
case type_def:
//type
plainTypedefs += "/*typedef " + declarationData.symbol.getName() + " */\n";
if (declarationData.valueType->baseType == template_type) {
plainTypedefs += "/* non instantiated template " + declarationData.symbol.getName() + " */";
} else if (declarationData.valueType->typeDefinition != declaration) {
if (declarationData.valueType->typeDefinition)
continue; // Aliases of objects are done with the thing it alises
// Otherwise, we're actually a renaming of a primitive, can generate here
plainTypedefs += "typedef " + ValueTypeToCType(declarationData.valueType) + " " + CifyName(declarationData.symbol.getName()) + ";\n";
plainTypedefs += generateAliasChains(from, declaration);
} else {
plainTypedefs += "typedef struct __struct_dummy_" + CifyName(declarationData.symbol.getName()) + "__ " + CifyName(declarationData.symbol.getName()) + ";\n";
functionPrototypes += "/* Method Prototypes for " + declarationData.symbol.getName() + " */\n";
// We use a seperate string for this because we only include it if this is the file we're defined in
std::string objectFunctionDefinitions = "/* Method Definitions for " + declarationData.symbol.getName() + " */\n";
for (int j = 0; j < decChildren.size(); j++) {
std::cout << decChildren[j]->getName() << std::endl;
if (decChildren[j]->getName() == "function") //If object method
objectFunctionDefinitions += generateObjectMethod(declaration, decChildren[j], &functionPrototypes) + "\n";
}
// Add all aliases to the plain typedefs. This will add any alias that aliases to this object, and any alias that aliases to that, and so on
plainTypedefs += generateAliasChains(from, declaration);
functionPrototypes += "/* Done with " + declarationData.symbol.getName() + " */\n";
// If this is the file the object is defined in, include methods
if (contains(children, declaration))
functionDefinitions += objectFunctionDefinitions + "/* Done with " + declarationData.symbol.getName() + " */\n";
}
break;
default:
//std::cout << "Declaration? named " << declaration->getName() << " of unknown type " << ASTData::ASTTypeToString(declarationData.type) << " in translation unit scope" << std::endl;
output += "/*unknown declaration named " + declaration->getName() + "*/\n";
}
}
}
//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
preName += "this->";
return preName + CifyName(data.symbol.getName()); //Cifying does nothing if not an operator overload
}
case type_def:
if (children.size() == 0) {
return "typedef " + ValueTypeToCType(data.valueType) + " " + data.symbol.getName() + ";";
} else {
std::string objectString = "typedef struct __struct_dummy_" + data.symbol.getName() + "__ {\n";
std::string postString; //The functions have to be outside the struct definition
for (int i = 0; i < children.size(); i++) {
std::cout << children[i]->getName() << std::endl;
if (children[i]->getName() == "function") //If object method
postString += generateObjectMethod(from, children[i]) + "\n";
else
objectString += generate(children[i], enclosingObject) + "\n";
}
objectString += "} " + data.symbol.getName() + ";";
return objectString + postString; //Functions come after the declaration of the struct
}
case function:
{
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,22 +226,39 @@ 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";
tabLevel++;
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;
}
tabLevel--;
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:
}
case expression:
output += " " + data.symbol.getName() + ", ";
case boolean_expression:
output += " " + data.symbol.getName() + " ";
@@ -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,18 +330,24 @@ 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()) {
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) + ",";
//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 + ")";
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 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 + ")";
}
} else {
//return "((" + generate(children[1], enclosingObject) + ")" + name + generate(children[2], enclosingObject) + ")";
@@ -239,10 +363,10 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
//Check to see if we're inside of an object and this is a method call
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,8 +163,10 @@ 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();
//Remove Transformations
@@ -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,12 +68,12 @@ std::string ParseAction::actionToString(ActionType action) {
}
}
std::string ParseAction::toString() {
std::string ParseAction::toString(bool printRuleLookahead) {
std::string outputString = "";
outputString += actionToString(action);
if (reduceRule != NULL)
outputString += " " + reduceRule->toString();
outputString += " " + reduceRule->toString(printRuleLookahead);
if (shiftState != -1)
outputString += " " + intToString(shiftState);
outputString += " " + intToString(shiftState);
return(outputString);
}
}

View File

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

View File

@@ -32,10 +32,22 @@ 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 != "") {
//Load the left of the rule
//First, if this starts with a '#', skip this
if (currToken.front() == '#') {
//If this line is more than one token long, eat it
std::cout << "Ate: " << currToken << std::endl;
if (currToken.back() != '\n')
std::cout << "Eating " << reader.line() << " b/c grammer comment" << std::endl;
currToken = reader.word(false);
continue;
}
if (currToken.back() == '\n' || currToken.back() == ' ' || currToken.back() == '\t')
currToken.erase(currToken.size()-1);
//Load the left of the rule
ParseRule* currentRule = new ParseRule();
Symbol leftSide = getOrAddSymbol(currToken, false); //Left handle is never a terminal
currentRule->setLeftHandle(leftSide);
@@ -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) {
//If we've already done this token, don't do it again
std::vector<Symbol> Parser::firstSet(Symbol token, std::vector<Symbol> avoidList, bool addNewTokens) {
if (tokenFirstSet.find(token) != tokenFirstSet.end())
return tokenFirstSet[token];
//If we've already done this token, don't do it again
for (std::vector<Symbol>::size_type i = 0; i < avoidList.size(); i++)
if (avoidList[i] == token) {
return new std::vector<Symbol>();
}
if (avoidList[i] == token)
return std::vector<Symbol>();
avoidList.push_back(token);
std::vector<Symbol>* first = new std::vector<Symbol>();
std::vector<Symbol> first;
//First, if the symbol is a terminal, than it's first set is just itself.
if (token.isTerminal()) {
first->push_back(token);
first.push_back(token);
return(first);
}
//Otherwise....
//Ok, to make a first set, go through the grammer, if the token it's left side, add it's production's first token's first set.
//If that one includes mull, do the next one too (if it exists).
Symbol rightToken;
std::vector<Symbol>* recursiveFirstSet = NULL;
std::vector<Symbol> recursiveFirstSet;
for (std::vector<ParseRule*>::size_type i = 0; i < loadedGrammer.size(); i++) {
if (token == loadedGrammer[i]->getLeftSide()) {
//Loop through the rule adding first sets for each token if the previous token contained NULL
bool recFirstSetHasNull = false;
int j = 0;
do {
rightToken = loadedGrammer[i]->getRightSide()[j]; //Get token of the right side of this rule
if (rightToken.isTerminal()) {
recursiveFirstSet = new std::vector<Symbol>();
recursiveFirstSet->push_back(rightToken);
recursiveFirstSet.push_back(rightToken);
} else {
//Add the entire set
recursiveFirstSet = firstSet(rightToken, avoidList);
recursiveFirstSet = firstSet(rightToken, avoidList, false);//Don't add children to cache, as early termination may cause them to be incomplete
}
first->insert(first->end(), recursiveFirstSet->begin(), recursiveFirstSet->end());
//Check to see if the current recursiveFirstSet contains NULL, if so, then go through again with the next token. (if there is one)
recFirstSetHasNull = false;
for (std::vector<Symbol>::size_type k = 0; k < recursiveFirstSet->size(); k++) {
if ((*recursiveFirstSet)[k] == nullSymbol) {
recFirstSetHasNull = true;
}
}
delete recursiveFirstSet;
first.insert(first.end(), recursiveFirstSet.begin(), recursiveFirstSet.end());
j++;
} while (recFirstSetHasNull && loadedGrammer[i]->getRightSide().size() > j);
} while (isNullable(rightToken) && loadedGrammer[i]->getRightSide().size() > j);
}
}
if (addNewTokens)
tokenFirstSet[token] = first;
return(first);
}
bool Parser::isNullable(Symbol token) {
if (tokenNullable.find(token) != tokenNullable.end())
return tokenNullable[token];
bool nullable = isNullableHelper(token, std::set<Symbol>());
tokenNullable[token] = nullable;
return nullable;
}
//We use this helper function to recurse because it is possible to wind up with loops, and if so we want
//early termination. However, this means that nullable determinations in the middle of the loop are inaccurate
//(since we terminated early), so we don't want to save them. Thus, for simplicity, only the main method will
//add to the cache. This is somewhat unfortunate for preformance, but the necessary additions to keep track of
//invalidated state are more complicated than it's worth.
bool Parser::isNullableHelper(Symbol token, std::set<Symbol> done) {
if (token.isTerminal())
return token == nullSymbol;
if (done.find(token) != done.end())
return false;
done.insert(token);
if (tokenNullable.find(token) != tokenNullable.end())
return tokenNullable[token];
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++) {
@@ -261,7 +299,7 @@ void Parser::addStates(std::vector< State* >* stateSets, State* state, std::queu
//Clone the current rule
ParseRule* advancedRule = (*currStateTotal)[i]->clone();
//Try to advance the pointer, if sucessful see if it is the correct next symbol
if (advancedRule->advancePointer()) {
if (advancedRule->advancePointer()) {
//Technically, it should be the set of rules sharing this symbol advanced past in the basis for new state
//So search our new states to see if any of them use this advanced symbol as a base.

View File

@@ -8,6 +8,20 @@ RNGLRParser::~RNGLRParser() {
//
}
void RNGLRParser::printReconstructedFrontier(int frontier) {
std::vector<int> lastFrontier = gss.getFrontier(frontier);
for (int j = 0; j < lastFrontier.size(); j++) {
std::cout << "State: " << lastFrontier[j] << std::endl;
std::vector<std::pair<std::string, ParseAction>> stateParseActions = table.stateAsParseActionVector(lastFrontier[j]);
std::set<std::pair<std::string, ParseAction>> noRepeats;
for (auto k : stateParseActions)
noRepeats.insert(k);
for (auto k : noRepeats)
std::cout << k.first << " " << k.second.toString(false) << std::endl;
std::cout << std::endl;
}
}
NodeTree<Symbol>* RNGLRParser::parseInput(std::string inputString) {
input.clear();
gss.clear();
@@ -53,7 +67,7 @@ NodeTree<Symbol>* RNGLRParser::parseInput(std::string inputString) {
// std::cout << "\nDone with Lexing, length:" << input.size() << std::endl;
// std::cout << input[0].toString() << std::endl;
// for (int i = 0; i < input.size(); i++)
// std::cout << "|" << input[i]->toString() << "|";
// std::cout << std::endl;
@@ -74,7 +88,6 @@ NodeTree<Symbol>* RNGLRParser::parseInput(std::string inputString) {
else if (firstActions[i]->action == ParseAction::REDUCE && fullyReducesToNull(firstActions[i]->reduceRule)) {
Reduction newReduction = {v0, firstActions[i]->reduceRule->getLeftSide(), 0, getNullableParts(firstActions[i]->reduceRule), NULL};
toReduce.push(newReduction);
//toReduce.push(std::make_pair(std::make_pair(v0, firstActions[i]->reduceRule->getLeftSide()), 0));
}
}
@@ -89,14 +102,21 @@ NodeTree<Symbol>* RNGLRParser::parseInput(std::string inputString) {
std::cout << "Parsing failed on " << input[i].toString() << std::endl;
std::cout << "Problem is on line: " << findLine(i) << std::endl;
std::cout << "Nearby is:" << std::endl;
const int range = 10;
int range = 10;
for (int j = (i-range >= 0 ? i-range : 0); j < (i+range < input.size() ? i+range : input.size()); j++)
if (j == i)
std::cout << "||*||*||" << input[j].toString() << "||*||*|| ";
else
std::cout << input[j].toString() << " ";
std::cout << std::endl;
break;
range = 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
@@ -186,7 +206,7 @@ void RNGLRParser::reducer(int i) {
toStateNode = gss.newNode(toState);
gss.addToFrontier(i, toStateNode);
gss.addEdge(toStateNode, currentReached, newLabel);
//std::cout << "Adding shifts and reductions for a state that did not exist" << std::endl;
std::vector<ParseAction*> actions = *(table.get(toState, input[i]));
for (std::vector<ParseAction*>::size_type k = 0; k < actions.size(); k++) {
@@ -319,7 +339,7 @@ void RNGLRParser::addStates(std::vector< State* >* stateSets, State* state, std:
//Clone the current rule
ParseRule* advancedRule = (*currStateTotal)[i]->clone();
//Try to advance the pointer, if sucessful see if it is the correct next symbol
if (advancedRule->advancePointer()) {
if (advancedRule->advancePointer()) {
//Technically, it should be the set of rules sharing this symbol advanced past in the basis for new state
//So search our new states to see if any of them use this advanced symbol as a base.
@@ -353,10 +373,10 @@ void RNGLRParser::addStates(std::vector< State* >* stateSets, State* state, std:
stateAlreadyInAllStates = true;
//If it does exist, we should add it as the shift/goto in the action table
//std::cout << "newStates[" << i << "] == stateSets[" << j << "]" << std::endl;
if (!((*stateSets)[j]->basisEquals(*(newStates[i]))))
toDo->push((*stateSets)[j]);
(*stateSets)[j]->combineStates(*(newStates[i]));
//std::cout << j << "\t Hay, doing an inside loop state reductions!" << std::endl;
addStateReductionsToTable((*stateSets)[j]);

View File

@@ -251,7 +251,7 @@ void Table::add(int stateNum, Symbol tranSymbol, ParseAction* action) {
//If this table slot is empty
//std::cout << "table[stateNum] is " << table[stateNum] << std::endl;
//std::cout << "blank is " << (*(table[stateNum]))[symbolIndex] << std::endl;
if ( (*(table[stateNum]))[symbolIndex] == NULL ) {
//std::cout << "Null, adding " << action->toString() << std::endl;
std::vector<ParseAction*>* actionList = new std::vector<ParseAction*>();
@@ -262,7 +262,7 @@ void Table::add(int stateNum, Symbol tranSymbol, ParseAction* action) {
//else if ( !(*(table[stateNum]))[symbolIndex]->equalsExceptLookahead(*action)) {
else {
//std::cout << "not Null!" << std::endl;
//std::cout << "State: " << stateNum << " Conflict between old: " << (*(table[stateNum]))[symbolIndex]->toString() << " and new: " << action->toString() << " on " << tranSymbol->toString() << std::endl;
//std::cout << "State: " << stateNum << " Conflict between old: " << (*(table[stateNum]))[symbolIndex]->toString() << " and new: " << action->toString() << " on " << tranSymbol->toString() << std::endl;
//Check to see if this action is already in the list
@@ -353,6 +353,17 @@ ParseAction* Table::getShift(int state, Symbol token) {
return shift;
}
std::vector<std::pair<std::string, ParseAction>> Table::stateAsParseActionVector(int state) {
std::vector<std::pair<std::string, ParseAction>> reconstructedState;
std::vector<std::vector<ParseAction*>*>* stateVec = table[state];
for (int i = 0; i < stateVec->size(); i++)
if (std::vector<ParseAction*>* forStateAndSymbol = (*stateVec)[i])
for (int j = 0; j < forStateAndSymbol->size(); j++)
reconstructedState.push_back(std::make_pair(symbolIndexVec[i].toString(),*((*forStateAndSymbol)[j])));
return reconstructedState;
}
std::string Table::toString() {
std::string concat = "";
for (std::vector<Symbol>::size_type i = 0; i < symbolIndexVec.size(); i++)

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