#include "ProjectParser.h" #include "Component.h" #include "Generator.h" #include "HostPlatform.h" #include "Project.h" #include "SharedRef.h" #include "TokenStream.h" #include "ToolChain.h" #include #include class Block; class Declaration; class Expression; class Context { public: Context(Project& aProject, TokenStream& anInput) : theProject(aProject), Input(anInput) { } SharedPtr lookup(const std::string& Name); Project& theProject; TokenStream& Input; std::vector Stack; private: Context& operator=(const Context&) { return *this; } }; SharedPtr memberCall(Context& Here, SharedPtr This, SharedPtr& Object, const std::string& Name, const std::vector >& Arguments); SharedPtr memberCall(Context& Here, SharedPtr This, SharedPtr& Object, const std::string& Name, const std::vector >& Arguments); SharedPtr evaluateBuiltIn(Context& Here, const std::vector::const_iterator Begin, const std::vector::const_iterator End); class Statement { public: Statement() { } virtual ~Statement() { } virtual void print(const std::string& id) const = 0; virtual void execute(Context& Here) = 0; }; class EmptyStatement : public Statement { public: virtual void print(const std::string&) const { } virtual void execute(Context&) { } }; class Expression : public Statement { public: virtual SharedPtr evaluate(Context& Here) const = 0; }; class VoidExpression : public Expression { public: virtual void print(const std::string&) const { std::cout << "(void)" << std::endl; } virtual void execute(Context&) { } virtual SharedPtr evaluate(Context&) const { return new VoidExpression; } }; class BoolExpression : public Expression { public: BoolExpression(bool aValue) : Value(aValue) { } virtual void print(const std::string& id) const { std::cout << id << (Value?"true":"false") << std::endl; } virtual void execute(Context&) { } virtual SharedPtr evaluate(Context&) const { return new BoolExpression(Value); } bool value() const { return Value; } private: bool Value; }; class StringLiteral : public Expression { public: StringLiteral(const std::string& aContent) : Content(aContent) { } virtual void print(const std::string& id) const { std::cout << id << "\"" << Content << "\"" << std::endl; } virtual void execute(Context&) { } virtual SharedPtr evaluate(Context&) const { return new StringLiteral(Content); } const std::string& content() const { return Content; } private: std::string Content; }; class Declaration : public Expression { public: typedef enum {Executable, CCSource, Component, Generator} Type; Declaration(Type aWhat, const std::string& aName, const std::vector >& Args) : What(aWhat), Name(aName), Arguments(Args) { } Declaration(SharedPtr< ::Component> aComp) : What(Component), Name(""), AsComponent(aComp) { } Declaration(SharedPtr< ::CCSource> aSource) : What(CCSource), Name(""), AsCCSource(aSource) { } Declaration(const Declaration& other) : What(other.What), Name(other.Name), AsExecutable(other.AsExecutable), AsComponent(other.AsComponent), AsGenerator(other.AsGenerator) { } SharedPtr< ::Component> component() { return AsComponent; } SharedPtr< ::CCSource> ccSource() { return AsCCSource; } virtual void print(const std::string& id) const { std::cout << id << "DECLARATION OF " << Name << " AS "; switch (What) { case Executable: std::cout << "Executable("; break; case CCSource: std::cout << "CCSource("; break; case Component: std::cout << "Component("; break; case Generator: std::cout << "Generator("; break; } for (unsigned int i=0; iprint(id+" "); } std::cout << id << ")" << std::endl; } const std::string& name() const { return Name; } virtual void execute(Context& Here) { if (Name.length() && !Here.lookup(Name).isNull()) Here.Input.error("Declaration of "+Name+" shadows earlier one."); switch (What) { case Executable: if (AsExecutable.isNull()) { AsExecutable = new ::Executable(Name); Here.theProject.add(AsExecutable); ::memberCall(Here,SharedPtr(),AsExecutable,"",Arguments); } break; case CCSource: // TODO break; case Component: if (AsComponent.isNull()) { Here.Input.error("Can't instantiate a component yourself"); } break; case Generator: if (AsGenerator.isNull()) { std::vector Template; for (unsigned int i=0; i Arg( Arguments[i]->evaluate(Here).dynamicCast()); if (Arg.isNull()) Here.Input.error("Argument of Generator constructor must be a string"); else Template.push_back(Arg->content()); } AsGenerator = new ::Generator(Template); AsGenerator->configuration().setParent( &Here.theProject.configuration()); } break; }; } SharedPtr memberCall(Context& Here, SharedPtr& This, const std::string& Name, const std::vector >& Arguments) { switch (What) { case Executable: return ::memberCall(Here,This,AsExecutable,Name,Arguments); break; case CCSource: // TODO break; case Component: Here.Input.error("Component does not support call "+Name); break; case Generator: return ::memberCall(Here,This,AsGenerator,Name,Arguments); break; } return new VoidExpression; } virtual SharedPtr evaluate(Context&) const { SharedPtr Result(new Declaration(*this)); return Result; } private: Type What; std::string Name; SharedPtr< ::Executable> AsExecutable; SharedPtr< ::CCSource> AsCCSource; SharedPtr< ::Component> AsComponent; SharedPtr< ::Generator> AsGenerator; std::vector > Arguments; }; class VariablePtrerence : public Expression { public: VariablePtrerence(const std::string& aName) : Name(aName) { } virtual void print(const std::string& id) const { std::cout << id << Name << std::endl; } virtual void execute(Context& Here) { evaluate(Here); } SharedPtr evaluate(Context& Here) const { SharedPtr Var(Here.lookup(Name)); if (Var.isNull()) { Here.Input.error("Unkown object "+Name); return new VoidExpression; } return Var.validCast(); } private: std::string Name; }; class BuiltInVariable : public Expression { public: BuiltInVariable(const std::string& a, const std::string& b) { Names.push_back(a); Names.push_back(b); } BuiltInVariable(const std::vector & aNames) : Names(aNames) { } virtual void print(const std::string& id) const { std::cout << id; for (unsigned int i=0;i evaluate(Context& Here) const { return evaluateBuiltIn(Here,Names.begin(),Names.end()); } bool is(const std::string& What) const { std::string Total; for (unsigned int i=0; i Names; }; class MemberCall : public Expression { public: MemberCall(SharedPtr anObj, const std::string& aName, const std::vector >& Args) : Object(anObj), Name(aName), Arguments(Args) { if (Object.isNull()) Object = new VoidExpression; } virtual void print(const std::string& id) const { Object->print(id); std::cout << id << " . " << Name << " ("; for (unsigned int i=0; iprint(id+" "); } if (Arguments.size()) std::cout << id << " )" << std::endl; else std::cout << " )" << std::endl; } virtual void execute(Context& Here) { evaluate(Here); } virtual SharedPtr evaluate(Context& Here) const { SharedPtr Var(Object->evaluate(Here).dynamicCast()); if (Var.isNull()) Here.Input.error("Left hand side of member call was not a composite object"); else return Var->memberCall(Here,Var,Name,Arguments); return new VoidExpression; } private: SharedPtr Object; std::string Name; std::vector > Arguments; }; class ShiftLeftExpression : public Expression { public: ShiftLeftExpression(SharedPtr aLeft, SharedPtr aRight) : Left(aLeft), Right(aRight) { if (Left.isNull()) Left = new VoidExpression; if (Right.isNull()) Right = new VoidExpression; } virtual void print(const std::string& id) const { Left->print(id); std::cout << id << " << "; Right->print(id+" "); } virtual void execute(Context& Here) { evaluate(Here); } virtual SharedPtr evaluate(Context& Here) const { SharedPtr First(Left->evaluate(Here)); SharedPtr FirstAsBuiltIn(First.dynamicCast()); if (!FirstAsBuiltIn.isNull() && FirstAsBuiltIn->is("std::cout")) { SharedPtr Second(Right->evaluate(Here)); SharedPtr SecondAsString(Second.dynamicCast()); if (!SecondAsString.isNull()) { std::cout << SecondAsString->content(); return First; } SharedPtr SecondAsVariable(Second.dynamicCast()); if (!SecondAsVariable.isNull() && SecondAsVariable->is("std::endl")) { std::cout << std::endl; return First; } Here.Input.error("Can't print right hand side of left shift"); return First; } Here.Input.error("Invalid expression type for left argument of left shift."); return new VoidExpression; } private: SharedPtr Left, Right; }; class Block : public Statement { public: Block() : StatementsSeen(0) { } void add(const SharedPtr& One) { List.push_back(One); } virtual void execute(Context& Here) { Here.Stack.push_back(this); for (StatementsSeen=0; StatementsSeenexecute(Here); Here.Stack.pop_back(); } virtual void print(const std::string& id) const { std::cout << id << "{" << std::endl; for (unsigned int i=0; iprint(id+" "); std::cout << id << "}" << std::endl; } void clear() { List.clear(); } SharedPtr lookup(const std::string& Name) { for (unsigned int i=0; i Current(List[i].dynamicCast()); if (!Current.isNull() && (Current->name() == Name)) return Current; } return SharedPtr(); } private: std::vector > List; unsigned int StatementsSeen; }; class IfStatement : public Statement { public: IfStatement(SharedPtr aCond, SharedPtr anIf, SharedPtr anElse) : Condition(aCond), If(anIf), Else(anElse) { if (Condition.isNull()) Condition = new StringLiteral(""); if (If.isNull()) If = new EmptyStatement; if (Else.isNull()) Else = new EmptyStatement; } virtual void print(const std::string& id) const { std::cout << id << "if (" << std::endl; Condition->print(id+" "); std::cout << id << ")" << std::endl << id << "{" << std::endl; If->print(id+" "); std::cout << id << "} else {" << std::endl; Else->print(id+" "); std::cout << id << "}" << std::endl; } virtual void execute(Context& Here) { SharedPtr Result(Condition->evaluate(Here).dynamicCast()); if (Result.isNull()) Here.Input.error("Condition on if-clause does not evaluate to boolean expression."); else { if (Result->value()) If->execute(Here); else Else->execute(Here); } } private: SharedPtr Condition; SharedPtr If,Else; }; /* CONTEXT */ SharedPtr Context::lookup(const std::string& Name) { for (unsigned int i=Stack.size(); i; --i) { SharedPtr Test(Stack[i-1]->lookup(Name)); if (!Test.isNull()) return Test; } return SharedPtr(); } /* PROJECTPARSER */ class ProjectParser { public: ProjectParser(Project& aProject, const std::string& Filename, bool aMode); private: SharedPtr statement(SharedPtr& Scope); SharedPtr block(SharedPtr& Scope); SharedPtr declaration(SharedPtr& Scope); SharedPtr ifStatement(SharedPtr& Scope); SharedPtr expression(); SharedPtr factorExpression(); SharedPtr basicExpression(); SharedPtr builtinVariable(); std::vector > argumentList(bool Mandatory); void skipToEndOfStatement(); TokenStream Input; SharedPtr Global; bool DiscoveryMode; }; ProjectParser::ProjectParser(Project& theProject, const std::string& Filename, bool aMode) : Input(Filename), Global(new Block), DiscoveryMode(aMode) { while (!Input.eos()) { SharedPtr Next(statement(Global)); if (Next.isNull()) { skipToEndOfStatement(); Input.error("expected a statement got "+Input.cToken()); } else Global->add(Next); Input.whiteSpace(); } Global->print(""); if (Input.errors()) { std::cerr << Input.errors() << " error(s) detected" << std::endl; return; } Context theContent(theProject,Input); Global->execute(theContent); } void ProjectParser::skipToEndOfStatement() { while (!Input.eosButWhite()) { std::string Token(Input.cToken()); if (Token == "}") break; if (Token == ";") break; } } SharedPtr ProjectParser::statement(SharedPtr& Scope) { SharedPtr AsBlock(block(Scope)); if (!AsBlock.isNull()) return AsBlock.validCast(); SharedPtr AsIf(ifStatement(Scope)); if (!AsIf.isNull()) return AsIf; SharedPtr AsDeclaration(declaration(Scope)); if (!AsDeclaration.isNull()) { if (!Input.literal(";")) Input.error("; expected after declaration"); return AsDeclaration; } SharedPtr AsExpression(expression()); if (!AsExpression.isNull()) { if (!Input.literal(";")) Input.error("; expected after expression"); return AsExpression.validCast(); } /* if (assignmentStatement()) { if (!Input.literal(";")) Input.error("; expected after assignment"); return true; } */ return SharedPtr(); } SharedPtr ProjectParser::block(SharedPtr& ) { if (!Input.literal("{")) return SharedPtr(); SharedPtr NewBlock(new Block); while (!Input.eos()) { if (Input.literal("}")) return NewBlock; SharedPtr Next(statement(NewBlock)); if (Next.isNull()) { Input.error("expected a statement got "+Input.cToken()); skipToEndOfStatement(); } else NewBlock->add(Next); Input.whiteSpace(); } Input.error("unexpected end of file, expected } to close statement block"); return NewBlock; } SharedPtr ProjectParser::ifStatement(SharedPtr& Scope) { if (!Input.literal("if")) return SharedPtr(); if (!Input.literal("(")) Input.error("expecting ( after if"); SharedPtr Condition(expression()); if (Condition.isNull()) { Input.error("expecting an expression for if clause"); } if (!Input.literal(")")) Input.error("expecting ) to close if-expression"); SharedPtr If(statement(Scope)); if (If.isNull()) { Input.error("expecting a statement after if expression"); skipToEndOfStatement(); } SharedPtr Else; if (Input.literal("else")) { Else = statement(Scope); if (Else.isNull()) Input.error("expecting a statement after else expression"); } return new IfStatement(Condition,If,Else); } SharedPtr ProjectParser::declaration(SharedPtr& Scope) { if (Input.literal("Executable")) { std::string Name = Input.cIdentifier(); if (!Name.length()) Input.error("Name expected for Executable"); else if (!Scope->lookup(Name).isNull()) Input.error("Name already used"); else return new Declaration(Declaration::Executable,Name,argumentList(false)); return new EmptyStatement; } else if (Input.literal("CCSource")) { std::string Name = Input.cIdentifier(); if (!Name.length()) { Input.error("Name expected for CCSource"); return new EmptyStatement; // TODO pass empty statement instead } // TODO check if name already exists // also check constructor SharedPtr Result(new Declaration(Declaration::CCSource,Name,argumentList(false))); // ccSourceConstructor(PV); return Result; } else if (Input.literal("Generator")) { std::string Name(Input.cIdentifier()); if (!Name.length()) { Input.error("Name expeced for Generator"); return new EmptyStatement; } return new Declaration(Declaration::Generator,Name,argumentList(false)); } return SharedPtr(); } SharedPtr ProjectParser::expression() { SharedPtr Result(factorExpression()); if (!Result.isNull()) { while (Input.literal("<<")) { SharedPtr Right(factorExpression()); if (Right.isNull()) Input.error("Expression expected as right hand side of left shift"); Result = new ShiftLeftExpression(Result,Right); } } return Result; } SharedPtr ProjectParser::factorExpression() { SharedPtr Object(basicExpression()); while (!Object.isNull() && Input.literal(".")) { std::string MemberName(Input.cIdentifier()); if (!MemberName.length()) { Input.error("Member name expected after ."); break; } Object = new MemberCall(Object,MemberName,argumentList(true)); } return Object; } std::vector > ProjectParser::argumentList(bool Mandatory) { std::vector > Arguments; if (Mandatory && !Input.literal("(")) { Input.error("Argument list expected."); return Arguments; } else if (!Mandatory && !Input.literal("(")) return Arguments; bool First = true; while (!Input.literal(")")) { if (Input.eos()) { Input.error("End of stream reached instead of )"); break; } if (!First && !Input.literal(",")) Input.error("expected , between arguments"); First = false; SharedPtr Argument(expression()); if (Argument.isNull()) Input.error("expected an expression"); else Arguments.push_back(Argument); } return Arguments; } SharedPtr ProjectParser::basicExpression() { if (Input.literal("true")) return new BoolExpression(true); if (Input.literal("false")) return new BoolExpression(false); std::string StringLit(Input.cString()); if (StringLit.size()) return new StringLiteral(StringLit.substr(1,StringLit.length())); SharedPtr AsBuiltIn(builtinVariable()); if (!AsBuiltIn.isNull()) return AsBuiltIn; std::string Identifier(Input.cIdentifier()); if (Identifier.length()) return new VariablePtrerence(Identifier); return SharedPtr(); } SharedPtr ProjectParser::builtinVariable() { TokenPoint Pt(Input); std::vector Names; std::string Name = Input.cIdentifier(); if (!Name.length() || !Input.literal("::")) return SharedPtr(); Names.push_back(Name); do { Name = Input.cIdentifier(); if (!Name.length()) { Input.error("Expected identifier after ::"); break; } Names.push_back(Name); } while (Input.literal("::")); Pt.accept(); return new BuiltInVariable(Names); } #if 0 bool ProjectParser::assignmentStatement() { TokenPoint Pt(Input); VariablePtr* PV(existingVar(true)); if (!PV) return false; VariablePtr LeftSide(*PV); if (Input.cToken() != "=") return false; VariablePtr RightSide(expression()); if (SilentLockCount) return Pt.accept(); std::string err(LeftSide->assignFrom(RightSide)); if (err.length()) Input.error(err); return Pt.accept(); } #endif void executableConstructor(Context& Here, SharedPtr& Object, const std::vector >& Arguments) { if (!Arguments.size()) return; if (Arguments.size() != 1) { Here.Input.error("Executable constructor does not match Executable() or Executable(std::string)"); return; } SharedPtr Name(Arguments[0]->evaluate(Here).dynamicCast()); if (Name.isNull()) { Here.Input.error("Executable constructor does not match Executable() or Executable(std::string)"); return; } Object->setName(Name->content()); } void executableAdd(Context& Here, SharedPtr& Object, const std::vector >& Arguments) { for (unsigned int i=0; i Result(Arguments[i]->evaluate(Here)); SharedPtr AsString(Result.dynamicCast()); if (AsString.isNull()) { SharedPtr AsDecl(Result.dynamicCast()); if (AsDecl.isNull() || AsDecl->ccSource().isNull()) Here.Input.error("Argument to Executable::add is not a string or ccsource"); else Object->add(AsDecl->ccSource()); } else Object->add(new CCSource(AsString->content())); } } void executableDefine(Context& Here, SharedPtr& Object, const std::vector >& Arguments) { for (unsigned int i=0; i Result(Arguments[i]->evaluate(Here).dynamicCast()); if (Result.isNull()) Here.Input.error("Argument to Executable::define is not a string"); else Object->configuration().addDefine(Result->content()); } } void executableUse(Context& Here, SharedPtr& Object, const std::vector >& Arguments) { for (unsigned int i=0; i Result(Arguments[i]->evaluate(Here).dynamicCast()); if (Result.isNull() || Result->component().isNull()) Here.Input.error("Executable::use called with a wrong parameter"); else Object->add(Result->component()); } } SharedPtr memberCall(Context& Here, SharedPtr This, SharedPtr& Object, const std::string& Name, const std::vector >& Arguments) { if (Name == "") { executableConstructor(Here,Object,Arguments); return This.validCast(); } else if (Name == "add") { executableAdd(Here, Object,Arguments); return This.validCast(); } else if (Name == "define") { executableDefine(Here,Object,Arguments); return This.validCast(); } else if (Name == "use") { executableUse(Here,Object,Arguments); return This.validCast(); } else Here.Input.error("Unknown membercall "+Name); return new VoidExpression; } void generatorOutput(Context& Here, SharedPtr& Object, const std::vector >& Arguments) { if (Arguments.size() != 1) { Here.Input.error("Generator::output takes one std::string argument"); return; } SharedPtr Result(Arguments[0]->evaluate(Here).dynamicCast()); if (Result.isNull()) Here.Input.error("Argument to Executable::output is not a string"); else Object->setOutput(Result->content()); } void generatorInput(Context& Here, SharedPtr& Object, const std::vector >& Arguments) { for (unsigned int i=0; i Result(Arguments[i]->evaluate(Here).dynamicCast()); if (Result.isNull()) Here.Input.error("Argument to Generator::input is not a string"); else Object->addInput(Result->content()); } } SharedPtr generatorMakeCCSource(Context& Here, SharedPtr& Object, const std::vector >& Arguments) { if (Arguments.size()) Here.Input.error("Generator::makeCCSource takes no arguments"); return new Declaration(new GeneratedCCSource(Object)); } SharedPtr memberCall(Context& Here, SharedPtr This, SharedPtr& Object, const std::string& Name, const std::vector >& Arguments) { if (Name == "output") { generatorOutput(Here, Object,Arguments); return This.validCast(); } else if (Name == "input") { generatorInput(Here,Object,Arguments); return This.validCast(); } else if (Name == "makeCCSource") return generatorMakeCCSource(Here,Object,Arguments); else Here.Input.error("Unknown membercall "+Name); return new VoidExpression; } SharedPtr evaluateHostPlatformBuiltIn(Context& Here, const std::vector::const_iterator Begin, const std::vector::const_iterator End) { if (Begin == End) { Here.Input.error("Subnamespace expected"); return new VoidExpression; } if (Begin+1 != End) { Here.Input.error("Subnamespace not expected"); return new VoidExpression; } if (*Begin == "is_windows") return new BoolExpression(hostIsWindows()); else if (*Begin == "is_macosx") return new BoolExpression(hostIsMacOSX()); else Here.Input.error("Unknown variable "+*Begin); return new VoidExpression; } SharedPtr evaluateStdBuiltIn(Context& Here, const std::vector::const_iterator Begin, const std::vector::const_iterator End) { if (Begin == End) { Here.Input.error("Subnamespace expected"); return new VoidExpression; } if (*Begin == "cout") return new BuiltInVariable("std","cout"); else if (*Begin == "endl") return new BuiltInVariable("std","endl"); else if (*Begin == "target_platform") // TODO CROSSCOMPILING then target!=host return evaluateHostPlatformBuiltIn(Here,Begin+1,End); else if (*Begin == "host_platform") return evaluateHostPlatformBuiltIn(Here,Begin+1,End); else { Here.Input.error("Unknown namespace "+*Begin); return new VoidExpression; } } SharedPtr evaluateLibraryBuiltIn(Context& Here, const std::vector::const_iterator Begin, const std::vector::const_iterator End) { if (Begin == End) { Here.Input.error("Subnamespace expected"); return new VoidExpression; } std::string Total; for (std::vector::const_iterator i=Begin; i!=End; ++i) { if (i!=Begin) Total+="::"; Total += *i; } SharedPtr Result(createComponentFromName(Total)); if (Result.isNull()) { Here.Input.error("Unkown component "+Total); return new VoidExpression; } return new Declaration(Result); } SharedPtr evaluateBuiltIn(Context& Here, const std::vector::const_iterator Begin, const std::vector::const_iterator End) { if (Begin == End) { Here.Input.error("Subnamespace expected"); return new VoidExpression; } if (*Begin == "std") return evaluateStdBuiltIn(Here,Begin+1,End); else if (*Begin == "library") return evaluateLibraryBuiltIn(Here,Begin+1,End); else { Here.Input.error("Unknown namespace "+*Begin); return new VoidExpression; } } void parse(Project& theProject, const std::string& Filename, bool DiscoveryMode) { ProjectParser PP(theProject, Filename, DiscoveryMode); }