No assertions fail during codegen (lang.c) for test file.
The generated executable is still incorrect for reasons which I have not yet investigated, but this is still a step forward.master
parent
f951e8ce08
commit
1383484e06
7
src/ir.c
7
src/ir.c
|
@ -119,6 +119,13 @@ var lit_string(char* str) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var add(var addend1, var addend2) {
|
||||||
|
load_var(AX, addend1);
|
||||||
|
load_var(BX, addend2);
|
||||||
|
x86_inst_add_r64_r64(AX, BX);
|
||||||
|
return push_var(AX);
|
||||||
|
}
|
||||||
|
|
||||||
var sub(var subtrahend, var minuend) {
|
var sub(var subtrahend, var minuend) {
|
||||||
// TODO: use modr/m
|
// TODO: use modr/m
|
||||||
load_var(AX, subtrahend);
|
load_var(AX, subtrahend);
|
||||||
|
|
3
src/ir.h
3
src/ir.h
|
@ -70,6 +70,9 @@ var lit(uint64_t lit);
|
||||||
/// String literal.
|
/// String literal.
|
||||||
var lit_string(char* str);
|
var lit_string(char* str);
|
||||||
|
|
||||||
|
/// Addition.
|
||||||
|
var add(var addend1, var addend2);
|
||||||
|
|
||||||
/// Subtraction.
|
/// Subtraction.
|
||||||
var sub(var subtrahend, var minuend);
|
var sub(var subtrahend, var minuend);
|
||||||
|
|
||||||
|
|
96
src/lang.c
96
src/lang.c
|
@ -66,6 +66,13 @@ struct expr_crumb {
|
||||||
enum operator_ operators[MAX_OPERATORS];
|
enum operator_ operators[MAX_OPERATORS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct jump_crumb {
|
||||||
|
label label;
|
||||||
|
uint32_t arity;
|
||||||
|
uint32_t argument_count;
|
||||||
|
var arguments[MAX_ARGUMENTS];
|
||||||
|
};
|
||||||
|
|
||||||
enum crumb_type {
|
enum crumb_type {
|
||||||
BLOCK_CRUMB,
|
BLOCK_CRUMB,
|
||||||
IF_CRUMB,
|
IF_CRUMB,
|
||||||
|
@ -79,7 +86,7 @@ union crumb_data {
|
||||||
struct if_crumb if_;
|
struct if_crumb if_;
|
||||||
struct loop_crumb loop;
|
struct loop_crumb loop;
|
||||||
struct expr_crumb expr;
|
struct expr_crumb expr;
|
||||||
label jump;
|
struct jump_crumb jump;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct crumb {
|
struct crumb {
|
||||||
|
@ -132,9 +139,16 @@ static void push_new_expr(void) {
|
||||||
push(crumb);
|
push(crumb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void push_new_jump(label label) {
|
struct label_and_arity {
|
||||||
|
label label;
|
||||||
|
uint32_t arity;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void push_new_jump(struct label_and_arity label) {
|
||||||
union crumb_data data;
|
union crumb_data data;
|
||||||
data.jump = label;
|
data.jump.label = label.label;
|
||||||
|
data.jump.arity = label.arity;
|
||||||
|
data.jump.argument_count = 0;
|
||||||
struct crumb crumb = {
|
struct crumb crumb = {
|
||||||
.type = JUMP_CRUMB,
|
.type = JUMP_CRUMB,
|
||||||
.data = data,
|
.data = data,
|
||||||
|
@ -241,17 +255,22 @@ static const char* label_type_name(enum label_type type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static label lookup_label(enum label_type type, char* name) {
|
static struct label_and_arity lookup_label(enum label_type type, char* name) {
|
||||||
for (uint32_t i = context_depth; i > 0; i--) {
|
for (uint32_t i = context_depth; i > 0; i--) {
|
||||||
struct crumb ctx = context[i - 1];
|
struct crumb ctx = context[i - 1];
|
||||||
switch (ctx.type) {
|
switch (ctx.type) {
|
||||||
case LOOP_CRUMB:
|
case LOOP_CRUMB:
|
||||||
if (name == NULL || strcmp(name, ctx.data.loop.label_name) == 0) {
|
if (name == NULL || strcmp(name, ctx.data.loop.label_name) == 0) {
|
||||||
|
struct label_and_arity label;
|
||||||
if (type == NEXT_LABEL) {
|
if (type == NEXT_LABEL) {
|
||||||
return ctx.data.loop.next;
|
label.label = ctx.data.loop.next;
|
||||||
|
label.arity = ctx.data.loop.assignment_count;
|
||||||
|
return label;
|
||||||
}
|
}
|
||||||
if (type == EXIT_LABEL) {
|
if (type == EXIT_LABEL) {
|
||||||
return ctx.data.loop.exit;
|
label.label = ctx.data.loop.exit;
|
||||||
|
label.arity = 1;
|
||||||
|
return label;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -267,11 +286,37 @@ static label lookup_label(enum label_type type, char* name) {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reduce_expression_binop(struct expr_crumb* exprc, var (*emit)(var arg1, var arg2)) {
|
||||||
|
assert(exprc->argument_count >= 2);
|
||||||
|
var arg1 = exprc->arguments[0];
|
||||||
|
var arg2 = exprc->arguments[1];
|
||||||
|
exprc->arguments[0] = emit(arg1, arg2);
|
||||||
|
memmove(&exprc->arguments[1], &exprc->arguments[2], exprc->argument_count - 2);
|
||||||
|
exprc->argument_count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
var reduce_expression(struct expr_crumb* exprc) {
|
||||||
void reduce_expression(struct expr_crumb* exprc) {
|
// TODO FIXME: operator precedence
|
||||||
// TODO FIXME
|
if (exprc->operator_count > 0 || exprc->argument_count > 1) {
|
||||||
return;
|
fprintf(stderr, "warning: expression reduction may be incorrect\n");
|
||||||
|
//exit(1);
|
||||||
|
}
|
||||||
|
for (uint32_t op_ix = 0; op_ix < exprc->operator_count; op_ix++) {
|
||||||
|
switch (exprc->operators[op_ix]) {
|
||||||
|
case OP_ADD:
|
||||||
|
reduce_expression_binop(exprc, add);
|
||||||
|
break;
|
||||||
|
case OP_SUB:
|
||||||
|
reduce_expression_binop(exprc, sub);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "error: operator not implemented: %i", exprc->operators[op_ix]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exprc->operator_count = 0;
|
||||||
|
assert(exprc->argument_count == 1);
|
||||||
|
return exprc->arguments[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
void enter_block(void) {
|
void enter_block(void) {
|
||||||
|
@ -371,7 +416,7 @@ void exit_block(void) {
|
||||||
case LOOP_CRUMB: {
|
case LOOP_CRUMB: {
|
||||||
// unlike with `if`, there is no `exit_loop`, so we do clean-up here.
|
// unlike with `if`, there is no `exit_loop`, so we do clean-up here.
|
||||||
struct loop_crumb loopc = ctx.data.loop;
|
struct loop_crumb loopc = ctx.data.loop;
|
||||||
assert(loopc.state == LOOP_CLEAN);
|
assert(loopc.state == LOOP_BODY);
|
||||||
jump(loopc.exit, &ret);
|
jump(loopc.exit, &ret);
|
||||||
context_depth--;
|
context_depth--;
|
||||||
for (uint32_t i = 0; i < loopc.assignment_count; i++) {
|
for (uint32_t i = 0; i < loopc.assignment_count; i++) {
|
||||||
|
@ -396,10 +441,6 @@ void exit_expr(void) {
|
||||||
struct expr_crumb* exprc = &ctx->data.expr;
|
struct expr_crumb* exprc = &ctx->data.expr;
|
||||||
assert(exprc->argument_count > 0);
|
assert(exprc->argument_count > 0);
|
||||||
reduce_expression(exprc);
|
reduce_expression(exprc);
|
||||||
if (exprc->operator_count > 0 || exprc->argument_count > 1) {
|
|
||||||
fprintf(stderr, "error: failed to reduce expression\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
var ret = exprc->arguments[0];
|
var ret = exprc->arguments[0];
|
||||||
context_depth--;
|
context_depth--;
|
||||||
ctx = &context[context_depth - 1];
|
ctx = &context[context_depth - 1];
|
||||||
|
@ -441,9 +482,13 @@ void exit_expr(void) {
|
||||||
}
|
}
|
||||||
case JUMP_CRUMB: {
|
case JUMP_CRUMB: {
|
||||||
// TODO FIXME: this is *completely wrong* for `next`!
|
// TODO FIXME: this is *completely wrong* for `next`!
|
||||||
label label = ctx->data.jump;
|
struct jump_crumb jumpc = ctx->data.jump;
|
||||||
jump(label, &ret);
|
fprintf(stderr, "args: %i, arity: %i\n", jumpc.argument_count, jumpc.arity);
|
||||||
|
assert(jumpc.argument_count + 1 == jumpc.arity);
|
||||||
|
jumpc.arguments[jumpc.argument_count] = ret;
|
||||||
|
jump(jumpc.label, jumpc.arguments);
|
||||||
// TODO: better way to handle returning impossible value
|
// TODO: better way to handle returning impossible value
|
||||||
|
context_depth--;
|
||||||
push_argument(ret);
|
push_argument(ret);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -491,6 +536,7 @@ void exit_if(void) {
|
||||||
}
|
}
|
||||||
var ret;
|
var ret;
|
||||||
leave(&ret);
|
leave(&ret);
|
||||||
|
context_depth--;
|
||||||
push_argument(ret);
|
push_argument(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,10 +604,24 @@ void exit_group(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void expr_op(enum operator_ op) {
|
void expr_op(enum operator_ op) {
|
||||||
printf("** expr_op %ir\n", op);
|
printf("** expr_op %i\n", op);
|
||||||
struct crumb* ctx = &context[context_depth - 1];
|
struct crumb* ctx = &context[context_depth - 1];
|
||||||
assert(ctx->type == EXPR_CRUMB);
|
assert(ctx->type == EXPR_CRUMB);
|
||||||
struct expr_crumb* exprc = &ctx->data.expr;
|
struct expr_crumb* exprc = &ctx->data.expr;
|
||||||
|
if (op == OP_JUXT && context_depth > 1) {
|
||||||
|
// HACK: should handle continuations separately from expressions
|
||||||
|
struct crumb* ctx2 = &context[context_depth - 2];
|
||||||
|
if (ctx2->type == JUMP_CRUMB) {
|
||||||
|
struct jump_crumb* jumpc = &ctx2->data.jump;
|
||||||
|
var ret = reduce_expression(exprc);
|
||||||
|
assert(jumpc->argument_count < MAX_ARGUMENTS);
|
||||||
|
jumpc->arguments[jumpc->argument_count] = ret;
|
||||||
|
jumpc->argument_count++;
|
||||||
|
context_depth--;
|
||||||
|
push_new_expr();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (exprc->operator_count > MAX_OPERATORS) {
|
if (exprc->operator_count > MAX_OPERATORS) {
|
||||||
fprintf(stderr, "error: exceeded maximum number of operators in expression\n");
|
fprintf(stderr, "error: exceeded maximum number of operators in expression\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
|
@ -21,6 +21,7 @@ symbol compile(void) {
|
||||||
var sys_exit = lit(60);
|
var sys_exit = lit(60);
|
||||||
var args[2] = { sys_exit, exit_code };
|
var args[2] = { sys_exit, exit_code };
|
||||||
syscall(2, args);
|
syscall(2, args);
|
||||||
|
parse();
|
||||||
return entry_point;
|
return entry_point;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,8 +32,6 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
open_files(argv[2], argv[1]);
|
open_files(argv[2], argv[1]);
|
||||||
|
|
||||||
//parse();
|
|
||||||
|
|
||||||
elf_executable();
|
elf_executable();
|
||||||
symbol entry_point = compile();
|
symbol entry_point = compile();
|
||||||
finish_executable(entry_point);
|
finish_executable(entry_point);
|
||||||
|
|
|
@ -192,7 +192,7 @@ void parse(void) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TOK_NEXT:
|
case TOK_NEXT:
|
||||||
push(ST_EXPR_CONT);
|
push(ST_EXPR);
|
||||||
if (nxt.type == TOK_LABEL) {
|
if (nxt.type == TOK_LABEL) {
|
||||||
next();
|
next();
|
||||||
expr_next(nxt.data.label);
|
expr_next(nxt.data.label);
|
||||||
|
|
|
@ -269,6 +269,10 @@ void x86_inst_add_r64_imm8(reg dest, int8_t imm) {
|
||||||
x86_enc_rexw_modxm_imm8(0x83, 0, dest, (uint8_t) imm);
|
x86_enc_rexw_modxm_imm8(0x83, 0, dest, (uint8_t) imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void x86_inst_add_r64_r64(reg dest, reg src) {
|
||||||
|
x86_enc_rexw_modrr(0x0, src, dest);
|
||||||
|
}
|
||||||
|
|
||||||
void x86_inst_syscall(void) {
|
void x86_inst_syscall(void) {
|
||||||
const uint8_t buf[2] = { 0x0f, 0x05 };
|
const uint8_t buf[2] = { 0x0f, 0x05 };
|
||||||
append_data(2, buf);
|
append_data(2, buf);
|
||||||
|
|
|
@ -55,6 +55,7 @@ void x86_inst_sub_r64_imm(reg dest, int32_t imm);
|
||||||
void x86_inst_sub_r64_r64(reg dest, reg src);
|
void x86_inst_sub_r64_r64(reg dest, reg src);
|
||||||
|
|
||||||
void x86_inst_add_r64_imm8(reg dest, int8_t imm);
|
void x86_inst_add_r64_imm8(reg dest, int8_t imm);
|
||||||
|
void x86_inst_add_r64_r64(reg dest, reg src);
|
||||||
|
|
||||||
void x86_inst_syscall(void);
|
void x86_inst_syscall(void);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue