From: luke Date: Sun, 11 Feb 2018 07:49:17 +0000 (-0500) Subject: Initial commit X-Git-Url: http://git.lukelau.me/?p=kaleidoscope.git;a=commitdiff_plain;h=5f81038886345b9c1e130bc7cfdd463e76b37b84 Initial commit --- diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6f79b2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Kaleidoscope/bin +*.xcodeproj/xcuserdata/ diff --git a/Kaleidoscope.xcodeproj/project.pbxproj b/Kaleidoscope.xcodeproj/project.pbxproj index 09e6486..01ca27d 100644 --- a/Kaleidoscope.xcodeproj/project.pbxproj +++ b/Kaleidoscope.xcodeproj/project.pbxproj @@ -7,7 +7,10 @@ objects = { /* Begin PBXBuildFile section */ - A38E77AA1E3961F000AFF10F /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A38E77A91E3961F000AFF10F /* main.cpp */; }; + A307FE90202C077F009FFBF2 /* codegen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A307FE8E202C077E009FFBF2 /* codegen.cpp */; }; + A3081B0620301A4D00205DAB /* stdlib.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A3081B0420301A4D00205DAB /* stdlib.cpp */; }; + A38E77B11E39621900AFF10F /* lexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A38E77B01E39621900AFF10F /* lexer.cpp */; }; + A3C5D8EE1FF1C877000A4385 /* ast.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A3C5D8EC1FF1C877000A4385 /* ast.cpp */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -23,8 +26,16 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + A307FE8E202C077E009FFBF2 /* codegen.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = codegen.cpp; sourceTree = ""; }; + A307FE8F202C077F009FFBF2 /* codegen.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = codegen.hpp; sourceTree = ""; }; + A3081B03202FCA9500205DAB /* shared.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = shared.h; sourceTree = ""; }; + A3081B0420301A4D00205DAB /* stdlib.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = stdlib.cpp; sourceTree = ""; }; + A3081B0520301A4D00205DAB /* stdlib.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = stdlib.hpp; sourceTree = ""; }; + A32DD46F1E396FB7001EF2C0 /* lexer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lexer.h; sourceTree = ""; }; A38E77A61E3961F000AFF10F /* Kaleidoscope */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Kaleidoscope; sourceTree = BUILT_PRODUCTS_DIR; }; - A38E77A91E3961F000AFF10F /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + A38E77B01E39621900AFF10F /* lexer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = lexer.cpp; sourceTree = ""; }; + A3C5D8EC1FF1C877000A4385 /* ast.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ast.cpp; sourceTree = ""; }; + A3C5D8ED1FF1C877000A4385 /* ast.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ast.hpp; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -38,11 +49,19 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + A3081B0720301E6200205DAB /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; A38E779D1E3961EF00AFF10F = { isa = PBXGroup; children = ( A38E77A81E3961F000AFF10F /* Kaleidoscope */, A38E77A71E3961F000AFF10F /* Products */, + A3081B0720301E6200205DAB /* Frameworks */, ); sourceTree = ""; }; @@ -57,7 +76,15 @@ A38E77A81E3961F000AFF10F /* Kaleidoscope */ = { isa = PBXGroup; children = ( - A38E77A91E3961F000AFF10F /* main.cpp */, + A3081B0420301A4D00205DAB /* stdlib.cpp */, + A3081B0520301A4D00205DAB /* stdlib.hpp */, + A3081B03202FCA9500205DAB /* shared.h */, + A38E77B01E39621900AFF10F /* lexer.cpp */, + A32DD46F1E396FB7001EF2C0 /* lexer.h */, + A3C5D8EC1FF1C877000A4385 /* ast.cpp */, + A3C5D8ED1FF1C877000A4385 /* ast.hpp */, + A307FE8E202C077E009FFBF2 /* codegen.cpp */, + A307FE8F202C077F009FFBF2 /* codegen.hpp */, ); path = Kaleidoscope; sourceTree = ""; @@ -88,7 +115,7 @@ A38E779E1E3961EF00AFF10F /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0820; + LastUpgradeCheck = 0930; ORGANIZATIONNAME = "Luke Lau"; TargetAttributes = { A38E77A51E3961EF00AFF10F = { @@ -120,7 +147,10 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A38E77AA1E3961F000AFF10F /* main.cpp in Sources */, + A307FE90202C077F009FFBF2 /* codegen.cpp in Sources */, + A3081B0620301A4D00205DAB /* stdlib.cpp in Sources */, + A3C5D8EE1FF1C877000A4385 /* ast.cpp in Sources */, + A38E77B11E39621900AFF10F /* lexer.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -136,15 +166,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -183,15 +221,23 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -217,7 +263,24 @@ A38E77AE1E3961F000AFF10F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; DEVELOPMENT_TEAM = 7R888D749H; + HEADER_SEARCH_PATHS = /usr/local/opt/llvm/include; + LIBRARY_SEARCH_PATHS = ( + /usr/local/opt/llvm/lib, + /usr/local/Cellar/llvm/5.0.1/lib, + ); + OTHER_LDFLAGS = ( + "-lz", + "-ltermcap", + "-lc++", + "-lLLVMCore", + "-lLLVMSupport", + "-lLLVMTransformUtils", + "-lLLVMBitReader", + "-lLLVMAnalysis", + "-lLLVMDemangle", + ); PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -225,7 +288,24 @@ A38E77AF1E3961F000AFF10F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; DEVELOPMENT_TEAM = 7R888D749H; + HEADER_SEARCH_PATHS = /usr/local/opt/llvm/include; + LIBRARY_SEARCH_PATHS = ( + /usr/local/opt/llvm/lib, + /usr/local/Cellar/llvm/5.0.1/lib, + ); + OTHER_LDFLAGS = ( + "-lz", + "-ltermcap", + "-lc++", + "-lLLVMCore", + "-lLLVMSupport", + "-lLLVMTransformUtils", + "-lLLVMBitReader", + "-lLLVMAnalysis", + "-lLLVMDemangle", + ); PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -249,6 +329,7 @@ A38E77AF1E3961F000AFF10F /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Kaleidoscope.xcodeproj/xcuserdata/luke.xcuserdatad/xcschemes/Kaleidoscope.xcscheme b/Kaleidoscope.xcodeproj/xcuserdata/luke.xcuserdatad/xcschemes/Kaleidoscope.xcscheme index ce3e8d2..0042e64 100644 --- a/Kaleidoscope.xcodeproj/xcuserdata/luke.xcuserdatad/xcschemes/Kaleidoscope.xcscheme +++ b/Kaleidoscope.xcodeproj/xcuserdata/luke.xcuserdatad/xcschemes/Kaleidoscope.xcscheme @@ -1,6 +1,6 @@ LogError(const char *Str) { + fprintf(stderr, "LogError: %s\n", Str); + return nullptr; +} diff --git a/Kaleidoscope/ast.hpp b/Kaleidoscope/ast.hpp new file mode 100644 index 0000000..34a5225 --- /dev/null +++ b/Kaleidoscope/ast.hpp @@ -0,0 +1,79 @@ +#include +#include +#include "llvm/IR/Value.h" +#include "llvm/IR/Function.h" + +using namespace llvm; + +class ExprAST { +public: + virtual ~ExprAST() = default; + virtual Value *codegen() = 0; +}; + +class NumberExprAST: public ExprAST { + double Val; + +public: + NumberExprAST(double Val): Val(Val) {} + virtual Value *codegen(); +}; + +class VariableExprAST: public ExprAST { + std::string Name; + +public: + VariableExprAST(const std::string &Name): Name(Name) {} + virtual Value *codegen(); +}; + +class BinaryExprAST: public ExprAST { + char Op; + std::unique_ptr LHS, RHS; + +public: + BinaryExprAST(char op, std::unique_ptr LHS, + std::unique_ptr RHS) + : Op(op), LHS(std::move(LHS)), RHS(std::move(RHS)) {} + virtual Value *codegen(); +}; + +class CallExprAST: public ExprAST { + std::string Callee; + std::vector> Args; + +public: + CallExprAST(std::string &Callee, std::vector> Args) + : Callee(Callee), Args(std::move(Args)) {} + virtual Value *codegen(); +}; + +/* + Captures the prototype for a function + which is basically its name and arguments + */ +class PrototypeAST { + std::string Name; + std::vector Args; + +public: + virtual ~PrototypeAST() = default; + PrototypeAST(std::string Name, std::vector Args) + : Name(Name), Args(std::move(Args)) {} + + const std::string &getName() const { return Name; } + virtual Function *codegen(); +}; + +class FunctionAST { + std::unique_ptr Prototype; + std::unique_ptr Body; + +public: + virtual ~FunctionAST() = default; + FunctionAST(std::unique_ptr Prototype, std::unique_ptr Body) + : Prototype(std::move(Prototype)), Body(std::move(Body)) {} + virtual Function *codegen(); +}; + +std::unique_ptr LogError(const char *Str); diff --git a/Kaleidoscope/codegen.cpp b/Kaleidoscope/codegen.cpp new file mode 100644 index 0000000..c185a3e --- /dev/null +++ b/Kaleidoscope/codegen.cpp @@ -0,0 +1,156 @@ +#include +#include +#include +#include +#include +#include +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/Reassociate.h" +#include "llvm/Transforms/Scalar/GVN.h" +#include +#include +#include +#include +#include +#include +#include +#include "ast.hpp" +#include "codegen.hpp" +#include "shared.h" + +using namespace llvm; + +static LLVMContext TheContext; +static IRBuilder<> Builder(TheContext); +static AnalysisManager TheAM; +static std::map NamedValues; +static std::unique_ptr TheFPM; +static std::unique_ptr TheFAM; + +void InitializeModuleAndPassManager(void) { + TheModule = llvm::make_unique("Kaleidoscope jit", TheContext); + + TheFPM = make_unique(); + TheFAM = make_unique(); + + PassBuilder PB; + PB.registerFunctionAnalyses(*TheFAM); + + TheFPM->addPass(InstCombinePass()); + TheFPM->addPass(ReassociatePass()); + TheFPM->addPass(SimplifyCFGPass()); + TheFPM->addPass(GVNHoistPass()); + TheFPM->addPass(GVNSinkPass()); +} + +void PrintModule() { + TheModule->print(errs(), nullptr); +} + +std::map> functionProtos; + +Function *getFunction(std::string name) { + if (auto *func = TheModule->getFunction(name)) + return func; + + auto iterator = functionProtos.find(name); + if (iterator != functionProtos.end()) + return iterator->second->codegen(); + + return nullptr; +} + +Value *LogErrorV(const char *Str) { + LogError(Str); + return nullptr; +} + +Value *NumberExprAST::codegen() { + return ConstantFP::get(TheContext, APFloat(Val)); +} + +Value *VariableExprAST::codegen() { + Value *V = NamedValues[Name]; + if (!V) + LogErrorV("Unknown variable name"); + return V; +} + +Value *BinaryExprAST::codegen() { + Value *L = LHS->codegen(); + Value *R = RHS->codegen(); + + if (!L || !R) return nullptr; + + switch (Op) { + case '+': + return Builder.CreateFAdd(L, R, "addtmp"); + case '-': + return Builder.CreateFSub(L, R, "subtmp"); + case '*': + return Builder.CreateFMul(L, R, "multmp"); + case '<': + L = Builder.CreateFCmpULT(L, R, "cmptmp"); + // convert bool 0/1 to double 0.0/1.0 + return Builder.CreateUIToFP(L, Type::getDoubleTy(TheContext), "booltmp"); + default: + return LogErrorV("Invalid binary operator"); + } +} + +Value *CallExprAST::codegen() { + Function *CalleeF = getFunction(Callee); + if (!CalleeF) + return LogErrorV("Unknown function referenced"); + + if (CalleeF->arg_size() != Args.size()) + return LogErrorV("Incorrect number of arguments passed"); + + std::vector ArgsV; + for (unsigned long i = 0, e = Args.size(); i != e; ++i) { + ArgsV.push_back(Args[i]->codegen()); + if (!ArgsV.back()) return nullptr; + } + + return Builder.CreateCall(CalleeF, ArgsV, "calltmp"); +} + +Function *PrototypeAST::codegen() { + std::vector Doubles(Args.size(), Type::getDoubleTy(TheContext)); + + FunctionType *FT = FunctionType::get(Type::getDoubleTy(TheContext), Doubles, false); + Function *func = Function::Create(FT, Function::ExternalLinkage, Name, TheModule.get()); + + unsigned i = 0; + for (auto &arg : func->args()) + arg.setName(Args[i++]); + + return func; +} + +Function *FunctionAST::codegen() { + //Transfer ownership but keep a reference + auto &P = *Prototype; + functionProtos[Prototype->getName()] = std::move(Prototype); + + Function *func = getFunction(P.getName()); + + if (!func) return nullptr; + + BasicBlock *bb = BasicBlock::Create(TheContext, "entry", func); + Builder.SetInsertPoint(bb); + + NamedValues.clear(); + for (auto &arg: func->args()) + NamedValues[arg.getName()] = &arg; + + if (Value *retVal = Body->codegen()) { + Builder.CreateRet(retVal); + verifyFunction(*func); + TheFPM->run(*func, *TheFAM); + return func; + } + + func->eraseFromParent(); + return nullptr; +} diff --git a/Kaleidoscope/codegen.hpp b/Kaleidoscope/codegen.hpp new file mode 100644 index 0000000..300282a --- /dev/null +++ b/Kaleidoscope/codegen.hpp @@ -0,0 +1,7 @@ +#include + +void InitializeModuleAndPassManager(void); + +void PrintModule(); + +extern std::map> functionProtos; diff --git a/Kaleidoscope/lexer.cpp b/Kaleidoscope/lexer.cpp new file mode 100644 index 0000000..ac75490 --- /dev/null +++ b/Kaleidoscope/lexer.cpp @@ -0,0 +1,352 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//Needed to force linking interpreter +#include +#include "lexer.h" +#include "ast.hpp" +#include "codegen.hpp" +#include "shared.h" + +static std::unique_ptr ParseBinOpRHS(int ExprPrec, + std::unique_ptr LHS); +static std::unique_ptr ParseExpression(); + +static ExecutionEngine* TheEngine; + +std::unique_ptr TheModule; + +constexpr auto ANON_EXPR_FUNC_NAME = "__anon_expr"; + +enum Token { + tok_eof = -1, + + tok_def = -2, + tok_extern = -3, + + tok_identifier = -4, + tok_number = -5, +}; + +static std::string IdentifierStr; +static double NumVal; + +///Returns the next token from stdin +static int gettok() { + static int LastChar = ' '; + + while(isspace(LastChar)) + LastChar = getchar(); + + if(isalpha(LastChar)) { + IdentifierStr = LastChar; + while(isalnum((LastChar = getchar()))) + IdentifierStr += LastChar; + + if(IdentifierStr == "def") + return tok_def; + if(IdentifierStr == "extern") + return tok_extern; + return tok_identifier; + } + + if(isdigit(LastChar) || LastChar == '.') { + std::string NumStr; + do { + NumStr += LastChar; + LastChar = getchar(); + } while (isdigit(LastChar) || LastChar == '.'); + + NumVal = strtod(NumStr.c_str(), 0); + return tok_number; + } + + if(LastChar == '#') { + //Coment until the end of the line + do + LastChar = getchar(); + while(LastChar != EOF && LastChar != '\n' && LastChar != 'r'); + + if(LastChar != EOF) + return gettok(); + } + + //Check for end of file + if(LastChar == EOF) + return tok_eof; + + int ThisChar = LastChar; + LastChar = getchar(); + return ThisChar; +} + + +static int CurTok; +static int getNextToken() { + return CurTok = gettok(); +} + +std::unique_ptr LogErrorP(const char *Str) { + LogError(Str); + return nullptr; +} + +static std::unique_ptr ParseNumberExpr() { + auto Result = llvm::make_unique(NumVal); + getNextToken(); // consume the number + return std::move(Result); +} + +static std::unique_ptr ParseParenExpr() { + getNextToken(); + auto V = ParseExpression(); + if (!V) + return nullptr; + + if (CurTok != ')') + return LogError("expected ')'"); + getNextToken(); + return V; +} + +static std::unique_ptr ParseIdentifierExpr() { + std::string IdName = IdentifierStr; + + getNextToken(); + + if (CurTok != '(') + return llvm::make_unique(IdName); + + // call a function + getNextToken(); + std::vector> Args; + if (CurTok != ')') { + while (true) { + if (auto Arg = ParseExpression()) + Args.push_back(std::move(Arg)); + else + return nullptr; + + if (CurTok == ')') + break; + + if (CurTok != ',') + return LogError("Expected ')' or ',' in argument list"); + getNextToken(); + } + } + + getNextToken(); + return llvm::make_unique(IdName, std::move(Args)); +} + +static std::unique_ptr ParsePrimary() { + switch (CurTok) { + default: + return LogError("Unknown token when expected an expression"); + case tok_identifier: + return ParseIdentifierExpr(); + case tok_number: + return ParseNumberExpr(); + case '(': + return ParseParenExpr(); + } +} + +static std::map BinopPrecedence; + +static int GetTokPrecedence() { + if (!isascii(CurTok)) + return -1; + + int TokPrec = BinopPrecedence[CurTok]; + if (TokPrec <= 0) return -1; + return TokPrec; +} + +static std::unique_ptr ParseExpression() { + auto LHS = ParsePrimary(); + if (!LHS) + return nullptr; + return ParseBinOpRHS(0, std::move(LHS)); +} + +static std::unique_ptr ParseBinOpRHS(int ExprPrec, + std::unique_ptr LHS) { + while (true) { + int TokPrec = GetTokPrecedence(); + if (TokPrec < ExprPrec) + return LHS; + + int BinOp = CurTok; + getNextToken(); // eat binop + + auto RHS = ParsePrimary(); + if (!RHS) + return nullptr; + + int NextPrec = GetTokPrecedence(); + if (TokPrec < NextPrec) { + RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS)); + if (!RHS) + return nullptr; + } + + LHS = llvm::make_unique(BinOp, std::move(LHS), std::move(RHS)); + } +} + +static std::unique_ptr ParsePrototype() { + if (CurTok != tok_identifier) + return LogErrorP("Expected function name in prototype"); + + std::string FnName = IdentifierStr; + getNextToken(); + + if (CurTok != '(') + return LogErrorP("Expected '(' in prototype"); + + std::vector ArgNames; + while (getNextToken() == tok_identifier) + ArgNames.push_back(IdentifierStr); + if (CurTok != ')') + return LogErrorP("Expected ')' in prototype"); + + getNextToken(); // eat ')' + + return llvm::make_unique(FnName, std::move(ArgNames)); +} + +static std::unique_ptr ParseDefinition() { + getNextToken(); + auto Proto = ParsePrototype(); + if (!Proto) return nullptr; + + if (auto E = ParseExpression()) + return llvm::make_unique(std::move(Proto), std::move(E)); + return nullptr; +} + +static std::unique_ptr ParseExtern() { + getNextToken(); + return ParsePrototype(); +} + +static std::unique_ptr ParseTopLevelExpr() { + if (auto e = ParseExpression()) { + // make an anonymous prototype + auto proto = llvm::make_unique(ANON_EXPR_FUNC_NAME, std::vector()); + return llvm::make_unique(std::move(proto), std::move(e)); + } + return nullptr; +} + +static void HandleDefinition() { + if (auto def = ParseDefinition()) { + if (auto gen = def->codegen()) { + std::cerr << "Read function defintion:"; + gen->print(errs()); + std::cerr << "\n"; + + TheEngine->addModule(std::move(TheModule)); + InitializeModuleAndPassManager(); + } + } + else + getNextToken(); // skip token for error recovery +} + +static void HandleExtern() { + if (auto externProto = ParseExtern()) { + if (auto gen = externProto->codegen()) { + std::cerr << "Read an extern:\n"; + gen->print(errs()); + std::cerr << "\n"; + functionProtos[externProto->getName()] = std::move(externProto); + } + } + else + getNextToken(); // skip token for error recovery +} + +static void HandleTopLevelExpr() { + if (auto expr = ParseTopLevelExpr()) { + if (auto gen = expr->codegen()) { + gen->print(errs()); + + auto module = TheModule.get(); + TheEngine->addModule(std::move(TheModule)); + InitializeModuleAndPassManager(); + + auto func = TheEngine->FindFunctionNamed(ANON_EXPR_FUNC_NAME); + GenericValue gv = TheEngine->runFunction(func, std::vector()); + std::cerr << "Evaluated to " << std::fixed << std::setw(5) << gv.DoubleVal << std::endl; + + TheEngine->removeModule(module); + } + } + else + getNextToken(); // skip token for error recovery +} + +void mainLoop() { + while (true) { + fprintf(stderr, "ready> "); + switch(CurTok) { + case tok_eof: + return; + case ';': + getNextToken(); + break; + case tok_def: + HandleDefinition(); + break; + case tok_extern: + HandleExtern(); + break; + default: + HandleTopLevelExpr(); + break; + } + } +} + +int main() { + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + InitializeNativeTargetAsmParser(); + + BinopPrecedence['<'] = 10; + BinopPrecedence['+'] = 20; + BinopPrecedence['-'] = 20; + BinopPrecedence['*'] = 40; + + InitializeModuleAndPassManager(); + + std::string engineError; + TheEngine = EngineBuilder(std::move(TheModule)).setErrorStr(&engineError).create(); + if (!engineError.empty()) + std::cout << engineError << "\n"; + + InitializeModuleAndPassManager(); + + // prime the first token + std::cerr << "ready> "; + getNextToken(); + + mainLoop(); + + PrintModule(); + + + return 0; +} diff --git a/Kaleidoscope/lexer.h b/Kaleidoscope/lexer.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Kaleidoscope/lexer.h @@ -0,0 +1 @@ + diff --git a/Kaleidoscope/main.cpp b/Kaleidoscope/main.cpp deleted file mode 100644 index 1e6814a..0000000 --- a/Kaleidoscope/main.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// -// main.cpp -// Kaleidoscope -// -// Created by Luke Lau on 25/01/2017. -// Copyright © 2017 Luke Lau. All rights reserved. -// - -#include - -int main(int argc, const char * argv[]) { - // insert code here... - std::cout << "Hello, World!\n"; - return 0; -} diff --git a/Kaleidoscope/makefile b/Kaleidoscope/makefile new file mode 100644 index 0000000..aee7f4b --- /dev/null +++ b/Kaleidoscope/makefile @@ -0,0 +1,2 @@ +all: + clang++ -g `llvm-config --cxxflags --ldflags --system-libs --libs core mcjit native passes interpreter` -o bin/kaleidoscope *.cpp diff --git a/Kaleidoscope/shared.h b/Kaleidoscope/shared.h new file mode 100644 index 0000000..b92baf0 --- /dev/null +++ b/Kaleidoscope/shared.h @@ -0,0 +1,14 @@ +// +// shared.h +// Kaleidoscope +// +// Created by Luke Lau on 10/02/2018. +// Copyright © 2018 Luke Lau. All rights reserved. +// + +#ifndef shared_h +#define shared_h + +extern std::unique_ptr TheModule; + +#endif /* shared_h */ diff --git a/Kaleidoscope/stdlib.cpp b/Kaleidoscope/stdlib.cpp new file mode 100644 index 0000000..08ccfd8 --- /dev/null +++ b/Kaleidoscope/stdlib.cpp @@ -0,0 +1,20 @@ +// +// stdlib.cpp +// Kaleidoscope +// +// Created by Luke Lau on 11/02/2018. +// Copyright © 2018 Luke Lau. All rights reserved. +// + +#include "stdlib.hpp" + +#ifdef LLVM_ON_WIN32 +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + +extern "C" DLLEXPORT double putchard(double X) { + fputc((char)X, stderr); + return 0; +} diff --git a/Kaleidoscope/stdlib.hpp b/Kaleidoscope/stdlib.hpp new file mode 100644 index 0000000..012512c --- /dev/null +++ b/Kaleidoscope/stdlib.hpp @@ -0,0 +1,14 @@ +// +// stdlib.hpp +// Kaleidoscope +// +// Created by Luke Lau on 11/02/2018. +// Copyright © 2018 Luke Lau. All rights reserved. +// + +#ifndef stdlib_hpp +#define stdlib_hpp + +#include + +#endif /* stdlib_hpp */