X-Git-Url: http://git.lukelau.me/?p=kaleidoscope.git;a=blobdiff_plain;f=Kaleidoscope%2Flexer.cpp;fp=Kaleidoscope%2Flexer.cpp;h=ac75490ff45d8c343200b0e3a4da55bbbadc7b08;hp=0000000000000000000000000000000000000000;hb=5f81038886345b9c1e130bc7cfdd463e76b37b84;hpb=400fd8ffcac74658d4323ba0b6f3519204075baa 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; +}