|
|
@ -1,5 +1,6 @@ |
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <iostream>
|
|
|
|
#include "molasses/parser_primitives.h"
|
|
|
|
|
|
|
|
namespace molasses { |
|
|
@ -88,7 +89,27 @@ namespace molasses { |
|
|
|
|
|
|
|
return type_stack == execution_output; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> initialize_stack() { |
|
|
|
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, |
|
|
@ -159,70 +180,86 @@ namespace molasses { |
|
|
|
return std::make_pair(it, std::make_shared<procedure_operation>(name, argument_types, return_types, body)); |
|
|
|
#undef CHECK_FOR_UNEXPECTED_STREAM_END
|
|
|
|
}; |
|
|
|
|
|
|
|
auto [iterator, procedure] = parse_proc(tokens.symbols.begin()); |
|
|
|
ctx.operations.push_back(procedure); |
|
|
|
parsed_procedures.emplace_back(std::move(procedure)); |
|
|
|
|
|
|
|
|
|
|
|
auto progress = tokens.symbols.begin(); |
|
|
|
|
|
|
|
do { |
|
|
|
auto [iterator, procedure] = parse_proc(progress); |
|
|
|
ctx.operations.push_back(procedure); |
|
|
|
parsed_procedures.emplace_back(std::move(procedure)); |
|
|
|
progress = iterator; |
|
|
|
} while (progress != tokens.symbols.end()); |
|
|
|
|
|
|
|
for(auto& proc : parsed_procedures) { |
|
|
|
if(not type_check(ctx, tokens, proc->_body, proc->_args, proc->_rets)) { |
|
|
|
throw ProcedureStackError(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<std::string> generated; |
|
|
|
|
|
|
|
for(auto instr : initialize_stack()) { |
|
|
|
generated.push_back(instr); |
|
|
|
} |
|
|
|
|
|
|
|
for(auto proc : parsed_procedures) { |
|
|
|
for(auto instr : proc->generate(ctx, tokens)) { |
|
|
|
generated.push_back(instr); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for(auto line : generated) { |
|
|
|
std::cout << line; |
|
|
|
} |
|
|
|
|
|
|
|
return ctx; |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<std::string> initialize_stack() { |
|
|
|
return { |
|
|
|
".bss\n",// TODO: make threadlocal
|
|
|
|
"stack_instruction:", |
|
|
|
" .quad 0", |
|
|
|
".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", |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<std::string> generate_call(std::string target) { |
|
|
|
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> procedure_operation::generate(const parser_context& ctx) const { |
|
|
|
size_t initial_stack = 0; |
|
|
|
size_t final_stack = 0; |
|
|
|
for(const auto& elem : argument_types()) { |
|
|
|
initial_stack += ctx.lookup_type(elem)->byte_size(); |
|
|
|
} |
|
|
|
for(const auto& elem : return_types()) { |
|
|
|
final_stack += ctx.lookup_type(elem)->byte_size(); |
|
|
|
} |
|
|
|
std::vector<std::string> ops; |
|
|
|
ops.emplace_back(name()+":\n"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Return to caller
|
|
|
|
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"); |
|
|
|
|
|
|
|
return ops; |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<std::string> generate_call(std::string target) { |
|
|
|
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) { |
|
|
|
return { |
|
|
|
" pushq $" +std::to_string(target)+ "\n" |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<std::string> procedure_operation::generate(const parser_context& ctx, const lexed_output& lexer_data) const { |
|
|
|
std::vector<std::string> ops; |
|
|
|
ops.emplace_back(name()+":\n"); |
|
|
|
|
|
|
|
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); |
|
|
|
} |
|
|
|
} else if(auto op = ctx.lookup_operation(token); op) { |
|
|
|
for(auto&& elem : op->emit(ctx)) { |
|
|
|
ops.push_back(elem); |
|
|
|
} |
|
|
|
} 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"); |
|
|
|
|
|
|
|
return ops; |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<std::string> procedure_operation::emit(const parser_context& ctx) const { |
|
|
|
return generate_call(name()); |
|
|
|
} |
|
|
|
} |