From bf262cb71451f8c04b9e96cf57f9c9f3b0cf636e Mon Sep 17 00:00:00 2001 From: Ludovic 'Archivist' Lagouardette Date: Wed, 25 Jan 2023 21:23:43 +0100 Subject: [PATCH] Compiles into a valid executable that returns exit success --- CMakeLists.txt | 2 +- include/molasses/generator_primitives.h | 16 ++ include/molasses/parser_primitives.h | 7 + src/main.cpp | 7 +- .../generator_primitives_x86_64_linux.cpp | 247 ++++++++++++++++++ src/molasses/parser_primitives.cpp | 241 ++--------------- 6 files changed, 293 insertions(+), 227 deletions(-) create mode 100644 include/molasses/generator_primitives.h create mode 100644 src/molasses/generator_primitives_x86_64_linux.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4205f73..6d0bc7d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,4 +7,4 @@ set(CMAKE_CXX_STANDARD 20) include_directories(include) -add_executable(sugar src/main.cpp src/molasses/lexer.cpp include/molasses/lexer.h src/molasses/parser_primitives.cpp include/molasses/parser_primitives.h) +add_executable(sugar src/main.cpp src/molasses/lexer.cpp src/molasses/generator_primitives_x86_64_linux.cpp include/molasses/lexer.h src/molasses/parser_primitives.cpp include/molasses/parser_primitives.h include/molasses/generator_primitives.h) diff --git a/include/molasses/generator_primitives.h b/include/molasses/generator_primitives.h new file mode 100644 index 0000000..7a79480 --- /dev/null +++ b/include/molasses/generator_primitives.h @@ -0,0 +1,16 @@ +#pragma once +#include "molasses/parser_primitives.h" + +namespace molasses { + std::vector initialize_stack(); + + std::vector generate_return(); + + std::vector generate_label(std::string target); + + std::vector generate_push_int32(int32_t target); + + std::vector generate_call(std::string target); + + std::vector generate_enter(); +} \ No newline at end of file diff --git a/include/molasses/parser_primitives.h b/include/molasses/parser_primitives.h index 39eaa96..c0a508b 100644 --- a/include/molasses/parser_primitives.h +++ b/include/molasses/parser_primitives.h @@ -9,6 +9,13 @@ #include "molasses/lexer.h" + +enum class architecture_t { + x86_64 +}; + +constexpr architecture_t architecture = architecture_t::x86_64; + namespace molasses { struct type { [[nodiscard]] virtual std::string name() const = 0; diff --git a/src/main.cpp b/src/main.cpp index 181c8b9..b3cdd7f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,13 +33,18 @@ int main() { if(molasses::type_check(ctx, v, v.symbols, {}, {"i32"})) { std::cout << "Checks out\n"; }*/ - + /* auto lexed = molasses::lex("__PROC__ sum\n" "i32 i32\n" "__--__\n" "i32\n" "__DO__\n" "+\n" + "__END__");*/ + + auto lexed = molasses::lex("__PROC__ main\n" + "__--__\n" + "__DO__\n" "__END__"); molasses::parser_context ctx; diff --git a/src/molasses/generator_primitives_x86_64_linux.cpp b/src/molasses/generator_primitives_x86_64_linux.cpp new file mode 100644 index 0000000..702f3b1 --- /dev/null +++ b/src/molasses/generator_primitives_x86_64_linux.cpp @@ -0,0 +1,247 @@ +#include "molasses/parser_primitives.h" +#include "molasses/generator_primitives.h" + +namespace molasses { + parser_context register_integers(parser_context ctx) requires (architecture == architecture_t::x86_64) { + ctx.types.push_back(std::make_shared("i8", 1)); + ctx.types.push_back(std::make_shared("i16", 2)); + ctx.types.push_back(std::make_shared("i32", 4)); + ctx.types.push_back(std::make_shared("i64", 8)); + ctx.types.push_back(std::make_shared("u8", 1)); + ctx.types.push_back(std::make_shared("u16", 2)); + ctx.types.push_back(std::make_shared("u32", 4)); + ctx.types.push_back(std::make_shared("u64", 8)); + + return ctx; + } + + parser_context register_i32_operations(parser_context ctx) requires (architecture == architecture_t::x86_64) { + ctx.operations.emplace_back( + std::make_shared( + std::string{"+"}, + std::vector({"i32", "i32"}), + std::vector({"i32"}), + std::vector({ + " popq %rax\n", + " popq %rbx\n", + " addl %ebx, %eax\n", + " andl $0xFFFFFFFF, %eax\n", + " pushq %rax\n" + }) + ) + ); + ctx.operations.emplace_back( + std::make_shared( + std::string{"*"}, + std::vector({"i32", "i32"}), + std::vector({"i32"}), + std::vector({ + " popq %rax\n", + " popq %rbx\n", + " multl %ebx, %eax\n", + " andl $0xFFFFFFFF, %eax\n", + " pushq %rax\n" + }) + ) + ); + ctx.operations.emplace_back( + std::make_shared( + std::string{"-"}, + std::vector({"i32", "i32"}), + std::vector({"i32"}), + std::vector({ + " popq %rax\n", + " popq %rbx\n", + " subl %ebx, %eax\n", + " andl $0xFFFFFFFF, %eax\n", + " pushq %rax\n" + }) + ) + ); + ctx.operations.emplace_back( + std::make_shared( + std::string{"i32-to-i64"}, + std::vector({"i32"}), + std::vector({"i64"}), + std::vector({ + " popq %rax\n", + " movslq %rax\n", + " pushq %rax\n" + }) + ) + ); + + ctx.operations.emplace_back( + std::make_shared( + std::string{"syscall1"}, + std::vector({"i64", "i64"}), + std::vector({"i64"}), + std::vector({ + " popq %rax\n", + " popq %rdi\n", + " syscall\n", + " pushq %rax\n" + }) + ) + ); + ctx.operations.emplace_back( + std::make_shared( + std::string{"syscall2"}, + std::vector({"i64", "i64", "i64"}), + std::vector({"i64"}), + std::vector({ + " popq %rax\n", + " popq %rdi\n", + " popq %rsi\n", + " syscall\n", + " pushq %rax\n" + }) + ) + ); + ctx.operations.emplace_back( + std::make_shared( + std::string{"syscall3"}, + std::vector({"i64", "i64", "i64", "i64"}), + std::vector({"i64"}), + std::vector({ + " popq %rax\n", + " popq %rdi\n", + " popq %rsi\n", + " popq %rdx\n", + " syscall\n", + " pushq %rax\n" + }) + ) + ); + ctx.operations.emplace_back( + std::make_shared( + std::string{"syscall4"}, + std::vector({"i64", "i64", "i64", "i64", "i64"}), + std::vector({"i64"}), + std::vector({ + " popq %rax\n", + " popq %rdi\n", + " popq %rsi\n", + " popq %rdx\n", + " popq %r10\n", + " syscall\n", + " pushq %rax\n" + }) + ) + ); + ctx.operations.emplace_back( + std::make_shared( + std::string{"syscall5"}, + std::vector({"i64", "i64", "i64", "i64", "i64", "i64"}), + std::vector({"i64"}), + std::vector({ + " popq %rax\n", + " popq %rdi\n", + " popq %rsi\n", + " popq %rdx\n", + " popq %r10\n", + " popq %r8\n", + " syscall\n", + " pushq %rax\n" + }) + ) + ); + ctx.operations.emplace_back( + std::make_shared( + std::string{"syscall6"}, + std::vector({"i64", "i64", "i64", "i64", "i64", "i64", "i64"}), + std::vector({"i64"}), + std::vector({ + " popq %rax\n", + " popq %rdi\n", + " popq %rsi\n", + " popq %rdx\n", + " popq %r10\n", + " popq %r8\n", + " popq %r9\n", + " syscall\n", + " pushq %rax\n" + }) + ) + ); + + return ctx; + } + + std::vector generate_call(std::string target) + requires (architecture == architecture_t::x86_64) { + return { + " call "+target+"\n", + }; + } + + std::vector generate_push_int32(int32_t target) + requires (architecture == architecture_t::x86_64) { + return { + " pushq $" +std::to_string(target)+ "\n" + }; + } + + std::vector generate_label(std::string target) + requires (architecture == architecture_t::x86_64) { + return { + target+":\n" + }; + } + + std::vector generate_return() + requires (architecture == architecture_t::x86_64) { + return { + " // Return to caller\n", + " addq $-8, %r10\n", + " pushq (%r10)\n", + " retq\n" + }; + } + + std::vector generate_enter() + requires (architecture == architecture_t::x86_64) { + return { + " // Prepare the function stack\n", + " popq (%r10)\n" + " addq $8, %r10\n", + }; + } + + std::vector initialize_stack() + requires (architecture == architecture_t::x86_64) { + std::vector operations = { + "code:\n", + " .skip 1000000\n", + ".text\n", + " .globl _start\n", + "initialize_callstack:\n", + " movq $9, %rax\n", + " movq $0, %rdi\n", + " movq $8192, %rsi\n", + " movq $3, %rdx\n", + " movq $34, %r10\n", + " movq $-1, %r8\n", + " movq $0, %r9\n", + " syscall\n", + " movq %rax, %r10\n", + " retq\n", + "_start:\n", + " call initialize_callstack\n" + }; + + for(auto op : generate_call("main")) { + operations.push_back(op); + } + + for(auto op : std::vector{ + " movq $0, %rdi\n", + " movq $60, %rax\n", + " syscall\n" + } + ) { + operations.push_back(op); + } + return operations; + } +} \ No newline at end of file diff --git a/src/molasses/parser_primitives.cpp b/src/molasses/parser_primitives.cpp index 06e9189..9f459a5 100644 --- a/src/molasses/parser_primitives.cpp +++ b/src/molasses/parser_primitives.cpp @@ -2,180 +2,9 @@ #include #include #include "molasses/parser_primitives.h" - -enum class architecture_t { - x86_64 -}; - -constexpr architecture_t architecture = architecture_t::x86_64; +#include "molasses/generator_primitives.h" namespace molasses { - parser_context register_integers(parser_context ctx) { - ctx.types.push_back(std::make_shared("i8",1)); - ctx.types.push_back(std::make_shared("i16",2)); - ctx.types.push_back(std::make_shared("i32",4)); - ctx.types.push_back(std::make_shared("i64",8)); - ctx.types.push_back(std::make_shared("u8",1)); - ctx.types.push_back(std::make_shared("u16",2)); - ctx.types.push_back(std::make_shared("u32",4)); - ctx.types.push_back(std::make_shared("u64",8)); - - return ctx; - } - - parser_context register_i32_operations(parser_context ctx) { - ctx.operations.emplace_back( - std::make_shared( - std::string{"+"}, - std::vector({"i32", "i32"}), - std::vector({"i32"}), - std::vector({ - " popq %rax\n", - " popq %rbx\n", - " addl %ebx, %eax\n", - " andl $0xFFFFFFFF, %eax\n", - " pushq %rax\n" - }) - ) - ); - ctx.operations.emplace_back( - std::make_shared( - std::string{"*"}, - std::vector({"i32", "i32"}), - std::vector({"i32"}), - std::vector({ - " popq %rax\n", - " popq %rbx\n", - " multl %ebx, %eax\n", - " andl $0xFFFFFFFF, %eax\n", - " pushq %rax\n" - }) - ) - ); - ctx.operations.emplace_back( - std::make_shared( - std::string{"-"}, - std::vector({"i32", "i32"}), - std::vector({"i32"}), - std::vector({ - " popq %rax\n", - " popq %rbx\n", - " subl %ebx, %eax\n", - " andl $0xFFFFFFFF, %eax\n", - " pushq %rax\n" - }) - ) - ); - ctx.operations.emplace_back( - std::make_shared( - std::string{"i32-to-i64"}, - std::vector({"i32"}), - std::vector({"i64"}), - std::vector({ - " popq %rax\n", - " movslq %rax\n", - " pushq %rax\n" - }) - ) - ); - - ctx.operations.emplace_back( - std::make_shared( - std::string{"syscall1"}, - std::vector({"i64", "i64"}), - std::vector({"i64"}), - std::vector({ - " popq %rax\n", - " popq %rdi\n", - " syscall\n", - " pushq %rax\n" - }) - ) - ); - ctx.operations.emplace_back( - std::make_shared( - std::string{"syscall2"}, - std::vector({"i64", "i64", "i64"}), - std::vector({"i64"}), - std::vector({ - " popq %rax\n", - " popq %rdi\n", - " popq %rsi\n", - " syscall\n", - " pushq %rax\n" - }) - ) - ); - ctx.operations.emplace_back( - std::make_shared( - std::string{"syscall3"}, - std::vector({"i64", "i64", "i64", "i64"}), - std::vector({"i64"}), - std::vector({ - " popq %rax\n", - " popq %rdi\n", - " popq %rsi\n", - " popq %rdx\n", - " syscall\n", - " pushq %rax\n" - }) - ) - ); - ctx.operations.emplace_back( - std::make_shared( - std::string{"syscall4"}, - std::vector({"i64", "i64", "i64", "i64", "i64"}), - std::vector({"i64"}), - std::vector({ - " popq %rax\n", - " popq %rdi\n", - " popq %rsi\n", - " popq %rdx\n", - " popq %r10\n", - " syscall\n", - " pushq %rax\n" - }) - ) - ); - ctx.operations.emplace_back( - std::make_shared( - std::string{"syscall5"}, - std::vector({"i64", "i64", "i64", "i64", "i64", "i64"}), - std::vector({"i64"}), - std::vector({ - " popq %rax\n", - " popq %rdi\n", - " popq %rsi\n", - " popq %rdx\n", - " popq %r10\n", - " popq %r8\n", - " syscall\n", - " pushq %rax\n" - }) - ) - ); - ctx.operations.emplace_back( - std::make_shared( - std::string{"syscall6"}, - std::vector({"i64", "i64", "i64", "i64", "i64", "i64", "i64"}), - std::vector({"i64"}), - std::vector({ - " popq %rax\n", - " popq %rdi\n", - " popq %rsi\n", - " popq %rdx\n", - " popq %r10\n", - " popq %r8\n", - " popq %r9\n", - " syscall\n", - " pushq %rax\n" - }) - ) - ); - - return ctx; - } - std::vector operator>>(std::vector current_stack, const operation& next_op) { { auto args = next_op.argument_types(); @@ -249,27 +78,6 @@ namespace molasses { return type_stack == execution_output; } - std::vector initialize_stack() - requires (architecture == architecture_t::x86_64) { - return { - ".bss\n",// TODO: make threadlocal - "stack_instruction:\n", - " .quad 0\n", - ".text\n", - "initialize_callstack:\n", - " movq $9, %rax\n", - " movq $0, %rdi\n", - " movq $8192, %rsi\n", - " movq $3, %rdx\n", - " movq $34, %r10\n", - " movq $-1, %r8\n", - " movq $0, %r9\n", - " syscall\n", - " movq %rax, (stack_instruction)\n", - " retq\n", - }; - } - parser_context parse(parser_context ctx, const lexed_output& lexer_data) { enum op : int { DO_KW = 1, @@ -375,48 +183,31 @@ namespace molasses { return ctx; } - std::vector generate_call(std::string target) - requires (architecture == architecture_t::x86_64) { - static uint64_t label_count= 0; - return { - " movq return_label_n"+std::to_string(label_count)+", (stack_instruction)\n", - " addq $8, stack_instruction\n", - " jmp "+target+"\n", - " return_label_n"+std::to_string(label_count++)+":" - }; - } - - std::vector generate_push_int32(int32_t target) requires (architecture == architecture_t::x86_64) { - return { - " pushq $" +std::to_string(target)+ "\n" - }; - } - - std::vector procedure_operation::generate(const parser_context& ctx, const lexed_output& lexer_data) const - requires (architecture == architecture_t::x86_64) { - std::vector ops; - ops.emplace_back(name()+":\n"); - + std::vector procedure_operation::generate(const parser_context& ctx, const lexed_output& lexer_data) const { + std::vector ops = generate_label(name()); + + for(auto&& instruction : generate_enter()) { + ops.push_back(instruction); + } + for(auto elem : _body) { auto token = lexer_data.dictionary.at(elem); if(auto result = try_parse_int32(token); result) { - for(auto&& elem : generate_push_int32(result.value())) { - ops.push_back(elem); + for(auto&& instruction : generate_push_int32(result.value())) { + ops.push_back(instruction); } } else if(auto op = ctx.lookup_operation(token); op) { - for(auto&& elem : op->emit(ctx)) { - ops.push_back(elem); + for(auto&& instruction : op->emit(ctx)) { + ops.push_back(instruction); } } else { throw UnknownTokenError(); } } - - ops.emplace_back(" // Return to caller\n"); - ops.emplace_back(" addq $-8, stack_instruction\n"); - ops.emplace_back(" movq (stack_instruction), %rax\n"); - ops.emplace_back(" pushq %rax\n"); - ops.emplace_back(" retq\n"); + + for(auto&& instruction : generate_return()) { + ops.push_back(instruction); + } return ops; }