Merge branch 'master' of https://www.github.com/Limvot/kraken
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
124
src/Importer.cpp
124
src/Importer.cpp
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
116
src/Parser.cpp
116
src/Parser.cpp
@@ -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.
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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
69
src/Tester.cpp
Normal 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;
|
||||
}
|
||||
79
src/Type.cpp
79
src/Type.cpp
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user