mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-01 19:38:06 +03:00
jaf: loops
This commit is contained in:
@@ -370,6 +370,7 @@ struct jaf_block_item *jaf_for_loop(struct jaf_block *init, struct jaf_block_ite
|
||||
item->for_loop.test = test->expr;
|
||||
item->for_loop.after = after;
|
||||
item->for_loop.body = body;
|
||||
free(test);
|
||||
return item;
|
||||
}
|
||||
|
||||
|
||||
+261
-142
@@ -34,6 +34,23 @@ int yyparse(void);
|
||||
struct ain *jaf_ain_out;
|
||||
struct jaf_block *jaf_toplevel;
|
||||
|
||||
/*
|
||||
* NOTE: We need to pass some state between calls to handle
|
||||
* break/continue.
|
||||
*/
|
||||
struct loop_state {
|
||||
size_t loop_addr;
|
||||
size_t nr_breaks;
|
||||
uint32_t *breaks;
|
||||
};
|
||||
|
||||
struct compiler_state {
|
||||
struct ain *ain;
|
||||
struct buffer out;
|
||||
size_t nr_loops;
|
||||
struct loop_state *loops;
|
||||
};
|
||||
|
||||
int sym_type(char *name)
|
||||
{
|
||||
char *u = encode_text_to_input_format(name);
|
||||
@@ -46,32 +63,50 @@ int sym_type(char *name)
|
||||
return IDENTIFIER;
|
||||
}
|
||||
|
||||
static void write_opcode(struct buffer *out, uint16_t opcode)
|
||||
static void start_loop(struct compiler_state *state)
|
||||
{
|
||||
buffer_write_int16(out, opcode);
|
||||
state->loops = xrealloc_array(state->loops, state->nr_loops, state->nr_loops+1, sizeof(struct loop_state));
|
||||
state->loops[state->nr_loops].loop_addr = state->out.index;
|
||||
state->loops[state->nr_loops].nr_breaks = 0;
|
||||
state->loops[state->nr_loops].breaks = NULL;
|
||||
state->nr_loops++;
|
||||
}
|
||||
|
||||
static void write_argument(struct buffer *out, uint32_t arg)
|
||||
static void end_loop(struct compiler_state *state)
|
||||
{
|
||||
buffer_write_int32(out, arg);
|
||||
struct loop_state *loop = &state->loops[--state->nr_loops];
|
||||
for (size_t i = 0; i < loop->nr_breaks; i++) {
|
||||
buffer_write_int32_at(&state->out, loop->breaks[i], state->out.index);
|
||||
}
|
||||
free(loop->breaks);
|
||||
}
|
||||
|
||||
static void write_instruction0(struct buffer *out, uint16_t opcode)
|
||||
static void write_opcode(struct compiler_state *state, uint16_t opcode)
|
||||
{
|
||||
write_opcode(out, opcode);
|
||||
buffer_write_int16(&state->out, opcode);
|
||||
}
|
||||
|
||||
static void write_instruction1(struct buffer *out, uint16_t opcode, uint32_t arg0)
|
||||
static void write_argument(struct compiler_state *state, uint32_t arg)
|
||||
{
|
||||
write_opcode(out, opcode);
|
||||
write_argument(out, arg0);
|
||||
buffer_write_int32(&state->out, arg);
|
||||
}
|
||||
|
||||
static void write_instruction2(struct buffer *out, uint16_t opcode, uint32_t arg0, uint32_t arg1)
|
||||
static void write_instruction0(struct compiler_state *state, uint16_t opcode)
|
||||
{
|
||||
write_opcode(out, opcode);
|
||||
write_argument(out, arg0);
|
||||
write_argument(out, arg1);
|
||||
write_opcode(state, opcode);
|
||||
}
|
||||
|
||||
static void write_instruction1(struct compiler_state *state, uint16_t opcode, uint32_t arg0)
|
||||
{
|
||||
write_opcode(state, opcode);
|
||||
write_argument(state, arg0);
|
||||
}
|
||||
|
||||
static void write_instruction2(struct compiler_state *state, uint16_t opcode, uint32_t arg0, uint32_t arg1)
|
||||
{
|
||||
write_opcode(state, opcode);
|
||||
write_argument(state, arg0);
|
||||
write_argument(state, arg1);
|
||||
}
|
||||
|
||||
static uint32_t flo2int(float f)
|
||||
@@ -139,38 +174,39 @@ static enum opcode jaf_op_to_opcode(enum jaf_operator op, enum jaf_type type)
|
||||
}
|
||||
}
|
||||
|
||||
static void compile_block(struct ain *ain, struct buffer *out, struct jaf_block *block);
|
||||
static void compile_expression(struct ain *ain, struct buffer *out, struct jaf_expression *expr);
|
||||
static void compile_block(struct compiler_state *state, struct jaf_block *block);
|
||||
static void compile_statement(struct compiler_state *state, struct jaf_block_item *item);
|
||||
static void compile_expression(struct compiler_state *state, struct jaf_expression *expr);
|
||||
|
||||
static void compile_identifier(possibly_unused struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
static void compile_identifier(struct compiler_state *state, struct jaf_expression *expr)
|
||||
{
|
||||
if (expr->ident.var_type == AIN_VAR_LOCAL) {
|
||||
write_instruction0(out, PUSHLOCALPAGE);
|
||||
write_instruction0(state, PUSHLOCALPAGE);
|
||||
} else if (expr->ident.var_type == AIN_VAR_GLOBAL) {
|
||||
write_instruction0(out, PUSHGLOBALPAGE);
|
||||
write_instruction0(state, PUSHGLOBALPAGE);
|
||||
} else {
|
||||
ERROR("Invalid variable type");
|
||||
}
|
||||
write_instruction1(out, PUSH, expr->ident.var_no);
|
||||
write_instruction0(out, REF);
|
||||
write_instruction1(state, PUSH, expr->ident.var_no);
|
||||
write_instruction0(state, REF);
|
||||
}
|
||||
|
||||
static void compile_unary(struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
static void compile_unary(struct compiler_state *state, struct jaf_expression *expr)
|
||||
{
|
||||
switch (expr->op) {
|
||||
case JAF_AMPERSAND:
|
||||
ERROR("Function types not supported");
|
||||
case JAF_UNARY_PLUS:
|
||||
compile_expression(ain, out, expr->expr);
|
||||
compile_expression(state, expr->expr);
|
||||
break;
|
||||
case JAF_UNARY_MINUS:
|
||||
write_instruction0(out, INV);
|
||||
write_instruction0(state, INV);
|
||||
break;
|
||||
case JAF_BIT_NOT:
|
||||
write_instruction0(out, COMPL);
|
||||
write_instruction0(state, COMPL);
|
||||
break;
|
||||
case JAF_LOG_NOT:
|
||||
write_instruction0(out, NOT);
|
||||
write_instruction0(state, NOT);
|
||||
break;
|
||||
case JAF_PRE_INC:
|
||||
case JAF_PRE_DEC:
|
||||
@@ -182,17 +218,17 @@ static void compile_unary(struct ain *ain, struct buffer *out, struct jaf_expres
|
||||
}
|
||||
}
|
||||
|
||||
static void compile_lvalue(possibly_unused struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
static void compile_lvalue(struct compiler_state *state, struct jaf_expression *expr)
|
||||
{
|
||||
if (expr->type == JAF_EXP_IDENTIFIER) {
|
||||
if (expr->ident.var_type == AIN_VAR_GLOBAL) {
|
||||
write_instruction0(out, PUSHGLOBALPAGE);
|
||||
write_instruction0(state, PUSHGLOBALPAGE);
|
||||
} else if (expr->ident.var_type == AIN_VAR_LOCAL) {
|
||||
write_instruction0(out, PUSHLOCALPAGE);
|
||||
write_instruction0(state, PUSHLOCALPAGE);
|
||||
} else {
|
||||
ERROR("Invalid variable type as lvalue");
|
||||
}
|
||||
write_instruction1(out, PUSH, expr->ident.var_no);
|
||||
write_instruction1(state, PUSH, expr->ident.var_no);
|
||||
} else if (expr->type == JAF_EXP_MEMBER) {
|
||||
ERROR("struct member lvalues not supported");
|
||||
} else {
|
||||
@@ -200,7 +236,7 @@ static void compile_lvalue(possibly_unused struct ain *ain, struct buffer *out,
|
||||
}
|
||||
}
|
||||
|
||||
static void compile_binary(struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
static void compile_binary(struct compiler_state *state, struct jaf_expression *expr)
|
||||
{
|
||||
size_t addr[3];
|
||||
switch (expr->op) {
|
||||
@@ -220,39 +256,39 @@ static void compile_binary(struct ain *ain, struct buffer *out, struct jaf_expre
|
||||
case JAF_BIT_XOR:
|
||||
case JAF_BIT_IOR:
|
||||
assert(expr->lhs->value_type.type == expr->rhs->value_type.type);
|
||||
compile_expression(ain, out, expr->lhs);
|
||||
compile_expression(ain, out, expr->rhs);
|
||||
write_instruction0(out, jaf_op_to_opcode(expr->op, expr->value_type.type));
|
||||
compile_expression(state, expr->lhs);
|
||||
compile_expression(state, expr->rhs);
|
||||
write_instruction0(state, jaf_op_to_opcode(expr->op, expr->value_type.type));
|
||||
break;
|
||||
case JAF_LOG_AND:
|
||||
compile_expression(ain, out, expr->lhs);
|
||||
addr[0] = out->index + 2;
|
||||
write_instruction1(out, IFZ, 0);
|
||||
compile_expression(ain, out, expr->rhs);
|
||||
addr[1] = out->index + 2;
|
||||
write_instruction1(out, IFZ, 0);
|
||||
write_instruction1(out, PUSH, 1);
|
||||
addr[2] = out->index + 2;
|
||||
write_instruction1(out, JUMP, 0);
|
||||
buffer_write_int32_at(out, addr[0], out->index);
|
||||
buffer_write_int32_at(out, addr[1], out->index);
|
||||
write_instruction1(out, PUSH, 0);
|
||||
buffer_write_int32_at(out, addr[2], out->index);
|
||||
compile_expression(state, expr->lhs);
|
||||
addr[0] = state->out.index + 2;
|
||||
write_instruction1(state, IFZ, 0);
|
||||
compile_expression(state, expr->rhs);
|
||||
addr[1] = state->out.index + 2;
|
||||
write_instruction1(state, IFZ, 0);
|
||||
write_instruction1(state, PUSH, 1);
|
||||
addr[2] = state->out.index + 2;
|
||||
write_instruction1(state, JUMP, 0);
|
||||
buffer_write_int32_at(&state->out, addr[0], state->out.index);
|
||||
buffer_write_int32_at(&state->out, addr[1], state->out.index);
|
||||
write_instruction1(state, PUSH, 0);
|
||||
buffer_write_int32_at(&state->out, addr[2], state->out.index);
|
||||
break;
|
||||
case JAF_LOG_OR:
|
||||
compile_expression(ain, out, expr->lhs);
|
||||
addr[0] = out->index + 2;
|
||||
write_instruction1(out, IFNZ, 0);
|
||||
compile_expression(ain, out, expr->rhs);
|
||||
addr[1] = out->index + 2;
|
||||
write_instruction1(out, IFNZ, 0);
|
||||
write_instruction1(out, PUSH, 0);
|
||||
addr[2] = out->index + 2;
|
||||
write_instruction1(out, JUMP, 0);
|
||||
buffer_write_int32_at(out, addr[0], out->index);
|
||||
buffer_write_int32_at(out, addr[1], out->index);
|
||||
write_instruction1(out, PUSH, 1);
|
||||
buffer_write_int32_at(out, addr[2], out->index);
|
||||
compile_expression(state, expr->lhs);
|
||||
addr[0] = state->out.index + 2;
|
||||
write_instruction1(state, IFNZ, 0);
|
||||
compile_expression(state, expr->rhs);
|
||||
addr[1] = state->out.index + 2;
|
||||
write_instruction1(state, IFNZ, 0);
|
||||
write_instruction1(state, PUSH, 0);
|
||||
addr[2] = state->out.index + 2;
|
||||
write_instruction1(state, JUMP, 0);
|
||||
buffer_write_int32_at(&state->out, addr[0], state->out.index);
|
||||
buffer_write_int32_at(&state->out, addr[1], state->out.index);
|
||||
write_instruction1(state, PUSH, 1);
|
||||
buffer_write_int32_at(&state->out, addr[2], state->out.index);
|
||||
break;
|
||||
case JAF_ASSIGN:
|
||||
case JAF_MUL_ASSIGN:
|
||||
@@ -266,55 +302,55 @@ static void compile_binary(struct ain *ain, struct buffer *out, struct jaf_expre
|
||||
case JAF_XOR_ASSIGN:
|
||||
case JAF_OR_ASSIGN:
|
||||
case JAF_REF_ASSIGN:
|
||||
compile_lvalue(ain, out, expr->lhs);
|
||||
compile_expression(ain, out, expr->rhs);
|
||||
write_instruction0(out, jaf_op_to_opcode(expr->op, expr->value_type.type));
|
||||
compile_lvalue(state, expr->lhs);
|
||||
compile_expression(state, expr->rhs);
|
||||
write_instruction0(state, jaf_op_to_opcode(expr->op, expr->value_type.type));
|
||||
break;
|
||||
default:
|
||||
ERROR("Invalid binary operator");
|
||||
}
|
||||
}
|
||||
|
||||
static void compile_ternary(struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
static void compile_ternary(struct compiler_state *state, struct jaf_expression *expr)
|
||||
{
|
||||
ERROR("Ternary operator not supported");
|
||||
}
|
||||
|
||||
static void compile_funcall(struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
static void compile_funcall(struct compiler_state *state, struct jaf_expression *expr)
|
||||
{
|
||||
for (size_t i = 0; i < expr->call.args->nr_items; i++) {
|
||||
compile_expression(ain, out, expr->call.args->items[i]);
|
||||
compile_expression(state, expr->call.args->items[i]);
|
||||
}
|
||||
write_instruction1(out, CALLFUNC, expr->call.func_no);
|
||||
write_instruction1(state, CALLFUNC, expr->call.func_no);
|
||||
}
|
||||
|
||||
static void compile_cast(struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
static void compile_cast(struct compiler_state *state, struct jaf_expression *expr)
|
||||
{
|
||||
enum jaf_type src_type = expr->cast.expr->value_type.type;
|
||||
enum jaf_type dst_type = expr->cast.type;
|
||||
compile_expression(ain, out, expr->cast.expr);
|
||||
compile_expression(state, expr->cast.expr);
|
||||
|
||||
if (src_type == dst_type)
|
||||
return;
|
||||
if (src_type == JAF_INT) {
|
||||
if (dst_type == JAF_FLOAT) {
|
||||
write_instruction0(out, ITOF);
|
||||
write_instruction0(state, ITOF);
|
||||
} else if (dst_type == JAF_STRING) {
|
||||
write_instruction0(out, I_STRING);
|
||||
write_instruction0(state, I_STRING);
|
||||
} else {
|
||||
goto invalid_cast;
|
||||
}
|
||||
} else if (src_type == JAF_FLOAT) {
|
||||
if (dst_type == JAF_INT) {
|
||||
write_instruction0(out, FTOI);
|
||||
write_instruction0(state, FTOI);
|
||||
} else if (dst_type == JAF_STRING) {
|
||||
write_instruction0(out, FTOS);
|
||||
write_instruction0(state, FTOS);
|
||||
} else {
|
||||
goto invalid_cast;
|
||||
}
|
||||
} else if (src_type == JAF_STRING) {
|
||||
if (dst_type == JAF_INT) {
|
||||
write_instruction0(out, STOI);
|
||||
write_instruction0(state, STOI);
|
||||
} else {
|
||||
goto invalid_cast;
|
||||
}
|
||||
@@ -324,47 +360,47 @@ invalid_cast:
|
||||
ERROR("Unsupported cast: %s to %s", jaf_typestr(src_type), jaf_typestr(dst_type));
|
||||
}
|
||||
|
||||
static void compile_member(struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
static void compile_member(struct compiler_state *state, struct jaf_expression *expr)
|
||||
{
|
||||
ERROR("struct member access not supported");
|
||||
}
|
||||
|
||||
static void compile_expression(struct ain *ain, struct buffer *out, struct jaf_expression *expr)
|
||||
static void compile_expression(struct compiler_state *state, struct jaf_expression *expr)
|
||||
{
|
||||
switch (expr->type) {
|
||||
case JAF_EXP_VOID:
|
||||
break;
|
||||
case JAF_EXP_INT:
|
||||
write_instruction1(out, PUSH, expr->i);
|
||||
write_instruction1(state, PUSH, expr->i);
|
||||
break;
|
||||
case JAF_EXP_FLOAT:
|
||||
write_instruction1(out, F_PUSH, flo2int(expr->f));
|
||||
write_instruction1(state, F_PUSH, flo2int(expr->f));
|
||||
break;
|
||||
case JAF_EXP_STRING:
|
||||
ERROR("strings not supported");
|
||||
case JAF_EXP_IDENTIFIER:
|
||||
compile_identifier(ain, out, expr);
|
||||
compile_identifier(state, expr);
|
||||
break;
|
||||
case JAF_EXP_UNARY:
|
||||
compile_unary(ain, out, expr);
|
||||
compile_unary(state, expr);
|
||||
break;
|
||||
case JAF_EXP_BINARY:
|
||||
compile_binary(ain, out, expr);
|
||||
compile_binary(state, expr);
|
||||
break;
|
||||
case JAF_EXP_TERNARY:
|
||||
compile_ternary(ain, out, expr);
|
||||
compile_ternary(state, expr);
|
||||
break;
|
||||
//case JAF_EXP_SUBSCRIPT:
|
||||
//compile_subscript(ain, out, expr);
|
||||
//break;
|
||||
case JAF_EXP_FUNCALL:
|
||||
compile_funcall(ain, out, expr);
|
||||
compile_funcall(state, expr);
|
||||
break;
|
||||
case JAF_EXP_CAST:
|
||||
compile_cast(ain, out, expr);
|
||||
compile_cast(state, expr);
|
||||
break;
|
||||
case JAF_EXP_MEMBER:
|
||||
compile_member(ain, out, expr);
|
||||
compile_member(state, expr);
|
||||
break;
|
||||
//case JAF_EXP_SEQ:
|
||||
//compile_seq(ain, out, expr);
|
||||
@@ -372,32 +408,32 @@ static void compile_expression(struct ain *ain, struct buffer *out, struct jaf_e
|
||||
}
|
||||
}
|
||||
|
||||
static void compile_vardecl(struct ain *ain, struct buffer *out, struct jaf_declaration *decl)
|
||||
static void compile_vardecl(struct compiler_state *state, struct jaf_declaration *decl)
|
||||
{
|
||||
switch (decl->type->type) {
|
||||
case JAF_VOID:
|
||||
ERROR("void variable declaration");
|
||||
case JAF_INT:
|
||||
write_instruction0(out, PUSHLOCALPAGE);
|
||||
write_instruction1(out, PUSH, decl->var_no);
|
||||
write_instruction0(state, PUSHLOCALPAGE);
|
||||
write_instruction1(state, PUSH, decl->var_no);
|
||||
if (decl->init) {
|
||||
compile_expression(ain, out, decl->init);
|
||||
compile_expression(state, decl->init);
|
||||
} else {
|
||||
write_instruction1(out, PUSH, 0);
|
||||
write_instruction1(state, PUSH, 0);
|
||||
}
|
||||
write_instruction0(out, ASSIGN);
|
||||
write_instruction0(out, POP);
|
||||
write_instruction0(state, ASSIGN);
|
||||
write_instruction0(state, POP);
|
||||
break;
|
||||
case JAF_FLOAT:
|
||||
write_instruction0(out, PUSHLOCALPAGE);
|
||||
write_instruction1(out, PUSH, decl->var_no);
|
||||
write_instruction0(state, PUSHLOCALPAGE);
|
||||
write_instruction1(state, PUSH, decl->var_no);
|
||||
if (decl->init) {
|
||||
compile_expression(ain, out, decl->init);
|
||||
compile_expression(state, decl->init);
|
||||
} else {
|
||||
write_instruction1(out, F_PUSH, 0);
|
||||
write_instruction1(state, F_PUSH, 0);
|
||||
}
|
||||
write_instruction0(out, F_ASSIGN);
|
||||
write_instruction0(out, POP);
|
||||
write_instruction0(state, F_ASSIGN);
|
||||
write_instruction0(state, POP);
|
||||
break;
|
||||
case JAF_STRING:
|
||||
ERROR("strings not supported");
|
||||
@@ -413,12 +449,103 @@ static void compile_vardecl(struct ain *ain, struct buffer *out, struct jaf_decl
|
||||
}
|
||||
}
|
||||
|
||||
static void compile_statement(struct ain *ain, struct buffer *out, struct jaf_block_item *item)
|
||||
static void compile_if(struct compiler_state *state, struct jaf_expression *test, struct jaf_block_item *then, struct jaf_block_item *alt)
|
||||
{
|
||||
uint32_t addr[3];
|
||||
compile_expression(state, test);
|
||||
addr[0] = state->out.index + 2;
|
||||
write_instruction1(state, IFNZ, 0);
|
||||
addr[1] = state->out.index + 2;
|
||||
write_instruction1(state, JUMP, 0);
|
||||
buffer_write_int32_at(&state->out, addr[0], state->out.index);
|
||||
compile_statement(state, then);
|
||||
if (alt) {
|
||||
addr[2] = state->out.index + 2;
|
||||
write_instruction1(state, JUMP, 0);
|
||||
buffer_write_int32_at(&state->out, addr[1], state->out.index);
|
||||
compile_statement(state, alt);
|
||||
buffer_write_int32_at(&state->out, addr[2], state->out.index);
|
||||
} else {
|
||||
buffer_write_int32_at(&state->out, addr[1], state->out.index);
|
||||
}
|
||||
}
|
||||
|
||||
static void compile_while(struct compiler_state *state, struct jaf_expression *test, struct jaf_block_item *body)
|
||||
{
|
||||
uint32_t addr;
|
||||
// loop test
|
||||
start_loop(state);
|
||||
compile_expression(state, test);
|
||||
addr = state->out.index + 2;
|
||||
write_instruction1(state, IFZ, 0);
|
||||
// loop body
|
||||
compile_statement(state, body);
|
||||
write_instruction1(state, JUMP, state->loops[state->nr_loops-1].loop_addr);
|
||||
// loop end
|
||||
buffer_write_int32_at(&state->out, addr, state->out.index);
|
||||
end_loop(state);
|
||||
}
|
||||
|
||||
static void compile_do_while(struct compiler_state *state, struct jaf_expression *test, struct jaf_block_item *body)
|
||||
{
|
||||
uint32_t addr[2];
|
||||
// skip loop test
|
||||
addr[0] = state->out.index + 2;
|
||||
write_instruction1(state, JUMP, 0);
|
||||
// loop test
|
||||
start_loop(state);
|
||||
compile_expression(state, test);
|
||||
addr[1] = state->out.index + 2; // address of address of loop end
|
||||
write_instruction1(state, IFZ, 0);
|
||||
// loop body
|
||||
buffer_write_int32_at(&state->out, addr[0], state->out.index);
|
||||
compile_statement(state, body);
|
||||
write_instruction1(state, JUMP, state->loops[state->nr_loops-1].loop_addr);
|
||||
// loop end
|
||||
buffer_write_int32_at(&state->out, addr[1], state->out.index);
|
||||
end_loop(state);
|
||||
}
|
||||
|
||||
static void compile_for(struct compiler_state *state, struct jaf_block *init, struct jaf_expression *test, struct jaf_expression *after, struct jaf_block_item *body)
|
||||
{
|
||||
uint32_t addr[3];
|
||||
// loop init
|
||||
compile_block(state, init);
|
||||
// loop test
|
||||
addr[0] = state->out.index; // address of loop test
|
||||
compile_expression(state, test);
|
||||
addr[1] = state->out.index + 2; // address of address of loop end
|
||||
write_instruction1(state, IFZ, 0);
|
||||
addr[2] = state->out.index + 2; // address of address of loop body
|
||||
write_instruction1(state, JUMP, 0);
|
||||
// loop increment
|
||||
start_loop(state);
|
||||
compile_expression(state, after);
|
||||
write_instruction1(state, JUMP, addr[0]);
|
||||
// loop body
|
||||
buffer_write_int32_at(&state->out, addr[2], state->out.index);
|
||||
compile_statement(state, body);
|
||||
write_instruction1(state, JUMP, state->loops[state->nr_loops-1].loop_addr);
|
||||
// loop end
|
||||
buffer_write_int32_at(&state->out, addr[1], state->out.index);
|
||||
end_loop(state);
|
||||
}
|
||||
|
||||
static void compile_break(struct compiler_state *state)
|
||||
{
|
||||
if (state->nr_loops == 0)
|
||||
ERROR("break outside of loop");
|
||||
struct loop_state *loop = &state->loops[state->nr_loops-1];
|
||||
loop->breaks = xrealloc_array(loop->breaks, loop->nr_breaks, loop->nr_breaks+1, sizeof(uint32_t));
|
||||
loop->breaks[loop->nr_breaks++] = state->out.index + 2;
|
||||
write_instruction1(state, JUMP, 0);
|
||||
}
|
||||
|
||||
static void compile_statement(struct compiler_state *state, struct jaf_block_item *item)
|
||||
{
|
||||
int addr[8];
|
||||
switch (item->kind) {
|
||||
case JAF_DECLARATION:
|
||||
compile_vardecl(ain, out, &item->decl);
|
||||
compile_vardecl(state, &item->decl);
|
||||
break;
|
||||
case JAF_FUNDECL:
|
||||
ERROR("Nested functions not supported");
|
||||
@@ -426,10 +553,10 @@ static void compile_statement(struct ain *ain, struct buffer *out, struct jaf_bl
|
||||
ERROR("Labels not supported");
|
||||
break;
|
||||
case JAF_STMT_COMPOUND:
|
||||
compile_block(ain, out, item->block);
|
||||
compile_block(state, item->block);
|
||||
break;
|
||||
case JAF_STMT_EXPRESSION:
|
||||
compile_expression(ain, out, item->expr);
|
||||
compile_expression(state, item->expr);
|
||||
switch (item->expr->value_type.type) {
|
||||
case JAF_VOID:
|
||||
break;
|
||||
@@ -439,7 +566,7 @@ static void compile_statement(struct ain *ain, struct buffer *out, struct jaf_bl
|
||||
case JAF_STRUCT: // FIXME: this also needs a DELETE I think...
|
||||
case JAF_ENUM:
|
||||
case JAF_FUNCTION:
|
||||
write_instruction0(out, POP);
|
||||
write_instruction0(state, POP);
|
||||
break;
|
||||
// TODO: immediate ref types will need additional POP
|
||||
case JAF_TYPEDEF:
|
||||
@@ -447,46 +574,34 @@ static void compile_statement(struct ain *ain, struct buffer *out, struct jaf_bl
|
||||
}
|
||||
break;
|
||||
case JAF_STMT_IF:
|
||||
compile_expression(ain, out, item->cond.test);
|
||||
addr[0] = out->index + 2;
|
||||
write_instruction1(out, IFNZ, 0);
|
||||
addr[1] = out->index + 2;
|
||||
write_instruction1(out, JUMP, 0);
|
||||
buffer_write_int32_at(out, addr[0], out->index);
|
||||
compile_statement(ain, out, item->cond.consequent);
|
||||
if (item->cond.alternative) {
|
||||
addr[2] = out->index + 2;
|
||||
write_instruction1(out, JUMP, 0);
|
||||
buffer_write_int32_at(out, addr[1], out->index);
|
||||
compile_statement(ain, out, item->cond.alternative);
|
||||
buffer_write_int32_at(out, addr[2], out->index);
|
||||
} else {
|
||||
buffer_write_int32_at(out, addr[1], out->index);
|
||||
}
|
||||
compile_if(state, item->cond.test, item->cond.consequent, item->cond.alternative);
|
||||
break;
|
||||
case JAF_STMT_SWITCH:
|
||||
ERROR("switch not supported");
|
||||
break;
|
||||
case JAF_STMT_WHILE:
|
||||
ERROR("while loops not supported");
|
||||
compile_while(state, item->while_loop.test, item->while_loop.body);
|
||||
break;
|
||||
case JAF_STMT_DO_WHILE:
|
||||
ERROR("do-while loops not supported");
|
||||
compile_do_while(state, item->while_loop.test, item->while_loop.body);
|
||||
break;
|
||||
case JAF_STMT_FOR:
|
||||
ERROR("for loops not supported");
|
||||
compile_for(state, item->for_loop.init, item->for_loop.test, item->for_loop.after, item->for_loop.body);
|
||||
break;
|
||||
case JAF_STMT_GOTO:
|
||||
ERROR("goto not supported");
|
||||
case JAF_STMT_CONTINUE:
|
||||
if (state->nr_loops == 0)
|
||||
ERROR("continue outside of loop");
|
||||
write_instruction1(state, JUMP, state->loops[state->nr_loops-1].loop_addr);
|
||||
break;
|
||||
case JAF_STMT_BREAK:
|
||||
ERROR("break not supported");
|
||||
compile_break(state);
|
||||
break;
|
||||
case JAF_STMT_RETURN:
|
||||
if (item->expr)
|
||||
compile_expression(ain, out, item->expr);
|
||||
write_instruction0(out, RETURN);
|
||||
compile_expression(state, item->expr);
|
||||
write_instruction0(state, RETURN);
|
||||
break;
|
||||
case JAF_STMT_CASE:
|
||||
ERROR("switch not supported");
|
||||
@@ -497,26 +612,26 @@ static void compile_statement(struct ain *ain, struct buffer *out, struct jaf_bl
|
||||
}
|
||||
}
|
||||
|
||||
static void compile_block(struct ain *ain, struct buffer *out, struct jaf_block *block)
|
||||
static void compile_block(struct compiler_state *state, struct jaf_block *block)
|
||||
{
|
||||
for (size_t i = 0; i < block->nr_items; i++) {
|
||||
compile_statement(ain, out, block->items[i]);
|
||||
compile_statement(state, block->items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void compile_function(struct ain *ain, struct buffer *out, struct jaf_declaration *decl)
|
||||
static void compile_function(struct compiler_state *state, struct jaf_declaration *decl)
|
||||
{
|
||||
assert(decl->func_no >= 0 && decl->func_no < ain->nr_functions);
|
||||
ain->functions[decl->func_no].address = out->index;
|
||||
write_instruction1(out, FUNC, decl->func_no);
|
||||
compile_block(ain, out, decl->body);
|
||||
write_instruction1(out, ENDFUNC, decl->func_no);
|
||||
assert(decl->func_no >= 0 && decl->func_no < state->ain->nr_functions);
|
||||
state->ain->functions[decl->func_no].address = state->out.index;
|
||||
write_instruction1(state, FUNC, decl->func_no);
|
||||
compile_block(state, decl->body);
|
||||
write_instruction1(state, ENDFUNC, decl->func_no);
|
||||
}
|
||||
|
||||
static void compile_declaration(struct ain *ain, struct buffer *code, struct jaf_block_item *decl)
|
||||
static void compile_declaration(struct compiler_state *state, struct jaf_block_item *decl)
|
||||
{
|
||||
if (decl->kind == JAF_FUNDECL) {
|
||||
compile_function(ain, code, &decl->decl);
|
||||
compile_function(state, &decl->decl);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -541,16 +656,20 @@ void jaf_compile(struct ain *out, const char *path)
|
||||
|
||||
jaf_toplevel = jaf_static_analyze(out, jaf_toplevel);
|
||||
|
||||
struct buffer buf = {
|
||||
.buf = out->code,
|
||||
.size = out->code_size,
|
||||
.index = out->code_size
|
||||
struct compiler_state state = {
|
||||
.ain = out,
|
||||
.out = {
|
||||
.buf = out->code,
|
||||
.size = out->code_size,
|
||||
.index = out->code_size
|
||||
}
|
||||
};
|
||||
for (size_t i = 0; i < jaf_toplevel->nr_items; i++) {
|
||||
compile_declaration(out, &buf, jaf_toplevel->items[i]);
|
||||
compile_declaration(&state, jaf_toplevel->items[i]);
|
||||
}
|
||||
out->code = buf.buf;
|
||||
out->code_size = buf.index;
|
||||
free(state.loops);
|
||||
out->code = state.out.buf;
|
||||
out->code_size = state.out.index;
|
||||
|
||||
// XXX: ain_add_initval adds initval to GSET section of the ain file.
|
||||
// If the original ain file did not have a GSET section, init
|
||||
|
||||
@@ -166,8 +166,27 @@ static void analyze_function(struct jaf_env *env, struct jaf_declaration *decl)
|
||||
free(funenv);
|
||||
}
|
||||
|
||||
static struct jaf_env *push_env(struct jaf_env *parent)
|
||||
{
|
||||
struct jaf_env *newenv = xcalloc(1, sizeof(struct jaf_env));
|
||||
newenv->ain = parent->ain;
|
||||
newenv->parent = parent;
|
||||
newenv->func_no = parent->func_no;
|
||||
newenv->fundecl = parent->fundecl;
|
||||
return newenv;
|
||||
}
|
||||
|
||||
static struct jaf_env *pop_env(struct jaf_env *env)
|
||||
{
|
||||
struct jaf_env *parent = env->parent;
|
||||
free(env->locals);
|
||||
free(env);
|
||||
return parent;
|
||||
}
|
||||
|
||||
static void analyze_statement(struct jaf_env *env, struct jaf_block_item *item)
|
||||
{
|
||||
struct jaf_env *blockenv;
|
||||
if (!item)
|
||||
return;
|
||||
switch (item->kind) {
|
||||
@@ -204,10 +223,12 @@ static void analyze_statement(struct jaf_env *env, struct jaf_block_item *item)
|
||||
analyze_statement(env, item->while_loop.body);
|
||||
break;
|
||||
case JAF_STMT_FOR:
|
||||
analyze_block(env, item->for_loop.init);
|
||||
blockenv = push_env(env);
|
||||
jaf_analyze_block(env, item->for_loop.init);
|
||||
analyze_expression(env, &item->for_loop.test);
|
||||
analyze_expression(env, &item->for_loop.after);
|
||||
analyze_statement(env, item->for_loop.body);
|
||||
pop_env(blockenv);
|
||||
break;
|
||||
case JAF_STMT_RETURN:
|
||||
analyze_expression(env, &item->expr);
|
||||
@@ -233,15 +254,9 @@ static void jaf_analyze_block(struct jaf_env *env, struct jaf_block *block)
|
||||
|
||||
static void analyze_block(struct jaf_env *env, struct jaf_block *block)
|
||||
{
|
||||
struct jaf_env *blockenv = xcalloc(1, sizeof(struct jaf_env));
|
||||
blockenv->ain = env->ain;
|
||||
blockenv->parent = env;
|
||||
blockenv->func_no = env->func_no;
|
||||
blockenv->fundecl = env->fundecl;
|
||||
|
||||
struct jaf_env *blockenv = push_env(env);
|
||||
jaf_analyze_block(blockenv, block);
|
||||
free(blockenv->locals);
|
||||
free(blockenv);
|
||||
pop_env(blockenv);
|
||||
}
|
||||
|
||||
static void resolve_decl_types(struct ain *ain, struct jaf_declaration *decl)
|
||||
|
||||
@@ -234,7 +234,7 @@ struct ain_variable *jaf_env_lookup(struct jaf_env *env, struct string *name, in
|
||||
char *u = encode_text_to_input_format(name->text);
|
||||
struct jaf_env *scope = env;
|
||||
while (scope) {
|
||||
struct ain_variable *v = jaf_scope_lookup(env, u, var_no);
|
||||
struct ain_variable *v = jaf_scope_lookup(scope, u, var_no);
|
||||
if (v) {
|
||||
free(u);
|
||||
return v;
|
||||
|
||||
Reference in New Issue
Block a user