Browse Source

Compiles into a valid executable that returns exit success

master
Ludovic 'Archivist' Lagouardette 1 year ago
parent
commit
bf262cb714
6 changed files with 293 additions and 227 deletions
  1. +1
    -1
      CMakeLists.txt
  2. +16
    -0
      include/molasses/generator_primitives.h
  3. +7
    -0
      include/molasses/parser_primitives.h
  4. +6
    -1
      src/main.cpp
  5. +247
    -0
      src/molasses/generator_primitives_x86_64_linux.cpp
  6. +16
    -225
      src/molasses/parser_primitives.cpp

+ 1
- 1
CMakeLists.txt View File

@ -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)

+ 16
- 0
include/molasses/generator_primitives.h View File

@ -0,0 +1,16 @@
#pragma once
#include "molasses/parser_primitives.h"
namespace molasses {
std::vector<std::string> initialize_stack();
std::vector<std::string> generate_return();
std::vector<std::string> generate_label(std::string target);
std::vector<std::string> generate_push_int32(int32_t target);
std::vector<std::string> generate_call(std::string target);
std::vector<std::string> generate_enter();
}

+ 7
- 0
include/molasses/parser_primitives.h View File

@ -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;

+ 6
- 1
src/main.cpp View File

@ -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;

+ 247
- 0
src/molasses/generator_primitives_x86_64_linux.cpp View File

@ -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<primitive_type>("i8", 1));
ctx.types.push_back(std::make_shared<primitive_type>("i16", 2));
ctx.types.push_back(std::make_shared<primitive_type>("i32", 4));
ctx.types.push_back(std::make_shared<primitive_type>("i64", 8));
ctx.types.push_back(std::make_shared<primitive_type>("u8", 1));
ctx.types.push_back(std::make_shared<primitive_type>("u16", 2));
ctx.types.push_back(std::make_shared<primitive_type>("u32", 4));
ctx.types.push_back(std::make_shared<primitive_type>("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<molasses::primitive_operation>(
std::string{"+"},
std::vector<std::string>({"i32", "i32"}),
std::vector<std::string>({"i32"}),
std::vector<std::string>({
" popq %rax\n",
" popq %rbx\n",
" addl %ebx, %eax\n",
" andl $0xFFFFFFFF, %eax\n",
" pushq %rax\n"
})
)
);
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"*"},
std::vector<std::string>({"i32", "i32"}),
std::vector<std::string>({"i32"}),
std::vector<std::string>({
" popq %rax\n",
" popq %rbx\n",
" multl %ebx, %eax\n",
" andl $0xFFFFFFFF, %eax\n",
" pushq %rax\n"
})
)
);
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"-"},
std::vector<std::string>({"i32", "i32"}),
std::vector<std::string>({"i32"}),
std::vector<std::string>({
" popq %rax\n",
" popq %rbx\n",
" subl %ebx, %eax\n",
" andl $0xFFFFFFFF, %eax\n",
" pushq %rax\n"
})
)
);
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"i32-to-i64"},
std::vector<std::string>({"i32"}),
std::vector<std::string>({"i64"}),
std::vector<std::string>({
" popq %rax\n",
" movslq %rax\n",
" pushq %rax\n"
})
)
);
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"syscall1"},
std::vector<std::string>({"i64", "i64"}),
std::vector<std::string>({"i64"}),
std::vector<std::string>({
" popq %rax\n",
" popq %rdi\n",
" syscall\n",
" pushq %rax\n"
})
)
);
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"syscall2"},
std::vector<std::string>({"i64", "i64", "i64"}),
std::vector<std::string>({"i64"}),
std::vector<std::string>({
" popq %rax\n",
" popq %rdi\n",
" popq %rsi\n",
" syscall\n",
" pushq %rax\n"
})
)
);
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"syscall3"},
std::vector<std::string>({"i64", "i64", "i64", "i64"}),
std::vector<std::string>({"i64"}),
std::vector<std::string>({
" popq %rax\n",
" popq %rdi\n",
" popq %rsi\n",
" popq %rdx\n",
" syscall\n",
" pushq %rax\n"
})
)
);
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"syscall4"},
std::vector<std::string>({"i64", "i64", "i64", "i64", "i64"}),
std::vector<std::string>({"i64"}),
std::vector<std::string>({
" 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<molasses::primitive_operation>(
std::string{"syscall5"},
std::vector<std::string>({"i64", "i64", "i64", "i64", "i64", "i64"}),
std::vector<std::string>({"i64"}),
std::vector<std::string>({
" 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<molasses::primitive_operation>(
std::string{"syscall6"},
std::vector<std::string>({"i64", "i64", "i64", "i64", "i64", "i64", "i64"}),
std::vector<std::string>({"i64"}),
std::vector<std::string>({
" 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<std::string> generate_call(std::string target)
requires (architecture == architecture_t::x86_64) {
return {
" call "+target+"\n",
};
}
std::vector<std::string> generate_push_int32(int32_t target)
requires (architecture == architecture_t::x86_64) {
return {
" pushq $" +std::to_string(target)+ "\n"
};
}
std::vector<std::string> generate_label(std::string target)
requires (architecture == architecture_t::x86_64) {
return {
target+":\n"
};
}
std::vector<std::string> generate_return()
requires (architecture == architecture_t::x86_64) {
return {
" // Return to caller\n",
" addq $-8, %r10\n",
" pushq (%r10)\n",
" retq\n"
};
}
std::vector<std::string> generate_enter()
requires (architecture == architecture_t::x86_64) {
return {
" // Prepare the function stack\n",
" popq (%r10)\n"
" addq $8, %r10\n",
};
}
std::vector<std::string> initialize_stack()
requires (architecture == architecture_t::x86_64) {
std::vector<std::string> 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<std::string>{
" movq $0, %rdi\n",
" movq $60, %rax\n",
" syscall\n"
}
) {
operations.push_back(op);
}
return operations;
}
}

+ 16
- 225
src/molasses/parser_primitives.cpp View File

@ -2,180 +2,9 @@
#include <cassert>
#include <iostream>
#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<primitive_type>("i8",1));
ctx.types.push_back(std::make_shared<primitive_type>("i16",2));
ctx.types.push_back(std::make_shared<primitive_type>("i32",4));
ctx.types.push_back(std::make_shared<primitive_type>("i64",8));
ctx.types.push_back(std::make_shared<primitive_type>("u8",1));
ctx.types.push_back(std::make_shared<primitive_type>("u16",2));
ctx.types.push_back(std::make_shared<primitive_type>("u32",4));
ctx.types.push_back(std::make_shared<primitive_type>("u64",8));
return ctx;
}
parser_context register_i32_operations(parser_context ctx) {
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"+"},
std::vector<std::string>({"i32", "i32"}),
std::vector<std::string>({"i32"}),
std::vector<std::string>({
" popq %rax\n",
" popq %rbx\n",
" addl %ebx, %eax\n",
" andl $0xFFFFFFFF, %eax\n",
" pushq %rax\n"
})
)
);
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"*"},
std::vector<std::string>({"i32", "i32"}),
std::vector<std::string>({"i32"}),
std::vector<std::string>({
" popq %rax\n",
" popq %rbx\n",
" multl %ebx, %eax\n",
" andl $0xFFFFFFFF, %eax\n",
" pushq %rax\n"
})
)
);
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"-"},
std::vector<std::string>({"i32", "i32"}),
std::vector<std::string>({"i32"}),
std::vector<std::string>({
" popq %rax\n",
" popq %rbx\n",
" subl %ebx, %eax\n",
" andl $0xFFFFFFFF, %eax\n",
" pushq %rax\n"
})
)
);
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"i32-to-i64"},
std::vector<std::string>({"i32"}),
std::vector<std::string>({"i64"}),
std::vector<std::string>({
" popq %rax\n",
" movslq %rax\n",
" pushq %rax\n"
})
)
);
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"syscall1"},
std::vector<std::string>({"i64", "i64"}),
std::vector<std::string>({"i64"}),
std::vector<std::string>({
" popq %rax\n",
" popq %rdi\n",
" syscall\n",
" pushq %rax\n"
})
)
);
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"syscall2"},
std::vector<std::string>({"i64", "i64", "i64"}),
std::vector<std::string>({"i64"}),
std::vector<std::string>({
" popq %rax\n",
" popq %rdi\n",
" popq %rsi\n",
" syscall\n",
" pushq %rax\n"
})
)
);
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"syscall3"},
std::vector<std::string>({"i64", "i64", "i64", "i64"}),
std::vector<std::string>({"i64"}),
std::vector<std::string>({
" popq %rax\n",
" popq %rdi\n",
" popq %rsi\n",
" popq %rdx\n",
" syscall\n",
" pushq %rax\n"
})
)
);
ctx.operations.emplace_back(
std::make_shared<molasses::primitive_operation>(
std::string{"syscall4"},
std::vector<std::string>({"i64", "i64", "i64", "i64", "i64"}),
std::vector<std::string>({"i64"}),
std::vector<std::string>({
" 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<molasses::primitive_operation>(
std::string{"syscall5"},
std::vector<std::string>({"i64", "i64", "i64", "i64", "i64", "i64"}),
std::vector<std::string>({"i64"}),
std::vector<std::string>({
" 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<molasses::primitive_operation>(
std::string{"syscall6"},
std::vector<std::string>({"i64", "i64", "i64", "i64", "i64", "i64", "i64"}),
std::vector<std::string>({"i64"}),
std::vector<std::string>({
" 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<std::string> operator>>(std::vector<std::string> 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<std::string> 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<std::string> 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<std::string> generate_push_int32(int32_t target) requires (architecture == architecture_t::x86_64) {
return {
" pushq $" +std::to_string(target)+ "\n"
};
}
std::vector<std::string> procedure_operation::generate(const parser_context& ctx, const lexed_output& lexer_data) const
requires (architecture == architecture_t::x86_64) {
std::vector<std::string> ops;
ops.emplace_back(name()+":\n");
std::vector<std::string> procedure_operation::generate(const parser_context& ctx, const lexed_output& lexer_data) const {
std::vector<std::string> 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;
}

Loading…
Cancel
Save