elna/source/elna/backend.d

98 lines
2.6 KiB
D

module elna.backend;
import core.stdc.stdio;
import elna.elf;
import elna.ir;
import elna.extended;
import elna.riscv;
import elna.lexer;
import elna.parser;
import elna.result;
import std.algorithm;
import std.sumtype;
import std.typecons;
import tanya.os.error;
import tanya.container.array;
import tanya.container.string;
private Nullable!String readSource(string source) @nogc
{
enum size_t bufferSize = 255;
auto sourceFilename = String(source);
return readFile(sourceFilename).match!(
(ErrorCode errorCode) {
perror(sourceFilename.toStringz);
return Nullable!String();
},
(Array!ubyte contents) => nullable(String(cast(char[]) contents.get))
);
}
int generate(string inFile, ref String outputFilename) @nogc
{
auto sourceText = readSource(inFile);
if (sourceText.isNull)
{
return 3;
}
auto tokens = lex(sourceText.get.get);
if (!tokens.valid)
{
auto compileError = tokens.error.get;
printf("%lu:%lu: %s\n", compileError.line, compileError.column, compileError.message.ptr);
return 1;
}
auto ast = parse(tokens.result);
if (!ast.valid)
{
auto compileError = ast.error.get;
printf("%lu:%lu: %s\n", compileError.line, compileError.column, compileError.message.ptr);
return 2;
}
auto ir = transform(ast.result);
auto handle = File.open(outputFilename.toStringz, BitFlags!(File.Mode)(File.Mode.truncate));
if (!handle.valid)
{
return 1;
}
auto program = writeNext(ir);
auto elf = Elf!ELFCLASS32(move(handle));
auto readOnlyData = Array!ubyte(cast(const(ubyte)[]) "%d\n".ptr[0 .. 4]); // With \0.
elf.addReadOnlyData(String(".CL0"), readOnlyData);
elf.addCode(program.name, program.text);
elf.addExternSymbol(String("printf"));
foreach (ref reference; program.symbols)
{
elf.Rela relocationEntry = {
r_offset: cast(elf.Addr) reference.offset
};
elf.Rela relocationSub = {
r_offset: cast(elf.Addr) reference.offset,
r_info: R_RISCV_RELAX
};
final switch (reference.target)
{
case Reference.Target.text:
relocationEntry.r_info = R_RISCV_CALL;
break;
case Reference.Target.high20:
relocationEntry.r_info = R_RISCV_HI20;
break;
case Reference.Target.lower12i:
relocationEntry.r_info = R_RISCV_LO12_I;
break;
}
elf.relocate(reference.name, relocationEntry, relocationSub);
}
elf.finish();
return 0;
}