/** * lisp-compiler: Compiles LISP using LLVM. * Copyright (C) 2022 Clyne Sullivan * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see . * * @file main.cpp * @brief Program entry point. */ /* Current support: - Literals: - Integer - Double (when decimal point is found) - (define name value) - (set! defined-name new-value) - (lambda (...) ...) - (if cond then else) - Calling procedures: - Defined lambdas - Built-in things - Undefined procedures are prototyped TODO: - Error reporting! - Documentation! - Arithmetic - String literals? - Typed definitions... - See R7RS-small for more... */ #include "llvm/ADT/STLExtras.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Function.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Type.h" #include "llvm/IR/Verifier.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include #include #include "ast.hpp" #include "parser.hpp" #include "state.hpp" void compileToObjectFile(CompilerState&); int main(int argc, const char *argv[]) { CompilerState state; Parser parser; for (int i = 1; i < argc; ++i) parser.addString(argv[i]); auto functype = llvm::FunctionType::get(llvm::Type::getInt32Ty(state.context), {}, false); auto func = llvm::Function::Create(functype, llvm::Function::ExternalLinkage, "main", &state.module); auto block = llvm::BasicBlock::Create(state.context, "entry", func); state.builder.SetInsertPoint(block); auto astTree = parser.parse(); if (parser.hasErrors()) { auto err = parser.describeErrors(); std::cout << "Error: " << std::endl << err << std::endl; } else if (!astTree.empty()) { for (auto& node : astTree) { std::cout << node->desc() << std::endl; node->codegen(state); } state.builder.CreateRet(state.builder.getInt32(0)); std::cout << std::endl; state.module.print(llvm::errs(), nullptr); // prints everything compileToObjectFile(state); } else { std::cout << "Nothing to do." << std::endl; } return 0; } void compileToObjectFile(CompilerState& state) { llvm::InitializeAllTargetInfos(); llvm::InitializeAllTargets(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmParsers(); llvm::InitializeAllAsmPrinters(); auto TargetTriple = "x86_64-pc-linux-gnu"; std::string error; auto Target = llvm::TargetRegistry::lookupTarget(TargetTriple, error); if (!error.empty()) puts(error.c_str()); auto CPU = "generic"; auto Features = ""; llvm::TargetOptions opt; auto RM = llvm::Optional(); auto TargetMachine = Target->createTargetMachine(TargetTriple, CPU, Features, opt, RM); std::error_code EC; llvm::raw_fd_ostream dest ("out.o", EC, llvm::sys::fs::OF_None); llvm::legacy::PassManager pass; if (TargetMachine->addPassesToEmitFile(pass, dest, nullptr, llvm::CGFT_ObjectFile)) { llvm::errs() << "TargetMachine can't emit a file of this type"; } else { pass.run(state.module); dest.flush(); } }