|
@@ -1,399 +0,0 @@
|
|
|
-#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;
|
|
|
-}
|