From 1791738cd93c860ae8594405af5c101ac1e76c3c Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Mon, 3 Feb 2014 11:41:25 -0500 Subject: [PATCH] Working on objects and scoping. To finish, need to actually implement decent propogation of types --- include/CGenerator.h | 3 +- src/ASTTransformation.cpp | 101 +++++++++++++++++----------- src/CGenerator.cpp | 136 +++++++++++++++++++++++++++----------- 3 files changed, 161 insertions(+), 79 deletions(-) diff --git a/include/CGenerator.h b/include/CGenerator.h index 00d4c05..09142d6 100644 --- a/include/CGenerator.h +++ b/include/CGenerator.h @@ -17,8 +17,9 @@ class CGenerator { CGenerator(); ~CGenerator(); void generateCompSet(std::map*> ASTs, std::string outputName); - std::string generate(NodeTree* from); + std::string generate(NodeTree* from, NodeTree* enclosingObject = NULL); static std::string ValueTypeToCType(Type *type); + std::string generateObjectMethod(NodeTree* enclosingObject, NodeTree* from); std::string generatorString; private: diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 0543fb1..58d829e 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -17,7 +17,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from) { NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree* scope) { Symbol current = from->getData(); std::string name = current.getName(); - NodeTree* newNode; + NodeTree* newNode = NULL; std::vector*> children = from->getChildren(); std::set skipChildren; @@ -25,25 +25,26 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode = new NodeTree(name, ASTData(translation_unit)); scope = newNode; //Temporary scope fix - scope->getDataRef()->scope["+"] = new NodeTree(); - scope->getDataRef()->scope["-"] = new NodeTree(); - scope->getDataRef()->scope["*"] = new NodeTree(); - scope->getDataRef()->scope["&"] = new NodeTree(); - scope->getDataRef()->scope["--"] = new NodeTree(); - scope->getDataRef()->scope["++"] = new NodeTree(); - scope->getDataRef()->scope["=="] = new NodeTree(); - scope->getDataRef()->scope["<="] = new NodeTree(); - scope->getDataRef()->scope[">="] = new NodeTree(); - scope->getDataRef()->scope["<"] = new NodeTree(); - scope->getDataRef()->scope[">"] = new NodeTree(); - scope->getDataRef()->scope["&&"] = new NodeTree(); - scope->getDataRef()->scope["||"] = new NodeTree(); - scope->getDataRef()->scope["!"] = new NodeTree(); - scope->getDataRef()->scope["*="] = new NodeTree(); - scope->getDataRef()->scope["+="] = new NodeTree(); - scope->getDataRef()->scope["-="] = new NodeTree(); - scope->getDataRef()->scope["."] = new NodeTree(); - scope->getDataRef()->scope["->"] = new NodeTree(); + Type placeholderType; + scope->getDataRef()->scope["+"] = new NodeTree("function", ASTData(function, Symbol("+", true), &placeholderType)); + scope->getDataRef()->scope["-"] = new NodeTree("function", ASTData(function, Symbol("-", true), &placeholderType)); + scope->getDataRef()->scope["*"] = new NodeTree("function", ASTData(function, Symbol("*", true), &placeholderType)); + scope->getDataRef()->scope["&"] = new NodeTree("function", ASTData(function, Symbol("&", true), &placeholderType)); + scope->getDataRef()->scope["--"] = new NodeTree("function", ASTData(function, Symbol("--", true), &placeholderType)); + scope->getDataRef()->scope["++"] = new NodeTree("function", ASTData(function, Symbol("++", true), &placeholderType)); + scope->getDataRef()->scope["=="] = new NodeTree("function", ASTData(function, Symbol("==", true), &placeholderType)); + scope->getDataRef()->scope["<="] = new NodeTree("function", ASTData(function, Symbol("<=", true), &placeholderType)); + scope->getDataRef()->scope[">="] = new NodeTree("function", ASTData(function, Symbol(">=", true), &placeholderType)); + scope->getDataRef()->scope["<"] = new NodeTree("function", ASTData(function, Symbol("<", true), &placeholderType)); + scope->getDataRef()->scope[">"] = new NodeTree("function", ASTData(function, Symbol(">", true), &placeholderType)); + scope->getDataRef()->scope["&&"] = new NodeTree("function", ASTData(function, Symbol("&&", true), &placeholderType)); + scope->getDataRef()->scope["||"] = new NodeTree("function", ASTData(function, Symbol("||", true), &placeholderType)); + scope->getDataRef()->scope["!"] = new NodeTree("function", ASTData(function, Symbol("!", true), &placeholderType)); + scope->getDataRef()->scope["*="] = new NodeTree("function", ASTData(function, Symbol("*=", true), &placeholderType)); + scope->getDataRef()->scope["+="] = new NodeTree("function", ASTData(function, Symbol("+=", true), &placeholderType)); + scope->getDataRef()->scope["-="] = new NodeTree("function", ASTData(function, Symbol("-=", true), &placeholderType)); + scope->getDataRef()->scope["."] = new NodeTree("function", ASTData(function, Symbol(".", true), &placeholderType)); + scope->getDataRef()->scope["->"] = new NodeTree("function", ASTData(function, Symbol("->", true), &placeholderType)); } else if (name == "interpreter_directive") { newNode = new NodeTree(name, ASTData(interpreter_directive)); @@ -63,7 +64,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree //std::cout << "scope lookup from identifier" << std::endl; newNode = scopeLookup(scope, lookupName); if (newNode == NULL) { - std::cout << "scope lookup error! Could not find " << lookupName << std::endl; + std::cout << "scope lookup error! Could not find " << lookupName << " in identifier " << std::endl; throw "LOOKUP ERROR: " + lookupName; } else if (newNode->getDataRef()->symbol.getName() !=lookupName) { //This happens when the lookup name denotes a member of an object, i.e. obj.foo @@ -81,6 +82,8 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode->getDataRef()->valueType = new Type(newNode); //Type is self-referential since this is the definition } scope->getDataRef()->scope[typeAlias] = newNode; + newNode->getDataRef()->scope["~enclosing_scope"] = scope; + scope = newNode; skipChildren.insert(0); //Identifier lookup will be ourselves, as we just added ourselves to the scope //return newNode; } else if (name == "function") { @@ -91,6 +94,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree scope->getDataRef()->scope[functionName] = newNode; newNode->getDataRef()->scope["~enclosing_scope"] = scope; scope = newNode; + std::cout << "finished function " << functionName << std::endl; } else if (name == "code_block") { newNode = new NodeTree(name, ASTData(code_block)); newNode->getDataRef()->scope["~enclosing_scope"] = scope; @@ -101,19 +105,19 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree std::string typeString = concatSymbolTree(children[0]);//Get the type (left child) and set our new identifer to be that type newNode = new NodeTree("identifier", ASTData(identifier, Symbol(parameterName, true), typeFromString(typeString, scope))); scope->getDataRef()->scope[parameterName] = newNode; + newNode->getDataRef()->scope["~enclosing_scope"] = scope; return newNode; } else if (name == "boolean_expression" || name == "and_boolean_expression" || name == "bool_exp") { //If this is an actual part of an expression, not just a premoted term if (children.size() > 1) { - std::string functionCallName = concatSymbolTree(children[1]); - //std::cout << "scope lookup from boolen_expression or similar" << std::endl; - NodeTree* function = scopeLookup(scope, functionCallName); + std::string functionCallString = concatSymbolTree(children[1]); + NodeTree* function = scopeLookup(scope, functionCallString); if (function == NULL) { - std::cout << "scope lookup error! Could not find " << functionCallName << std::endl; - throw "LOOKUP ERROR: " + functionCallName; + std::cout << "scope lookup error! Could not find " << functionCallString << " in boolean stuff " << std::endl; + throw "LOOKUP ERROR: " + functionCallString; } - newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); - newNode->addChild(function); // First child of function call is a link to the function definition + newNode = new NodeTree(functionCallString, ASTData(function_call)); + newNode->addChild(function); // First child of function call is a link to the function skipChildren.insert(1); } else { //std::cout << children.size() << std::endl; @@ -129,12 +133,25 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree //std::cout << "scope lookup from expression or similar" << std::endl; NodeTree* function = scopeLookup(scope, functionCallName); if (function == NULL) { - std::cout << "scope lookup error! Could not find " << functionCallName << std::endl; + std::cout << "scope lookup error! Could not find " << functionCallName << " in expression " << std::endl; throw "LOOKUP ERROR: " + functionCallName; } newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); newNode->addChild(function); // First child of function call is a link to the function definition - skipChildren.insert(1); + NodeTree* lhs = transform(children[0], scope); + NodeTree* rhs;// = transform(children[2], scope); + if (name == "access_operation") + rhs = transform(children[2], lhs->getDataRef()->valueType->typeDefinition); //If an access operation, then the right side will be in the lhs's type's scope + else + rhs = transform(children[2], scope); + + if (name == "access_operation") + std::cout << "Access Operation: " << lhs->getDataRef()->symbol.getName() << " : " << rhs->getDataRef()->symbol.getName() << std::endl; + + newNode->addChild(lhs); + newNode->addChild(rhs); + return newNode; + //skipChildren.insert(1); } else { return transform(children[0], scope); //Just a promoted child, so do it instead } @@ -152,7 +169,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree //std::cout << "scope lookup from factor" << std::endl; NodeTree* function = scopeLookup(scope, funcName); if (function == NULL) { - std::cout << "scope lookup error! Could not find " << funcName << std::endl; + std::cout << "scope lookup error! Could not find " << funcName << " in factor " << std::endl; throw "LOOKUP ERROR: " + funcName; } newNode = new NodeTree(funcName, ASTData(function_call, Symbol(funcName, true))); @@ -184,7 +201,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree NodeTree* childCall = new NodeTree(functionName, ASTData(function_call, Symbol(functionName, true))); NodeTree* functionDef = scopeLookup(scope, functionName); if (functionDef == NULL) { - std::cout << "scope lookup error! Could not find " << functionName << std::endl; + std::cout << "scope lookup error! Could not find " << functionName << " in assignment_statement " << std::endl; throw "LOOKUP ERROR: " + functionName; } childCall->addChild(functionDef); //First child of function call is definition of the function @@ -204,6 +221,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree Type* identifierType = typeFromString(typeString, scope); NodeTree* newIdentifier = new NodeTree("identifier", ASTData(identifier, Symbol(newIdentifierStr, true), identifierType)); scope->getDataRef()->scope[newIdentifierStr] = newIdentifier; + newNode->getDataRef()->scope["~enclosing_scope"] = scope; //Now we don't do this thing // if (identifierType->typeDefinition) { // //Is a custom type. Populate this declaration's scope with it's inner declarations @@ -226,12 +244,19 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } else if (name == "function_call") { std::string functionCallName = concatSymbolTree(children[0]); newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); - //std::cout << "scope lookup from function_call" << std::endl; - NodeTree* function = scopeLookup(scope, functionCallName); - if (function == NULL) { - std::cout << "scope lookup error! Could not find " << functionCallName << std::endl; - throw "LOOKUP ERROR: " + functionCallName; - } + std::cout << "scope lookup from function_call: " << functionCallName << std::endl; + for (auto i : children) + std::cout << i << " : " << i->getName() << " : " << i->getDataRef()->getName() << std::endl; + //NodeTree* function = scopeLookup(scope, functionCallName); + NodeTree* function = transform(children[0], scope);/* scopeLookup(scope, functionCallName);*/ + std::cout << "The thing: " << function << " : " << function->getName() << std::endl; + for (auto i : function->getChildren()) + std::cout << i->getName() << " "; + std::cout << std::endl; + // if (function == NULL) { + // std::cout << "scope lookup error! Could not find " << functionCallName << " in function_call " << std::endl; + // throw "LOOKUP ERROR: " + functionCallName; + // } newNode->addChild(function); skipChildren.insert(0); } else if (name == "parameter") { diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index 5d88a66..1fa959b 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -35,16 +35,17 @@ std::string CGenerator::tabs() { return returnTabs; } -std::string CGenerator::generate(NodeTree* from) { +//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* from, NodeTree* enclosingObject) { ASTData data = from->getData(); std::vector*> 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]) + "\n"; + output += generate(children[i], enclosingObject) + "\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++) { NodeTree* declaration = i->second; @@ -55,11 +56,15 @@ std::string CGenerator::generate(NodeTree* from) { output += ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "; /*identifier*/\n"; break; case function: + if (decChildren.size() == 0) { //Not a real function, must be a built in passthrough { + output += "/* built in function: " + declarationData.toString() + " */\n"; + break; + } output += "\n" + ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "("; for (int j = 0; j < decChildren.size()-1; j++) { if (j > 0) output += ", "; - output += ValueTypeToCType(decChildren[j]->getData().valueType) + " " + generate(decChildren[j]); + output += ValueTypeToCType(decChildren[j]->getData().valueType) + " " + generate(decChildren[j], enclosingObject); } output += "); /*func*/\n"; break; @@ -75,7 +80,7 @@ std::string CGenerator::generate(NodeTree* from) { //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]) + "\n"; + output += generate(children[i], enclosingObject) + "\n"; return output; break; case interpreter_directive: @@ -85,31 +90,47 @@ std::string CGenerator::generate(NodeTree* from) { return "/* would import \"" + data.symbol.getName() + "\" but....*/\n"; //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. + if (enclosingObject && enclosingObject->getDataRef()->scope.find(data.symbol.getName()) != enclosingObject->getDataRef()->scope.end()) { + return "self->" + data.symbol.getName(); + } return data.symbol.getName(); + } 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"; - for (int i = 0; i < children.size(); i++) - objectString += generate(children[i]) + "\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; + return objectString + postString; //Functions come after the declaration of the struct } case function: output += "\n" + ValueTypeToCType(data.valueType) + " " + data.symbol.getName() + "("; for (int i = 0; i < children.size()-1; i++) { if (i > 0) output += ", "; - output += ValueTypeToCType(children[i]->getData().valueType) + " " + generate(children[i]); + output += ValueTypeToCType(children[i]->getData().valueType) + " " + generate(children[i], enclosingObject); } - output+= ")\n" + generate(children[children.size()-1]); + output+= ")\n" + generate(children[children.size()-1], enclosingObject); return output; case code_block: output += "{\n"; tabLevel++; - for (int i = 0; i < children.size(); i++) - output += generate(children[i]); + 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--; output += tabs() + "}"; return output; @@ -118,60 +139,82 @@ std::string CGenerator::generate(NodeTree* from) { case boolean_expression: output += " " + data.symbol.getName() + " "; case statement: - return tabs() + generate(children[0]) + ";\n"; + return tabs() + generate(children[0], enclosingObject) + ";\n"; case if_statement: - output += "if (" + generate(children[0]) + ")\n\t" + generate(children[1]); + output += "if (" + generate(children[0], enclosingObject) + ")\n\t" + generate(children[1], enclosingObject); if (children.size() > 2) - output += " else " + generate(children[2]); + output += " else " + generate(children[2], enclosingObject); return output; case while_loop: - output += "while (" + generate(children[0]) + ")\n\t" + generate(children[1]); + output += "while (" + generate(children[0], enclosingObject) + ")\n\t" + generate(children[1], enclosingObject); return output; case for_loop: //The strSlice's are there to get ride of an unwanted return and an unwanted semicolon(s) - output += "for (" + strSlice(generate(children[0]),0,-3) + generate(children[1]) + ";" + strSlice(generate(children[2]),0,-3) + ")\n\t" + generate(children[3]); + output += "for (" + strSlice(generate(children[0], enclosingObject),0,-3) + generate(children[1], enclosingObject) + ";" + strSlice(generate(children[2], enclosingObject),0,-3) + ")\n\t" + generate(children[3], enclosingObject); return output; case return_statement: if (children.size()) - return "return " + generate(children[0]); + return "return " + generate(children[0], enclosingObject); else return "return"; case assignment_statement: - return generate(children[0]) + " = " + generate(children[1]); + return generate(children[0], enclosingObject) + " = " + generate(children[1], enclosingObject); case declaration_statement: if (children.size() == 1) - return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0]) + ";"; + return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + ";"; else - return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0]) + " = " + generate(children[1]) + ";"; + return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + " = " + generate(children[1], enclosingObject) + ";"; case if_comp: - if (generate(children[0]) == generatorString) - return generate(children[1]); + if (generate(children[0], enclosingObject) == generatorString) + return generate(children[1], enclosingObject); return ""; case simple_passthrough: - return strSlice(generate(children[0]), 3, -4); + return strSlice(generate(children[0], enclosingObject), 3, -4); case function_call: { //NOTE: The first (0th) child of a function call node is the declaration of the function //Handle operators specially for now. Will later replace with //Inlined functions in the standard library - std::string name = data.symbol.getName(); - //std::cout << name << " == " << children[0]->getData().symbol.getName() << std::endl; - if (name == "++" || name == "--") - return generate(children[1]) + name; - if (name == "*" && children.size() == 2) //Is dereference, not multiplication - return "*(" + generate(children[1]) + ")"; - if (name == "+" || name == "-" || name == "*" || name == "/" || name == "==" || name == ">=" || name == "<=" || name == "!=" - || name == "<" || name == ">" || name == "%" || name == "+=" || name == "-=" || name == "*=" || name == "/=" || name == "||" - || name == "&&" || name == "!" ) - return "((" + generate(children[1]) + ")" + name + "(" + generate(children[2]) + "))"; - else if (name == "." || name == "->") - return "((" + generate(children[1]) + ")" + name + generate(children[2]) + ")"; - output += data.symbol.getName() + "("; + // std::string name = data.symbol.getName(); + // std::cout << name << " == " << children[0]->getData().symbol.getName() << std::endl; + std::string name = children[0]->getDataRef()->symbol.getName(); + ASTType funcType = children[0]->getDataRef()->type; + std::cout << "Doing function: " << name << std::endl; + //Test for specail functions only if what we're testing is, indeed, the definition, not a function call that returns a callable function pointer + 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 == "*" || 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) + return "/*dot operation with one child*/" + generate(children[0], enclosingObject) + "/*end one child*/"; + //If this is accessing an actual function, just output the name. No actual function definition should be in an access operation + if (children[2]->getDataRef()->type == function) + return "((" + generate(children[1], enclosingObject) + ")" + name + children[2]->getDataRef()->symbol.getName() + ")"; + return "((" + generate(children[1], enclosingObject) + ")" + name + generate(children[2], enclosingObject) + ")"; + } + } + //output += data.symbol.getName() + "("; + if (funcType == function) { + output += name + "("; + std::cout << "Is a function, outputting name!" << std::cout; + if (enclosingObject && enclosingObject->getDataRef()->scope.find(name) != enclosingObject->getDataRef()->scope.end()) { + //So, it is part of the enclosing object's namespace, so it's (for now) a member function and we need to pass in an implicit self reference + output += ValueTypeToCType(enclosingObject->getDataRef()->valueType) + "* self, "; + } + } else { + output += generate(children[0], enclosingObject) + "("; + } for (int i = 1; i < children.size(); i++) //children[0] is the declaration if (i < children.size()-1) - output += generate(children[i]) + ", "; - else output += generate(children[i]); + output += generate(children[i], enclosingObject) + ", "; + else output += generate(children[i], enclosingObject); output += ") "; return output; } @@ -182,11 +225,24 @@ std::string CGenerator::generate(NodeTree* from) { std::cout << "Nothing!" << std::endl; } for (int i = 0; i < children.size(); i++) - output += generate(children[i]); + output += generate(children[i], enclosingObject); return output; } +std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, NodeTree* from) { + std::string output; + ASTData data = from->getData(); + Type enclosingObjectType = *(enclosingObject->getDataRef()->valueType); //Copy a new type so we can turn it into a pointer + enclosingObjectType.indirection++; + std::vector*> children = from->getChildren(); + output += "\n" + ValueTypeToCType(data.valueType) + " " + enclosingObject->getDataRef()->symbol.getName() +"__" + data.symbol.getName() + "(" + ValueTypeToCType(&enclosingObjectType) + " self"; + for (int i = 0; i < children.size()-1; i++) + output += ", " + ValueTypeToCType(children[i]->getData().valueType) + " " + generate(children[i]); + output+= ")\n" + generate(children[children.size()-1], enclosingObject); //Pass in the object so we can + return output; +} + std::string CGenerator::ValueTypeToCType(Type *type) { std::string return_type; switch (type->baseType) {