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
James T. Martin 2022-10-17 11:45:38 -07:00
parent f951e8ce08
commit 1383484e06
Signed by: james
GPG Key ID: D6FB2F9892F9B225
7 changed files with 95 additions and 21 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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