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);
|
||||
}
|
||||
|
||||
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) {
|
||||
// TODO: use modr/m
|
||||
load_var(AX, subtrahend);
|
||||
|
|
3
src/ir.h
3
src/ir.h
|
@ -70,6 +70,9 @@ var lit(uint64_t lit);
|
|||
/// String literal.
|
||||
var lit_string(char* str);
|
||||
|
||||
/// Addition.
|
||||
var add(var addend1, var addend2);
|
||||
|
||||
/// Subtraction.
|
||||
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];
|
||||
};
|
||||
|
||||
struct jump_crumb {
|
||||
label label;
|
||||
uint32_t arity;
|
||||
uint32_t argument_count;
|
||||
var arguments[MAX_ARGUMENTS];
|
||||
};
|
||||
|
||||
enum crumb_type {
|
||||
BLOCK_CRUMB,
|
||||
IF_CRUMB,
|
||||
|
@ -79,7 +86,7 @@ union crumb_data {
|
|||
struct if_crumb if_;
|
||||
struct loop_crumb loop;
|
||||
struct expr_crumb expr;
|
||||
label jump;
|
||||
struct jump_crumb jump;
|
||||
};
|
||||
|
||||
struct crumb {
|
||||
|
@ -132,9 +139,16 @@ static void push_new_expr(void) {
|
|||
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;
|
||||
data.jump = label;
|
||||
data.jump.label = label.label;
|
||||
data.jump.arity = label.arity;
|
||||
data.jump.argument_count = 0;
|
||||
struct crumb crumb = {
|
||||
.type = JUMP_CRUMB,
|
||||
.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--) {
|
||||
struct crumb ctx = context[i - 1];
|
||||
switch (ctx.type) {
|
||||
case LOOP_CRUMB:
|
||||
if (name == NULL || strcmp(name, ctx.data.loop.label_name) == 0) {
|
||||
struct label_and_arity 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) {
|
||||
return ctx.data.loop.exit;
|
||||
label.label = ctx.data.loop.exit;
|
||||
label.arity = 1;
|
||||
return label;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -267,11 +286,37 @@ static label lookup_label(enum label_type type, char* name) {
|
|||
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--;
|
||||
}
|
||||
|
||||
|
||||
void reduce_expression(struct expr_crumb* exprc) {
|
||||
// TODO FIXME
|
||||
return;
|
||||
var reduce_expression(struct expr_crumb* exprc) {
|
||||
// TODO FIXME: operator precedence
|
||||
if (exprc->operator_count > 0 || exprc->argument_count > 1) {
|
||||
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) {
|
||||
|
@ -371,7 +416,7 @@ void exit_block(void) {
|
|||
case LOOP_CRUMB: {
|
||||
// unlike with `if`, there is no `exit_loop`, so we do clean-up here.
|
||||
struct loop_crumb loopc = ctx.data.loop;
|
||||
assert(loopc.state == LOOP_CLEAN);
|
||||
assert(loopc.state == LOOP_BODY);
|
||||
jump(loopc.exit, &ret);
|
||||
context_depth--;
|
||||
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;
|
||||
assert(exprc->argument_count > 0);
|
||||
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];
|
||||
context_depth--;
|
||||
ctx = &context[context_depth - 1];
|
||||
|
@ -441,9 +482,13 @@ void exit_expr(void) {
|
|||
}
|
||||
case JUMP_CRUMB: {
|
||||
// TODO FIXME: this is *completely wrong* for `next`!
|
||||
label label = ctx->data.jump;
|
||||
jump(label, &ret);
|
||||
struct jump_crumb jumpc = ctx->data.jump;
|
||||
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
|
||||
context_depth--;
|
||||
push_argument(ret);
|
||||
break;
|
||||
}
|
||||
|
@ -491,6 +536,7 @@ void exit_if(void) {
|
|||
}
|
||||
var ret;
|
||||
leave(&ret);
|
||||
context_depth--;
|
||||
push_argument(ret);
|
||||
}
|
||||
|
||||
|
@ -558,10 +604,24 @@ void exit_group(void) {
|
|||
}
|
||||
|
||||
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];
|
||||
assert(ctx->type == EXPR_CRUMB);
|
||||
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) {
|
||||
fprintf(stderr, "error: exceeded maximum number of operators in expression\n");
|
||||
exit(1);
|
||||
|
|
|
@ -21,6 +21,7 @@ symbol compile(void) {
|
|||
var sys_exit = lit(60);
|
||||
var args[2] = { sys_exit, exit_code };
|
||||
syscall(2, args);
|
||||
parse();
|
||||
return entry_point;
|
||||
}
|
||||
|
||||
|
@ -31,8 +32,6 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
open_files(argv[2], argv[1]);
|
||||
|
||||
//parse();
|
||||
|
||||
elf_executable();
|
||||
symbol entry_point = compile();
|
||||
finish_executable(entry_point);
|
||||
|
|
|
@ -192,7 +192,7 @@ void parse(void) {
|
|||
}
|
||||
break;
|
||||
case TOK_NEXT:
|
||||
push(ST_EXPR_CONT);
|
||||
push(ST_EXPR);
|
||||
if (nxt.type == TOK_LABEL) {
|
||||
next();
|
||||
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);
|
||||
}
|
||||
|
||||
void x86_inst_add_r64_r64(reg dest, reg src) {
|
||||
x86_enc_rexw_modrr(0x0, src, dest);
|
||||
}
|
||||
|
||||
void x86_inst_syscall(void) {
|
||||
const uint8_t buf[2] = { 0x0f, 0x05 };
|
||||
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_add_r64_imm8(reg dest, int8_t imm);
|
||||
void x86_inst_add_r64_r64(reg dest, reg src);
|
||||
|
||||
void x86_inst_syscall(void);
|
||||
|
||||
|
|
Loading…
Reference in New Issue