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++

/**
* 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();
}
}