From 4ac29669ad368ff3d42faeb4c95166242159c81e Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Thu, 7 Mar 2024 09:15:11 +0100 Subject: [PATCH] Split code generation from the ui --- CMakeLists.txt | 19 +-- TODO | 14 +-- {source => backend}/riscv.cpp | 144 +++++++++-------------- source/cl.cpp => backend/target.cpp | 73 +++--------- cli/cl.cpp | 52 ++++++++ {source => cli}/main.cpp | 4 +- include/elna/{ => backend}/riscv.hpp | 28 +++-- include/elna/backend/target.hpp | 7 ++ include/elna/{ => cli}/cl.hpp | 2 +- include/elna/result.hpp | 112 ------------------ include/elna/{ => shell}/history.hpp | 0 include/elna/{ => shell}/interactive.hpp | 4 +- include/elna/{ => shell}/state.hpp | 0 include/elna/{ => source}/ir.hpp | 4 +- include/elna/source/lexer.hpp | 9 +- include/elna/source/parser.hpp | 13 +- include/elna/source/result.hpp | 86 ++++++++++++++ shell/history.cpp | 2 +- shell/interactive.cpp | 2 +- shell/main.cpp | 2 +- shell/state.cpp | 2 +- source/ir.cpp | 6 +- source/lexer.cpp | 5 +- source/parser.cpp | 13 +- source/result.cpp | 12 +- tests/{runner.cpp => tester.cpp} | 0 26 files changed, 279 insertions(+), 336 deletions(-) rename {source => backend}/riscv.cpp (54%) rename source/cl.cpp => backend/target.cpp (53%) create mode 100644 cli/cl.cpp rename {source => cli}/main.cpp (94%) rename include/elna/{ => backend}/riscv.hpp (89%) create mode 100644 include/elna/backend/target.hpp rename include/elna/{ => cli}/cl.hpp (89%) delete mode 100644 include/elna/result.hpp rename include/elna/{ => shell}/history.hpp (100%) rename include/elna/{ => shell}/interactive.hpp (96%) rename include/elna/{ => shell}/state.hpp (100%) rename include/elna/{ => source}/ir.hpp (82%) create mode 100644 include/elna/source/result.hpp rename tests/{runner.cpp => tester.cpp} (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 22d3555..fb8a8ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,23 +8,24 @@ set(CMAKE_CXX_STANDARD 17) find_package(Boost COMPONENTS program_options REQUIRED) include_directories(${Boost_INCLUDE_DIR}) -add_executable(tester tests/runner.cpp include/elna/tester.hpp) +add_executable(tester tests/tester.cpp include/elna/tester.hpp) target_include_directories(tester PRIVATE include) add_executable(elnsh shell/main.cpp - shell/interactive.cpp include/elna/interactive.hpp - shell/history.cpp include/elna/history.hpp - shell/state.cpp include/elna/state.hpp + shell/interactive.cpp include/elna/shell/interactive.hpp + shell/history.cpp include/elna/shell/history.hpp + shell/state.cpp include/elna/shell/state.hpp ) target_include_directories(elnsh PRIVATE include) -add_executable(elna source/main.cpp +add_executable(elna cli/main.cpp source/lexer.cpp include/elna/source/lexer.hpp source/parser.cpp include/elna/source/parser.hpp - source/result.cpp include/elna/result.hpp - source/riscv.cpp include/elna/riscv.hpp - source/ir.cpp include/elna/ir.hpp - source/cl.cpp include/elna/cl.hpp + source/result.cpp include/elna/source/result.hpp + source/ir.cpp include/elna/source/ir.hpp + backend/riscv.cpp include/elna/backend/riscv.hpp + backend/target.cpp include/elna/backend/target.hpp + cli/cl.cpp include/elna/cli/cl.hpp ) target_include_directories(elna PRIVATE include) target_link_libraries(elna LINK_PUBLIC ${Boost_LIBRARIES}) diff --git a/TODO b/TODO index fb7f24e..e331d1e 100644 --- a/TODO +++ b/TODO @@ -4,14 +4,15 @@ - Make writing ELF independent from the code generation. - Argument parsing. - Whitespaces are checked twice, in the source class and by lexing. -- Replace pointer and length with vectors and strings. -- Choose one name for runner.cpp and tester.hpp. -- Move argument handling into the cl module. - Catch exceptions thrown by the argument parser and print them normally. -- cmake clean target. - Division. - Expressions contain one or more terms. Currently it parses another expression on the right side. - Multiple factors. +- Put riscv code into the backend namespace. +- Rename riscv backend structs to be snake case. +- Make reference and Target be nested types of the visitor. +- Rename visitors to snake case. +- The backend visitor seems to generate code before the prologue. # Shell - Persist the history. @@ -30,8 +31,3 @@ - Add a bar with additional information under the prompt (edit_bar), like the hostname. - Show current time in the prompt. - -## Input - -- DEL handling. -- Starting long running process and killing it with Ctrl-C kills the shell. diff --git a/source/riscv.cpp b/backend/riscv.cpp similarity index 54% rename from source/riscv.cpp rename to backend/riscv.cpp index 13b79b1..84c5353 100644 --- a/source/riscv.cpp +++ b/backend/riscv.cpp @@ -1,8 +1,7 @@ -#include "elna/riscv.hpp" +#include "elna/backend/riscv.hpp" #include -#include -namespace elna +namespace elna::backend { Instruction::Instruction(BaseOpcode opcode) { @@ -48,14 +47,14 @@ namespace elna return *this; } - const std::byte *Instruction::cbegin() + const std::byte *Instruction::cbegin() const { - return reinterpret_cast(&this->instruction); + return reinterpret_cast(&this->instruction); } - const std::byte *Instruction::cend() + const std::byte *Instruction::cend() const { - return reinterpret_cast(&this->instruction) + sizeof(this->instruction); + return reinterpret_cast(&this->instruction) + sizeof(this->instruction); } void RiscVVisitor::visit(source::definition *definition) @@ -69,62 +68,55 @@ namespace elna { block_definition->accept(this); } - this->instructionsLength += 4; - this->instructions = reinterpret_cast( - realloc(this->instructions, this->instructionsLength * sizeof(Instruction))); - block->body().accept(this); // Prologue. const uint stackSize = static_cast(variableCounter * 4 + 12); - this->instructions[0] = Instruction(BaseOpcode::opImm) - .i(XRegister::sp, Funct3::addi, XRegister::sp, -stackSize); - this->instructions[1] = Instruction(BaseOpcode::store) - .s(stackSize - 4, Funct3::sw, XRegister::sp, XRegister::s0); - this->instructions[2] = Instruction(BaseOpcode::store) - .s(stackSize - 8, Funct3::sw, XRegister::sp, XRegister::ra); - this->instructions[3] = Instruction(BaseOpcode::opImm) - .i(XRegister::s0, Funct3::addi, XRegister::sp, stackSize); - - this->instructions = reinterpret_cast( - realloc(this->instructions, (this->instructionsLength + 10) * sizeof(Instruction))); + this->instructions.push_back(Instruction(BaseOpcode::opImm) + .i(XRegister::sp, Funct3::addi, XRegister::sp, -stackSize)); + this->instructions.push_back(Instruction(BaseOpcode::store) + .s(stackSize - 4, Funct3::sw, XRegister::sp, XRegister::s0)); + this->instructions.push_back(Instruction(BaseOpcode::store) + .s(stackSize - 8, Funct3::sw, XRegister::sp, XRegister::ra)); + this->instructions.push_back(Instruction(BaseOpcode::opImm) + .i(XRegister::s0, Funct3::addi, XRegister::sp, stackSize)); // Print the result. - this->instructions[instructionsLength++] = Instruction(BaseOpcode::opImm) - .i(XRegister::a1, Funct3::addi, XRegister::a0, 0); + this->instructions.push_back(Instruction(BaseOpcode::opImm) + .i(XRegister::a1, Funct3::addi, XRegister::a0, 0)); this->references[0] = Reference(); this->references[0].name = ".CL0"; - this->references[0].offset = instructionsLength * 4; + this->references[0].offset = instructions.size() * 4; this->references[0].target = Target::high20; - this->instructions[instructionsLength++] = Instruction(BaseOpcode::lui).u(XRegister::a5, 0); + this->instructions.push_back(Instruction(BaseOpcode::lui).u(XRegister::a5, 0)); this->references[1] = Reference(); this->references[1].name = ".CL0"; - this->references[1].offset = instructionsLength * 4; + this->references[1].offset = instructions.size() * 4; this->references[1].target = Target::lower12i; - this->instructions[instructionsLength++] = Instruction(BaseOpcode::opImm) - .i(XRegister::a0, Funct3::addi, XRegister::a5, 0); + this->instructions.push_back(Instruction(BaseOpcode::opImm) + .i(XRegister::a0, Funct3::addi, XRegister::a5, 0)); this->references[2] = Reference(); this->references[2].name = "printf"; - this->references[2].offset = instructionsLength * 4; + this->references[2].offset = instructions.size() * 4; this->references[2].target = Target::text; - this->instructions[instructionsLength++] = Instruction(BaseOpcode::auipc).u(XRegister::ra, 0); - this->instructions[instructionsLength++] = Instruction(BaseOpcode::jalr) - .i(XRegister::ra, Funct3::jalr, XRegister::ra, 0); + this->instructions.push_back(Instruction(BaseOpcode::auipc).u(XRegister::ra, 0)); + this->instructions.push_back(Instruction(BaseOpcode::jalr) + .i(XRegister::ra, Funct3::jalr, XRegister::ra, 0)); // Set the return value (0). - this->instructions[instructionsLength++] = Instruction(BaseOpcode::op) - .r(XRegister::a0, Funct3::_and, XRegister::zero, XRegister::zero); + this->instructions.push_back(Instruction(BaseOpcode::op) + .r(XRegister::a0, Funct3::_and, XRegister::zero, XRegister::zero)); // Epilogue. - this->instructions[instructionsLength++] = Instruction(BaseOpcode::load) - .i(XRegister::s0, Funct3::lw, XRegister::sp, stackSize - 4); - this->instructions[instructionsLength++] = Instruction(BaseOpcode::load) - .i(XRegister::ra, Funct3::lw, XRegister::sp, stackSize - 8); - this->instructions[instructionsLength++] = Instruction(BaseOpcode::opImm) - .i(XRegister::sp, Funct3::addi, XRegister::sp, stackSize); - this->instructions[instructionsLength++] = Instruction(BaseOpcode::jalr) - .i(XRegister::zero, Funct3::jalr, XRegister::ra, 0); + this->instructions.push_back(Instruction(BaseOpcode::load) + .i(XRegister::s0, Funct3::lw, XRegister::sp, stackSize - 4)); + this->instructions.push_back(Instruction(BaseOpcode::load) + .i(XRegister::ra, Funct3::lw, XRegister::sp, stackSize - 8)); + this->instructions.push_back(Instruction(BaseOpcode::opImm) + .i(XRegister::sp, Funct3::addi, XRegister::sp, stackSize)); + this->instructions.push_back(Instruction(BaseOpcode::jalr) + .i(XRegister::zero, Funct3::jalr, XRegister::ra, 0)); } void RiscVVisitor::visit(source::bang_statement *statement) @@ -132,28 +124,24 @@ namespace elna statement->body().accept(this); } - void RiscVVisitor::visit(source::variable *variable) + void RiscVVisitor::visit(source::variable_expression *variable) { const auto freeRegister = this->registerInUse ? XRegister::a0 : XRegister::t0; - ++this->instructionsLength; - this->instructions = reinterpret_cast( - realloc(this->instructions, this->instructionsLength * sizeof(Instruction))); - this->instructions[this->instructionsLength - 1] = + this->instructions.push_back( Instruction(BaseOpcode::opImm) // movl $x, %eax; where $x is a number. - .i(freeRegister, Funct3::addi, XRegister::zero, constants[variable->name()]); + .i(freeRegister, Funct3::addi, XRegister::zero, constants[variable->name()]) + ); } void RiscVVisitor::visit(source::integer_literal *number) { const auto freeRegister = this->registerInUse ? XRegister::a0 : XRegister::t0; - ++this->instructionsLength; - this->instructions = reinterpret_cast( - realloc(this->instructions, this->instructionsLength * sizeof(Instruction))); - this->instructions[this->instructionsLength - 1] = + this->instructions.push_back( Instruction(BaseOpcode::opImm) // movl $x, %eax; where $x is a number. - .i(freeRegister, Funct3::addi, XRegister::zero, number->number()); + .i(freeRegister, Funct3::addi, XRegister::zero, number->number()) + ); } void RiscVVisitor::visit(source::binary_expression *expression) @@ -163,59 +151,35 @@ namespace elna this->registerInUse = true; expression->lhs().accept(this); - ++this->instructionsLength; - this->instructions = reinterpret_cast( - realloc(this->instructions, this->instructionsLength * sizeof(Instruction))); - this->instructions[instructionsLength - 1] = // movl %eax, -x(%rbp); where x is a number. + this->instructions.push_back( // movl %eax, -x(%rbp); where x is a number. Instruction(BaseOpcode::store) - .s(static_cast(this->variableCounter * 4), Funct3::sw, XRegister::sp, XRegister::a0); + .s(static_cast(this->variableCounter * 4), Funct3::sw, XRegister::sp, XRegister::a0) + ); auto lhs_stack_position = ++this->variableCounter; this->registerInUse = false; expression->rhs().accept(this); - this->instructionsLength += 2; - this->instructions = reinterpret_cast( - realloc(this->instructions, this->instructionsLength * sizeof(Instruction))); - - this->instructions[instructionsLength - 2] = Instruction(BaseOpcode::load) + this->instructions.push_back(Instruction(BaseOpcode::load) .i(XRegister::a0, Funct3::lw, XRegister::sp, - static_cast((lhs_stack_position - 1) * 4)); + static_cast((lhs_stack_position - 1) * 4)) + ); // Calculate the result and assign it to a variable on the stack. switch (expression->operation()) { case source::binary_operator::sum: - this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op) - .r(lhs_register, Funct3::add, XRegister::a0, XRegister::t0); + this->instructions.push_back(Instruction(BaseOpcode::op) + .r(lhs_register, Funct3::add, XRegister::a0, XRegister::t0)); break; case source::binary_operator::subtraction: - this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op) - .r(lhs_register, Funct3::sub, XRegister::a0, XRegister::t0, Funct7::sub); + this->instructions.push_back(Instruction(BaseOpcode::op) + .r(lhs_register, Funct3::sub, XRegister::a0, XRegister::t0, Funct7::sub)); break; case source::binary_operator::multiplication: - this->instructions[instructionsLength - 1] = Instruction(BaseOpcode::op) - .r(lhs_register, Funct3::mul, XRegister::a0, XRegister::t0, Funct7::muldiv); + this->instructions.push_back(Instruction(BaseOpcode::op) + .r(lhs_register, Funct3::mul, XRegister::a0, XRegister::t0, Funct7::muldiv)); break; } } - - Symbol writeNext(source::block *ast) - { - auto visitor = std::make_unique(); - visitor->visit(ast); - - Symbol program{ "main" }; - - for (std::size_t i = 0; i < 3; ++i) - { - program.symbols[i] = visitor->references[i]; - } - for (std::size_t i = 0; i < visitor->instructionsLength; ++i) - { - program.text.insert(program.text.cend(), - visitor->instructions[i].cbegin(), visitor->instructions[i].cend()); - } - return program; - } } diff --git a/source/cl.cpp b/backend/target.cpp similarity index 53% rename from source/cl.cpp rename to backend/target.cpp index 7ed6be5..7506757 100644 --- a/source/cl.cpp +++ b/backend/target.cpp @@ -1,69 +1,30 @@ -#include "elna/cl.hpp" -#include "elna/result.hpp" -#include "elna/riscv.hpp" -#include +#include "elna/backend/target.hpp" +#include "elna/backend/riscv.hpp" #include -#include -#include -namespace elna +namespace elna::backend { - char *readSource(const char *source) + void riscv32_elf(source::block *ast, const std::filesystem::path& out_file) { - const std::size_t bufferSize = 255; + auto visitor = std::make_unique(); + visitor->visit(ast); - std::ifstream input_stream{ source }; - std::stringstream buffer; - buffer << input_stream.rdbuf(); - input_stream.close(); - std::string contents = buffer.str(); - char *result = reinterpret_cast(malloc(contents.size() + 1)); - std::copy(std::cbegin(contents), std::cend(contents), result); - result[contents.size()] = '\0'; - - return result; - } - - int compile(const std::filesystem::path& in_file, const std::filesystem::path& out_file) - { ELFIO::elfio writer; + const ELFIO::Elf_Word instructions_size = visitor->instructions.size() * sizeof(Instruction); - // You can't proceed before this function call! writer.create(ELFIO::ELFCLASS32, ELFIO::ELFDATA2LSB); writer.set_os_abi(ELFIO::ELFOSABI_NONE); writer.set_type(ELFIO::ET_REL); writer.set_machine(ELFIO::EM_RISCV); - auto sourceText = readSource(in_file.c_str()); - if (sourceText == nullptr) - { - return 3; - } - size_t tokensCount{ 0 }; - auto lex_result = source::lex(sourceText); - free(sourceText); - if (lex_result.has_errors()) - { - for (const auto& compile_error : lex_result.errors()) - { - printf("%lu:%lu: %s\n", compile_error.line(), compile_error.column(), compile_error.what()); - } - return 1; - } - auto ast = source::parser(lex_result.success()).parse(); - if (ast == nullptr) - { - return 2; - } - auto program = writeNext(ast.get()); - // Create code section ELFIO::section* text_sec = writer.sections.add(".text"); text_sec->set_type(ELFIO::SHT_PROGBITS); text_sec->set_flags(ELFIO::SHF_ALLOC | ELFIO::SHF_EXECINSTR); text_sec->set_addr_align(0x1); - text_sec->set_data(reinterpret_cast(program.text.data()), program.text.size()); + text_sec->set_data(reinterpret_cast(visitor->instructions.data()), + instructions_size); // Create string table section ELFIO::section* str_sec = writer.sections.add(".strtab"); @@ -93,7 +54,7 @@ namespace elna ELFIO::symbol_section_accessor syma(writer, sym_sec); auto label_sym = syma.add_symbol(stra, ".CL0", 0x00000000, strlen("%d\n") + 1, ELFIO::STB_LOCAL, ELFIO::STT_NOTYPE, 0, ro_sec->get_index()); - syma.add_symbol(stra, program.name, 0x00000000, program.text.size(), + syma.add_symbol(stra, "main", 0x00000000, instructions_size, ELFIO::STB_GLOBAL, ELFIO::STT_FUNC, 0, text_sec->get_index()); auto printf_sym = syma.add_symbol(stra, "printf", 0x00000000, 0, ELFIO::STB_GLOBAL, ELFIO::STT_NOTYPE, 0, ELFIO::SHN_UNDEF); @@ -110,16 +71,14 @@ namespace elna // Create relocation table writer ELFIO::relocation_section_accessor rela(writer, rel_sec); // Add relocation entry (adjust address at offset 11) - rela.add_entry(program.symbols[0].offset, label_sym, 26 /* ELFIO::R_RISCV_HI20 */); - rela.add_entry(program.symbols[0].offset, label_sym, 51 /* ELFIO::R_RISCV_RELAX */); - rela.add_entry(program.symbols[1].offset, label_sym, 27 /* ELFIO::R_RISCV_LO12_I */); - rela.add_entry(program.symbols[1].offset, label_sym, 51 /* ELFIO::R_RISCV_RELAX */); - rela.add_entry(program.symbols[2].offset, printf_sym, 18 /* ELFIO::R_RISCV_CALL */); - rela.add_entry(program.symbols[2].offset, printf_sym, 51 /* ELFIO::R_RISCV_RELAX */); + rela.add_entry(visitor->references[0].offset, label_sym, 26 /* ELFIO::R_RISCV_HI20 */); + rela.add_entry(visitor->references[0].offset, label_sym, 51 /* ELFIO::R_RISCV_RELAX */); + rela.add_entry(visitor->references[1].offset, label_sym, 27 /* ELFIO::R_RISCV_LO12_I */); + rela.add_entry(visitor->references[1].offset, label_sym, 51 /* ELFIO::R_RISCV_RELAX */); + rela.add_entry(visitor->references[2].offset, printf_sym, 18 /* ELFIO::R_RISCV_CALL */); + rela.add_entry(visitor->references[2].offset, printf_sym, 51 /* ELFIO::R_RISCV_RELAX */); // Create ELF object file writer.save(out_file); - - return 0; } } diff --git a/cli/cl.cpp b/cli/cl.cpp new file mode 100644 index 0000000..36cb10e --- /dev/null +++ b/cli/cl.cpp @@ -0,0 +1,52 @@ +#include "elna/cli/cl.hpp" +#include "elna/backend/target.hpp" +#include +#include +#include + +namespace elna::cli +{ + char *readSource(const char *source) + { + const std::size_t bufferSize = 255; + + std::ifstream input_stream{ source }; + std::stringstream buffer; + buffer << input_stream.rdbuf(); + input_stream.close(); + std::string contents = buffer.str(); + char *result = reinterpret_cast(malloc(contents.size() + 1)); + std::copy(std::cbegin(contents), std::cend(contents), result); + result[contents.size()] = '\0'; + + return result; + } + + int compile(const std::filesystem::path& in_file, const std::filesystem::path& out_file) + { + auto sourceText = readSource(in_file.c_str()); + if (sourceText == nullptr) + { + return 3; + } + size_t tokensCount{ 0 }; + auto lex_result = source::lex(sourceText); + free(sourceText); + if (lex_result.has_errors()) + { + for (const auto& compile_error : lex_result.errors()) + { + printf("%lu:%lu: %s\n", compile_error.line(), compile_error.column(), compile_error.what()); + } + return 1; + } + auto ast = source::parser(lex_result.success()).parse(); + if (ast == nullptr) + { + return 2; + } + backend::riscv32_elf(ast.get(), out_file); + + return 0; + } +} diff --git a/source/main.cpp b/cli/main.cpp similarity index 94% rename from source/main.cpp rename to cli/main.cpp index 6cd8ba2..409abbd 100644 --- a/source/main.cpp +++ b/cli/main.cpp @@ -1,4 +1,4 @@ -#include "elna/cl.hpp" +#include "elna/cli/cl.hpp" #include #include @@ -43,5 +43,5 @@ int main(int argc, char **argv) { out_file = in_file.filename().replace_extension(".o"); } - return elna::compile(in_file, out_file); + return elna::cli::compile(in_file, out_file); } diff --git a/include/elna/riscv.hpp b/include/elna/backend/riscv.hpp similarity index 89% rename from include/elna/riscv.hpp rename to include/elna/backend/riscv.hpp index 2d8cd2e..7ca80a4 100644 --- a/include/elna/riscv.hpp +++ b/include/elna/backend/riscv.hpp @@ -3,10 +3,23 @@ #include #include #include "elna/source/parser.hpp" -#include "elna/result.hpp" -namespace elna +namespace elna::backend { + enum class Target + { + text, + high20, + lower12i + }; + + struct Reference + { + const char* name; + std::size_t offset; + Target target; + }; + enum class XRegister : std::uint8_t { zero = 0, @@ -135,8 +148,8 @@ namespace elna Instruction& r(XRegister rd, Funct3 funct3, XRegister rs1, XRegister rs2, Funct7 funct7 = Funct7::none); Instruction& u(XRegister rd, std::uint32_t imm); - const std::byte *cbegin(); - const std::byte *cend(); + const std::byte *cbegin() const; + const std::byte *cend() const; private: std::uint32_t instruction{ 0 }; @@ -145,8 +158,7 @@ namespace elna class RiscVVisitor : public source::ParserVisitor { public: - Instruction *instructions; - std::size_t instructionsLength; + std::vector instructions; bool registerInUse{ true }; std::uint32_t variableCounter = 1; Reference references[3]; @@ -155,10 +167,8 @@ namespace elna virtual void visit(source::definition *definition) override; virtual void visit(source::bang_statement *statement) override; virtual void visit(source::block *block) override; - virtual void visit(source::variable *variable) override; + virtual void visit(source::variable_expression *variable) override; virtual void visit(source::integer_literal *number) override; virtual void visit(source::binary_expression *expression) override; }; - - Symbol writeNext(source::block *ast); } diff --git a/include/elna/backend/target.hpp b/include/elna/backend/target.hpp new file mode 100644 index 0000000..45ebb26 --- /dev/null +++ b/include/elna/backend/target.hpp @@ -0,0 +1,7 @@ +#include "elna/source/parser.hpp" +#include + +namespace elna::backend +{ + void riscv32_elf(source::block *ast, const std::filesystem::path& out_file); +} diff --git a/include/elna/cl.hpp b/include/elna/cli/cl.hpp similarity index 89% rename from include/elna/cl.hpp rename to include/elna/cli/cl.hpp index d431d94..2d12d39 100644 --- a/include/elna/cl.hpp +++ b/include/elna/cli/cl.hpp @@ -2,7 +2,7 @@ #include -namespace elna +namespace elna::cli { char *readSource(const char *source); int compile(const std::filesystem::path& in_file, const std::filesystem::path& out_file); diff --git a/include/elna/result.hpp b/include/elna/result.hpp deleted file mode 100644 index 7e81129..0000000 --- a/include/elna/result.hpp +++ /dev/null @@ -1,112 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace elna -{ - namespace source - { - /** - * Position in the source text. - */ - struct position - { - /// Line. - std::size_t line = 1; - - /// Column. - std::size_t column = 1; - }; - - /** - * A compilation error consists of an error message and position. - */ - struct error - { - private: - char const *message; - source::position position; - - public: - /** - * \param message Error text. - * \param position Error position in the source text. - */ - error(char const *message, const source::position position) noexcept; - - /// Error text. - const char *what() const noexcept; - - /// Error line in the source text. - std::size_t line() const noexcept; - - /// Error column in the source text. - std::size_t column() const noexcept; - }; - - template - struct result - { - using E = std::forward_list; - - template - explicit result(Args&&... arguments) - : payload(std::forward(arguments)...) - { - } - - explicit result(const char *message, const source::position position) - : payload(E{ source::error(message, position) }) - { - } - - bool has_errors() const noexcept - { - return std::holds_alternative(payload); - } - - bool is_success() const noexcept - { - return std::holds_alternative(payload); - } - - T& success() - { - return std::get(payload); - } - - E& errors() - { - return std::get(payload); - } - - private: - std::variant payload; - }; - } - - enum class Target - { - text, - high20, - lower12i - }; - - struct Reference - { - const char* name; - size_t offset; - Target target; - }; - - struct Symbol - { - Symbol(const char *name); - const char *name; - std::vector text; - Reference symbols[3]; - }; -} diff --git a/include/elna/history.hpp b/include/elna/shell/history.hpp similarity index 100% rename from include/elna/history.hpp rename to include/elna/shell/history.hpp diff --git a/include/elna/interactive.hpp b/include/elna/shell/interactive.hpp similarity index 96% rename from include/elna/interactive.hpp rename to include/elna/shell/interactive.hpp index 8106060..bd3f94c 100644 --- a/include/elna/interactive.hpp +++ b/include/elna/shell/interactive.hpp @@ -5,8 +5,8 @@ #include #include -#include "elna/state.hpp" -#include "elna/history.hpp" +#include "elna/shell/state.hpp" +#include "elna/shell/history.hpp" #define BOOST_PROCESS_USE_STD_FS diff --git a/include/elna/state.hpp b/include/elna/shell/state.hpp similarity index 100% rename from include/elna/state.hpp rename to include/elna/shell/state.hpp diff --git a/include/elna/ir.hpp b/include/elna/source/ir.hpp similarity index 82% rename from include/elna/ir.hpp rename to include/elna/source/ir.hpp index ae4269c..9acad11 100644 --- a/include/elna/ir.hpp +++ b/include/elna/source/ir.hpp @@ -2,7 +2,7 @@ #include "elna/source/parser.hpp" -namespace elna +namespace elna::source { class TransformVisitor final : public source::ParserVisitor { @@ -10,7 +10,7 @@ namespace elna void visit(source::bang_statement *statement) override; void visit(source::block *block) override; void visit(source::integer_literal *number) override; - void visit(source::variable *variable) override; + void visit(source::variable_expression *variable) override; void visit(source::binary_expression *binaryExpression) override; }; } diff --git a/include/elna/source/lexer.hpp b/include/elna/source/lexer.hpp index 3f08770..5ad4f03 100644 --- a/include/elna/source/lexer.hpp +++ b/include/elna/source/lexer.hpp @@ -2,12 +2,10 @@ #include #include +#include +#include "elna/source/result.hpp" -#include "elna/result.hpp" - -namespace elna -{ -namespace source +namespace elna::source { /** * Range over the source text that keeps track of the current position. @@ -113,4 +111,3 @@ namespace source */ elna::source::result> lex(const std::string& buffer); } -} diff --git a/include/elna/source/parser.hpp b/include/elna/source/parser.hpp index 975e0e9..587df1d 100644 --- a/include/elna/source/parser.hpp +++ b/include/elna/source/parser.hpp @@ -4,9 +4,7 @@ #include #include -namespace elna -{ -namespace source +namespace elna::source { enum class binary_operator { @@ -20,7 +18,7 @@ namespace source class bang_statement; class block; class binary_expression; - class variable; + class variable_expression; class integer_literal; struct ParserVisitor @@ -29,7 +27,7 @@ namespace source virtual void visit(bang_statement *) = 0; virtual void visit(block *) = 0; virtual void visit(binary_expression *) = 0; - virtual void visit(variable *) = 0; + virtual void visit(variable_expression *) = 0; virtual void visit(integer_literal *) = 0; }; @@ -104,12 +102,12 @@ namespace source std::int32_t number() const noexcept; }; - class variable : public expression + class variable_expression : public expression { std::string m_name; public: - variable(const std::string& name); + variable_expression(const std::string& name); virtual void accept(ParserVisitor *visitor) override; const std::string& name() const noexcept; @@ -150,4 +148,3 @@ namespace source std::vector::const_iterator end; }; } -} diff --git a/include/elna/source/result.hpp b/include/elna/source/result.hpp new file mode 100644 index 0000000..b383ed4 --- /dev/null +++ b/include/elna/source/result.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include +#include +#include + +namespace elna::source +{ + /** + * Position in the source text. + */ + struct position + { + /// Line. + std::size_t line = 1; + + /// Column. + std::size_t column = 1; + }; + + /** + * A compilation error consists of an error message and position. + */ + struct error + { + private: + char const *message; + source::position position; + + public: + /** + * \param message Error text. + * \param position Error position in the source text. + */ + error(char const *message, const source::position position) noexcept; + + /// Error text. + const char *what() const noexcept; + + /// Error line in the source text. + std::size_t line() const noexcept; + + /// Error column in the source text. + std::size_t column() const noexcept; + }; + + template + struct result + { + using E = std::forward_list; + + template + explicit result(Args&&... arguments) + : payload(std::forward(arguments)...) + { + } + + explicit result(const char *message, const source::position position) + : payload(E{ source::error(message, position) }) + { + } + + bool has_errors() const noexcept + { + return std::holds_alternative(payload); + } + + bool is_success() const noexcept + { + return std::holds_alternative(payload); + } + + T& success() + { + return std::get(payload); + } + + E& errors() + { + return std::get(payload); + } + + private: + std::variant payload; + }; +} diff --git a/shell/history.cpp b/shell/history.cpp index aad7375..986e068 100644 --- a/shell/history.cpp +++ b/shell/history.cpp @@ -1,4 +1,4 @@ -#include "elna/history.hpp" +#include "elna/shell/history.hpp" namespace elna { diff --git a/shell/interactive.cpp b/shell/interactive.cpp index e10446a..4cca5ae 100644 --- a/shell/interactive.cpp +++ b/shell/interactive.cpp @@ -1,4 +1,4 @@ -#include "elna/interactive.hpp" +#include "elna/shell/interactive.hpp" #include #include diff --git a/shell/main.cpp b/shell/main.cpp index 19b1892..c30c4a2 100644 --- a/shell/main.cpp +++ b/shell/main.cpp @@ -1,6 +1,6 @@ #include #include -#include "elna/interactive.hpp" +#include "elna/shell/interactive.hpp" int main() { diff --git a/shell/state.cpp b/shell/state.cpp index f148980..1aef61b 100644 --- a/shell/state.cpp +++ b/shell/state.cpp @@ -1,7 +1,7 @@ #include #include -#include "elna/state.hpp" +#include "elna/shell/state.hpp" namespace elna { diff --git a/source/ir.cpp b/source/ir.cpp index bd8c622..118eb09 100644 --- a/source/ir.cpp +++ b/source/ir.cpp @@ -1,8 +1,8 @@ -#include "elna/ir.hpp" +#include "elna/source/ir.hpp" #include -namespace elna +namespace elna::source { void TransformVisitor::visit(source::definition *definition) { @@ -24,7 +24,7 @@ namespace elna assert(false); } - void TransformVisitor::visit(source::variable *variable) + void TransformVisitor::visit(source::variable_expression *variable) { assert(false); } diff --git a/source/lexer.cpp b/source/lexer.cpp index f39f49b..ed5117b 100644 --- a/source/lexer.cpp +++ b/source/lexer.cpp @@ -1,9 +1,7 @@ #include "elna/source/lexer.hpp" #include -namespace elna -{ -namespace source +namespace elna::source { using source_position = elna::source::position; using source_error = elna::source::error; @@ -287,4 +285,3 @@ namespace source return source_result(tokens); } } -} diff --git a/source/parser.cpp b/source/parser.cpp index 97dbc43..7866b94 100644 --- a/source/parser.cpp +++ b/source/parser.cpp @@ -1,9 +1,7 @@ #include "elna/source/parser.hpp" #include -namespace elna -{ -namespace source +namespace elna::source { /** * AST node. @@ -67,17 +65,17 @@ namespace source return m_number; } - variable::variable(const std::string& name) + variable_expression::variable_expression(const std::string& name) : m_name(name) { } - void variable::accept(ParserVisitor *visitor) + void variable_expression::accept(ParserVisitor *visitor) { visitor->visit(this); } - const std::string& variable::name() const noexcept + const std::string& variable_expression::name() const noexcept { return m_name; } @@ -154,7 +152,7 @@ namespace source { if (tokens->of() == source::token::type::identifier) { - auto result = std::make_unique(tokens->identifier()); + auto result = std::make_unique(tokens->identifier()); ++tokens; return result; } @@ -291,4 +289,3 @@ namespace source return std::make_unique(std::move(definitions), std::move(parsed_statement)); } } -} diff --git a/source/result.cpp b/source/result.cpp index 15fc56a..9fec0b6 100644 --- a/source/result.cpp +++ b/source/result.cpp @@ -1,8 +1,6 @@ -#include "elna/result.hpp" +#include "elna/source/result.hpp" -namespace elna -{ -namespace source +namespace elna::source { error::error(const char *message, const source::position position) noexcept { @@ -25,9 +23,3 @@ namespace source return this->position.column; } } - - Symbol::Symbol(const char *name) - { - this->name = name; - } -} diff --git a/tests/runner.cpp b/tests/tester.cpp similarity index 100% rename from tests/runner.cpp rename to tests/tester.cpp