You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
3.9 KiB
C++
141 lines
3.9 KiB
C++
/**
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
* @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 <iostream>
|
|
#include <string>
|
|
|
|
#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<llvm::Reloc::Model>();
|
|
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();
|
|
}
|
|
}
|
|
|