|
@@ -0,0 +1,399 @@
|
|
|
+#include "llvm/ADT/STLExtras.h"
|
|
|
+#include "llvm/IR/IRBuilder.h"
|
|
|
+#include "llvm/IR/LLVMContext.h"
|
|
|
+#include "llvm/IR/Module.h"
|
|
|
+#include "llvm/IR/Verifier.h"
|
|
|
+#include <cctype>
|
|
|
+#include <cstdio>
|
|
|
+#include <map>
|
|
|
+#include <string>
|
|
|
+#include <vector>
|
|
|
+#include "Ast.h"
|
|
|
+
|
|
|
+using namespace llvm;
|
|
|
+using namespace ast;
|
|
|
+
|
|
|
+
|
|
|
+namespace helper {
|
|
|
+// Cloning make_unique here until it's standard in C++14.
|
|
|
+// Using a namespace to avoid conflicting with MSVC's std::make_unique (which
|
|
|
+// ADL can sometimes find in unqualified calls).
|
|
|
+template <class T, class... Args>
|
|
|
+static
|
|
|
+ typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
|
|
|
+ make_unique(Args &&... args) {
|
|
|
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
|
|
+}
|
|
|
+}
|
|
|
+
|
|
|
+//===----------------------------------------------------------------------===//
|
|
|
+// Lexer
|
|
|
+//===----------------------------------------------------------------------===//
|
|
|
+
|
|
|
+// The lexer returns tokens [0-255] if it is an unknown character, otherwise one
|
|
|
+// of these for known things.
|
|
|
+enum Token {
|
|
|
+ tok_eof = -1,
|
|
|
+
|
|
|
+ // commands
|
|
|
+ tok_def = -2,
|
|
|
+ tok_extern = -3,
|
|
|
+
|
|
|
+ // primary
|
|
|
+ tok_identifier = -4,
|
|
|
+ tok_number = -5
|
|
|
+};
|
|
|
+
|
|
|
+static std::string IdentifierStr; // Filled in if tok_identifier
|
|
|
+static double NumVal; // Filled in if tok_number
|
|
|
+
|
|
|
+/// gettok - Return the next token from standard input.
|
|
|
+static int gettok() {
|
|
|
+ static int LastChar = ' ';
|
|
|
+
|
|
|
+ // Skip any whitespace.
|
|
|
+ while (isspace(LastChar))
|
|
|
+ LastChar = getchar();
|
|
|
+
|
|
|
+ if (isalpha(LastChar)) { // identifier: [a-zA-Z][a-zA-Z0-9]*
|
|
|
+ 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 == '.') { // Number: [0-9.]+
|
|
|
+ std::string NumStr;
|
|
|
+ do {
|
|
|
+ NumStr += LastChar;
|
|
|
+ LastChar = getchar();
|
|
|
+ } while (isdigit(LastChar) || LastChar == '.');
|
|
|
+
|
|
|
+ NumVal = strtod(NumStr.c_str(), nullptr);
|
|
|
+ return tok_number;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (LastChar == '#') {
|
|
|
+ // Comment until end of line.
|
|
|
+ do
|
|
|
+ LastChar = getchar();
|
|
|
+ while (LastChar != EOF && LastChar != '\n' && LastChar != '\r');
|
|
|
+
|
|
|
+ if (LastChar != EOF)
|
|
|
+ return gettok();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check for end of file. Don't eat the EOF.
|
|
|
+ if (LastChar == EOF)
|
|
|
+ return tok_eof;
|
|
|
+
|
|
|
+ // Otherwise, just return the character as its ascii value.
|
|
|
+ int ThisChar = LastChar;
|
|
|
+ LastChar = getchar();
|
|
|
+ return ThisChar;
|
|
|
+}
|
|
|
+
|
|
|
+//===----------------------------------------------------------------------===//
|
|
|
+// Parser
|
|
|
+//===----------------------------------------------------------------------===//
|
|
|
+
|
|
|
+/// CurTok/getNextToken - Provide a simple token buffer. CurTok is the current
|
|
|
+/// token the parser is looking at. getNextToken reads another token from the
|
|
|
+/// lexer and updates CurTok with its results.
|
|
|
+static int CurTok;
|
|
|
+static int getNextToken() { return CurTok = gettok(); }
|
|
|
+
|
|
|
+/// BinopPrecedence - This holds the precedence for each binary operator that is
|
|
|
+/// defined.
|
|
|
+static std::map<char, int> BinopPrecedence;
|
|
|
+
|
|
|
+/// GetTokPrecedence - Get the precedence of the pending binary operator token.
|
|
|
+static int GetTokPrecedence() {
|
|
|
+ if (!isascii(CurTok))
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ // Make sure it's a declared binop.
|
|
|
+ int TokPrec = BinopPrecedence[CurTok];
|
|
|
+ if (TokPrec <= 0)
|
|
|
+ return -1;
|
|
|
+ return TokPrec;
|
|
|
+}
|
|
|
+
|
|
|
+/// Error* - These are little helper functions for error handling.
|
|
|
+std::unique_ptr<ExprAST> Error(const char *Str) {
|
|
|
+ fprintf(stderr, "Error: %s\n", Str);
|
|
|
+ return nullptr;
|
|
|
+}
|
|
|
+std::unique_ptr<PrototypeAST> ErrorP(const char *Str) {
|
|
|
+ Error(Str);
|
|
|
+ return nullptr;
|
|
|
+}
|
|
|
+
|
|
|
+static std::unique_ptr<ExprAST> ParseExpression();
|
|
|
+
|
|
|
+/// numberexpr ::= number
|
|
|
+static std::unique_ptr<ExprAST> ParseNumberExpr() {
|
|
|
+ auto Result = helper::make_unique<NumberExprAST>(NumVal);
|
|
|
+ getNextToken(); // consume the number
|
|
|
+ return std::move(Result);
|
|
|
+}
|
|
|
+
|
|
|
+/// parenexpr ::= '(' expression ')'
|
|
|
+static std::unique_ptr<ExprAST> ParseParenExpr() {
|
|
|
+ getNextToken(); // eat (.
|
|
|
+ auto V = ParseExpression();
|
|
|
+ if (!V)
|
|
|
+ return nullptr;
|
|
|
+
|
|
|
+ if (CurTok != ')')
|
|
|
+ return Error("expected ')'");
|
|
|
+ getNextToken(); // eat ).
|
|
|
+ return V;
|
|
|
+}
|
|
|
+
|
|
|
+/// identifierexpr
|
|
|
+/// ::= identifier
|
|
|
+/// ::= identifier '(' expression* ')'
|
|
|
+static std::unique_ptr<ExprAST> ParseIdentifierExpr() {
|
|
|
+ std::string IdName = IdentifierStr;
|
|
|
+
|
|
|
+ getNextToken(); // eat identifier.
|
|
|
+
|
|
|
+ if (CurTok != '(') // Simple variable ref.
|
|
|
+ return helper::make_unique<VariableExprAST>(IdName);
|
|
|
+
|
|
|
+ // Call.
|
|
|
+ getNextToken(); // eat (
|
|
|
+ std::vector<std::unique_ptr<ExprAST>> Args;
|
|
|
+ if (CurTok != ')') {
|
|
|
+ while (1) {
|
|
|
+ if (auto Arg = ParseExpression())
|
|
|
+ Args.push_back(std::move(Arg));
|
|
|
+ else
|
|
|
+ return nullptr;
|
|
|
+
|
|
|
+ if (CurTok == ')')
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (CurTok != ',')
|
|
|
+ return Error("Expected ')' or ',' in argument list");
|
|
|
+ getNextToken();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Eat the ')'.
|
|
|
+ getNextToken();
|
|
|
+
|
|
|
+ return helper::make_unique<CallExprAST>(IdName, std::move(Args));
|
|
|
+}
|
|
|
+
|
|
|
+/// primary
|
|
|
+/// ::= identifierexpr
|
|
|
+/// ::= numberexpr
|
|
|
+/// ::= parenexpr
|
|
|
+static std::unique_ptr<ExprAST> ParsePrimary() {
|
|
|
+ switch (CurTok) {
|
|
|
+ default:
|
|
|
+ return Error("unknown token when expecting an expression");
|
|
|
+ case tok_identifier:
|
|
|
+ return ParseIdentifierExpr();
|
|
|
+ case tok_number:
|
|
|
+ return ParseNumberExpr();
|
|
|
+ case '(':
|
|
|
+ return ParseParenExpr();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// binoprhs
|
|
|
+/// ::= ('+' primary)*
|
|
|
+static std::unique_ptr<ExprAST> ParseBinOpRHS(int ExprPrec,
|
|
|
+ std::unique_ptr<ExprAST> LHS) {
|
|
|
+ // If this is a binop, find its precedence.
|
|
|
+ while (1) {
|
|
|
+ int TokPrec = GetTokPrecedence();
|
|
|
+
|
|
|
+ // If this is a binop that binds at least as tightly as the current binop,
|
|
|
+ // consume it, otherwise we are done.
|
|
|
+ if (TokPrec < ExprPrec)
|
|
|
+ return LHS;
|
|
|
+
|
|
|
+ // Okay, we know this is a binop.
|
|
|
+ int BinOp = CurTok;
|
|
|
+ getNextToken(); // eat binop
|
|
|
+
|
|
|
+ // Parse the primary expression after the binary operator.
|
|
|
+ auto RHS = ParsePrimary();
|
|
|
+ if (!RHS)
|
|
|
+ return nullptr;
|
|
|
+
|
|
|
+ // If BinOp binds less tightly with RHS than the operator after RHS, let
|
|
|
+ // the pending operator take RHS as its LHS.
|
|
|
+ int NextPrec = GetTokPrecedence();
|
|
|
+ if (TokPrec < NextPrec) {
|
|
|
+ RHS = ParseBinOpRHS(TokPrec + 1, std::move(RHS));
|
|
|
+ if (!RHS)
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Merge LHS/RHS.
|
|
|
+ LHS = helper::make_unique<BinaryExprAST>(BinOp, std::move(LHS),
|
|
|
+ std::move(RHS));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// expression
|
|
|
+/// ::= primary binoprhs
|
|
|
+///
|
|
|
+static std::unique_ptr<ExprAST> ParseExpression() {
|
|
|
+ auto LHS = ParsePrimary();
|
|
|
+ if (!LHS)
|
|
|
+ return nullptr;
|
|
|
+
|
|
|
+ return ParseBinOpRHS(0, std::move(LHS));
|
|
|
+}
|
|
|
+
|
|
|
+/// prototype
|
|
|
+/// ::= id '(' id* ')'
|
|
|
+static std::unique_ptr<PrototypeAST> ParsePrototype() {
|
|
|
+ if (CurTok != tok_identifier)
|
|
|
+ return ErrorP("Expected function name in prototype");
|
|
|
+
|
|
|
+ std::string FnName = IdentifierStr;
|
|
|
+ getNextToken();
|
|
|
+
|
|
|
+ if (CurTok != '(')
|
|
|
+ return ErrorP("Expected '(' in prototype");
|
|
|
+
|
|
|
+ std::vector<std::string> ArgNames;
|
|
|
+ while (getNextToken() == tok_identifier)
|
|
|
+ ArgNames.push_back(IdentifierStr);
|
|
|
+ if (CurTok != ')')
|
|
|
+ return ErrorP("Expected ')' in prototype");
|
|
|
+
|
|
|
+ // success.
|
|
|
+ getNextToken(); // eat ')'.
|
|
|
+
|
|
|
+ return helper::make_unique<PrototypeAST>(FnName, std::move(ArgNames));
|
|
|
+}
|
|
|
+
|
|
|
+/// definition ::= 'def' prototype expression
|
|
|
+static std::unique_ptr<FunctionAST> ParseDefinition() {
|
|
|
+ getNextToken(); // eat def.
|
|
|
+ auto Proto = ParsePrototype();
|
|
|
+ if (!Proto)
|
|
|
+ return nullptr;
|
|
|
+
|
|
|
+ if (auto E = ParseExpression())
|
|
|
+ return helper::make_unique<FunctionAST>(std::move(Proto), std::move(E));
|
|
|
+ return nullptr;
|
|
|
+}
|
|
|
+
|
|
|
+/// toplevelexpr ::= expression
|
|
|
+static std::unique_ptr<FunctionAST> ParseTopLevelExpr() {
|
|
|
+ if (auto E = ParseExpression()) {
|
|
|
+ // Make an anonymous proto.
|
|
|
+ auto Proto = helper::make_unique<PrototypeAST>("__anon_expr",
|
|
|
+ std::vector<std::string>());
|
|
|
+ return helper::make_unique<FunctionAST>(std::move(Proto), std::move(E));
|
|
|
+ }
|
|
|
+ return nullptr;
|
|
|
+}
|
|
|
+
|
|
|
+/// external ::= 'extern' prototype
|
|
|
+static std::unique_ptr<PrototypeAST> ParseExtern() {
|
|
|
+ getNextToken(); // eat extern.
|
|
|
+ return ParsePrototype();
|
|
|
+}
|
|
|
+
|
|
|
+//===----------------------------------------------------------------------===//
|
|
|
+// Top-Level parsing
|
|
|
+//===----------------------------------------------------------------------===//
|
|
|
+
|
|
|
+static void HandleDefinition() {
|
|
|
+ if (auto FnAST = ParseDefinition()) {
|
|
|
+ if (auto *FnIR = FnAST->codegen()) {
|
|
|
+ fprintf(stderr, "Read function definition:");
|
|
|
+ FnIR->dump();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // Skip token for error recovery.
|
|
|
+ getNextToken();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void HandleExtern() {
|
|
|
+ if (auto ProtoAST = ParseExtern()) {
|
|
|
+ if (auto *FnIR = ProtoAST->codegen()) {
|
|
|
+ fprintf(stderr, "Read extern: ");
|
|
|
+ FnIR->dump();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // Skip token for error recovery.
|
|
|
+ getNextToken();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void HandleTopLevelExpression() {
|
|
|
+ // Evaluate a top-level expression into an anonymous function.
|
|
|
+ if (auto FnAST = ParseTopLevelExpr()) {
|
|
|
+ if (auto *FnIR = FnAST->codegen()) {
|
|
|
+ fprintf(stderr, "Read top-level expression:");
|
|
|
+ FnIR->dump();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // Skip token for error recovery.
|
|
|
+ getNextToken();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/// top ::= definition | external | expression | ';'
|
|
|
+static void MainLoop() {
|
|
|
+ while (1) {
|
|
|
+ fprintf(stderr, "ready> ");
|
|
|
+ switch (CurTok) {
|
|
|
+ case tok_eof:
|
|
|
+ return;
|
|
|
+ case ';': // ignore top-level semicolons.
|
|
|
+ getNextToken();
|
|
|
+ break;
|
|
|
+ case tok_def:
|
|
|
+ HandleDefinition();
|
|
|
+ break;
|
|
|
+ case tok_extern:
|
|
|
+ HandleExtern();
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ HandleTopLevelExpression();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//===----------------------------------------------------------------------===//
|
|
|
+// Main driver code.
|
|
|
+//===----------------------------------------------------------------------===//
|
|
|
+
|
|
|
+int main() {
|
|
|
+ // Install standard binary operators.
|
|
|
+ // 1 is lowest precedence.
|
|
|
+ BinopPrecedence['<'] = 10;
|
|
|
+ BinopPrecedence['+'] = 20;
|
|
|
+ BinopPrecedence['-'] = 20;
|
|
|
+ BinopPrecedence['*'] = 40; // highest.
|
|
|
+
|
|
|
+ // Prime the first token.
|
|
|
+ fprintf(stderr, "ready> ");
|
|
|
+ getNextToken();
|
|
|
+
|
|
|
+ // Run the main "interpreter loop" now.
|
|
|
+ MainLoop();
|
|
|
+
|
|
|
+ AstTree::TheModule->dump();
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|