From 4c4ebeecfcdf256bae898813bb7cd5d3af1bf4cc Mon Sep 17 00:00:00 2001 From: James Martin Date: Sat, 10 Sep 2022 09:07:38 -0700 Subject: [PATCH] Fixed bug: use references to mutate the stack instead of values. --- src/lang.c | 172 ++++++++++++++++++++++++++++++---------------------- src/lex.h | 2 + src/parse.c | 53 +++++++++++++++- 3 files changed, 152 insertions(+), 75 deletions(-) diff --git a/src/lang.c b/src/lang.c index d12fca7..d824f45 100644 --- a/src/lang.c +++ b/src/lang.c @@ -143,38 +143,38 @@ static void push_new_jump(label label) { } static void push_argument(var ref) { - struct crumb ctx = context[context_depth - 1]; - assert(ctx.type == EXPR_CRUMB); - struct expr_crumb exprc = ctx.data.expr; - if (exprc.argument_count > MAX_ARGUMENTS) { + struct crumb* ctx = &context[context_depth - 1]; + assert(ctx->type == EXPR_CRUMB); + struct expr_crumb* exprc = &ctx->data.expr; + if (exprc->argument_count > MAX_ARGUMENTS) { fprintf(stderr, "error: exceeded maximum number of arguments in expression\n"); exit(1); } - exprc.arguments[exprc.argument_count] = ref; - exprc.argument_count++; + exprc->arguments[exprc->argument_count] = ref; + exprc->argument_count++; } static void push_cvar_name(char* name) { - struct crumb ctx = context[context_depth - 1]; - assert(ctx.type == LOOP_CRUMB); - struct loop_crumb loopc = ctx.data.loop; - if (loopc.assignment_count == MAX_ASSIGNMENTS) { + struct crumb* ctx = &context[context_depth - 1]; + assert(ctx->type == LOOP_CRUMB); + struct loop_crumb* loopc = &ctx->data.loop; + if (loopc->assignment_count == MAX_ASSIGNMENTS) { fprintf(stderr, "error: exceed maximum number of assignments in loop cvars\n"); exit(1); } - loopc.assignments[loopc.assignment_count].name = copy_str(name); + loopc->assignments[loopc->assignment_count].name = copy_str(name); } static void push_cvar(var ref) { - struct crumb ctx = context[context_depth - 1]; - assert(ctx.type == LOOP_CRUMB); - struct loop_crumb loopc = ctx.data.loop; - if (loopc.assignment_count > MAX_ASSIGNMENTS) { + struct crumb* ctx = &context[context_depth - 1]; + assert(ctx->type == LOOP_CRUMB); + struct loop_crumb* loopc = &ctx->data.loop; + if (loopc->assignment_count > MAX_ASSIGNMENTS) { fprintf(stderr, "error: exceed maximum number of assignments in loop cvars\n"); exit(1); } - loopc.initializers[loopc.assignment_count] = ref; - loopc.assignment_count++; + loopc->initializers[loopc->assignment_count] = ref; + loopc->assignment_count++; } static var lookup_assignment( @@ -267,9 +267,17 @@ static label lookup_label(enum label_type type, char* name) { exit(1); } + + +void reduce_expression(struct expr_crumb* exprc) { + // TODO FIXME + return; +} + void enter_block(void) { - struct crumb ctx = context[context_depth - 1]; - switch (ctx.type) { + printf("** enter_block\n"); + struct crumb* ctx = &context[context_depth - 1]; + switch (ctx->type) { case BLOCK_CRUMB: // we should have seen a stmt_assign or stmt_expr first, // either of which pushes an expr crumb. @@ -280,7 +288,7 @@ void enter_block(void) { break; } case IF_CRUMB: { - struct if_crumb ifc = ctx.data.if_; + struct if_crumb ifc = ctx->data.if_; switch (ifc.state) { case IF_COND: assert(0); @@ -294,14 +302,14 @@ void enter_block(void) { break; } case LOOP_CRUMB: { - struct loop_crumb loopc = ctx.data.loop; - assert(loopc.state == LOOP_CLEAN); - loopc.state = LOOP_BODY; + struct loop_crumb* loopc = &ctx->data.loop; + assert(loopc->state == LOOP_CLEAN); + loopc->state = LOOP_BODY; var args[MAX_ASSIGNMENTS]; - define(loopc.next, args); + define(loopc->next, args); // TODO NOTE: is this the correct order? - for (uint32_t i = 0; i < loopc.assignment_count; i++) { - loopc.assignments[i].ref = args[i]; + for (uint32_t i = 0; i < loopc->assignment_count; i++) { + loopc->assignments[i].ref = args[i]; } break; } @@ -312,29 +320,32 @@ void enter_block(void) { } void stmt_assign(char* name) { - struct crumb ctx = context[context_depth - 1]; - assert(ctx.type == BLOCK_CRUMB); - struct block_crumb blockc = ctx.data.block; - assert(blockc.state == BLOCK_CLEAN); - if (blockc.assignment_count == MAX_ASSIGNMENTS) { + printf("** stmt_assign\n"); + struct crumb* ctx = &context[context_depth - 1]; + assert(ctx->type == BLOCK_CRUMB); + struct block_crumb* blockc = &ctx->data.block; + assert(blockc->state == BLOCK_CLEAN); + if (blockc->assignment_count == MAX_ASSIGNMENTS) { fprintf(stderr, "error: exceeded maximum number of assignments in block\n"); exit(1); } - blockc.state = BLOCK_ASSIGN; - blockc.assignments[blockc.assignment_count].name = copy_str(name); + blockc->state = BLOCK_ASSIGN; + blockc->assignments[blockc->assignment_count].name = copy_str(name); push_new_expr(); } void stmt_expr(void) { - struct crumb ctx = context[context_depth - 1]; - assert(ctx.type == BLOCK_CRUMB); - struct block_crumb blockc = ctx.data.block; - assert(blockc.state == BLOCK_CLEAN); - blockc.state = BLOCK_EXPR; + printf("** stmt_expr\n"); + struct crumb* ctx = &context[context_depth - 1]; + assert(ctx->type == BLOCK_CRUMB); + struct block_crumb* blockc = &ctx->data.block; + assert(blockc->state == BLOCK_CLEAN); + blockc->state = BLOCK_EXPR; push_new_expr(); } void exit_block(void) { + printf("** exit_block\n"); struct crumb ctx = context[context_depth - 1]; assert(ctx.type == BLOCK_CRUMB); struct block_crumb blockc = ctx.data.block; @@ -379,55 +390,58 @@ void exit_block(void) { } void exit_expr(void) { - struct crumb ctx = context[context_depth - 1]; - assert(ctx.type == EXPR_CRUMB); - struct expr_crumb exprc = ctx.data.expr; - assert(exprc.argument_count > 0); - if (exprc.operator_count > 0 || exprc.argument_count > 1) { - // TODO FIXME - fprintf(stderr, "error: I don't know how to evaluate exprs yet\n"); + printf("** exit_expr\n"); + struct crumb* ctx = &context[context_depth - 1]; + assert(ctx->type == EXPR_CRUMB); + 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]; + var ret = exprc->arguments[0]; context_depth--; - ctx = context[context_depth - 1]; - switch (ctx.type) { + ctx = &context[context_depth - 1]; + switch (ctx->type) { case BLOCK_CRUMB: { - struct block_crumb blockc = ctx.data.block; - blockc.final = ret; - switch (blockc.state) { + struct block_crumb* blockc = &ctx->data.block; + blockc->final = ret; + switch (blockc->state) { case BLOCK_CLEAN: assert(0); case BLOCK_EXPR: + blockc->state = BLOCK_CLEAN; break; case BLOCK_ASSIGN: - blockc.assignments[blockc.assignment_count].ref = ret; - blockc.assignment_count++; + blockc->assignments[blockc->assignment_count].ref = ret; + blockc->assignment_count++; + blockc->state = BLOCK_CLEAN; break; } break; } case IF_CRUMB: { - struct if_crumb ifc = ctx.data.if_; - assert(ifc.state == IF_COND); - jump_if(ifc.then, ret, NULL); - jump(ifc.else_, NULL); - ifc.state = IF_THEN; + struct if_crumb* ifc = &ctx->data.if_; + assert(ifc->state == IF_COND); + jump_if(ifc->then, ret, NULL); + jump(ifc->else_, NULL); + ifc->state = IF_THEN; break; } case EXPR_CRUMB: push_argument(ret); break; case LOOP_CRUMB: { - struct loop_crumb loopc = ctx.data.loop; - assert(loopc.state == LOOP_CVAR_INIT); + struct loop_crumb* loopc = &ctx->data.loop; + assert(loopc->state == LOOP_CVAR_INIT); push_cvar(ret); - loopc.state = LOOP_CLEAN; + loopc->state = LOOP_CLEAN; break; } case JUMP_CRUMB: { // TODO FIXME: this is *completely wrong* for `next`! - label label = ctx.data.jump; + label label = ctx->data.jump; jump(label, &ret); // TODO: better way to handle returning impossible value push_argument(ret); @@ -437,6 +451,7 @@ void exit_expr(void) { } void enter_if(void) { + printf("** enter_if\n"); enter(); label then = declare(0); label else_ = declare(0); @@ -458,6 +473,7 @@ void enter_if(void) { } void exit_if(void) { + printf("** exit_if\n"); struct crumb ctx = context[context_depth - 1]; assert(ctx.type == IF_CRUMB); struct if_crumb ifc = ctx.data.if_; @@ -479,6 +495,7 @@ void exit_if(void) { } void enter_loop(char* label_name) { + printf("** enter_loop\n"); enter(); label exit = declare_exit(1); struct loop_crumb loopc = { @@ -497,62 +514,73 @@ void enter_loop(char* label_name) { } void cvar_pass(char* name) { + printf("** cvar_pass\n"); push_cvar_name(name); push_cvar(lookup_var(name)); } void cvar_init(char* name) { - struct crumb ctx = context[context_depth - 1]; - assert(ctx.type == LOOP_CRUMB); - struct loop_crumb loopc = ctx.data.loop; - loopc.state = LOOP_CVAR_INIT; + printf("** cvar_init\n"); + struct crumb* ctx = &context[context_depth - 1]; + assert(ctx->type == LOOP_CRUMB); + struct loop_crumb* loopc = &ctx->data.loop; + loopc->state = LOOP_CVAR_INIT; push_cvar_name(name); push_new_expr(); } void expr_next(char* label) { + printf("** expr_next\n"); push_new_jump(lookup_label(NEXT_LABEL, label)); push_new_expr(); } void expr_exit(char* label) { + printf("** expr_exit\n"); push_new_jump(lookup_label(EXIT_LABEL, label)); push_new_expr(); } void expr_return(void) { + printf("** expr_return\n"); push_new_jump(lookup_label(RETURN_LABEL, NULL)); push_new_expr(); } void enter_group(void) { + printf("** enter_group\n"); push_new_expr(); } void exit_group(void) { + printf("** exit_group\n"); // exit_expr is sufficient } void expr_op(enum operator_ op) { - struct crumb ctx = context[context_depth - 1]; - assert(ctx.type == EXPR_CRUMB); - struct expr_crumb exprc = ctx.data.expr; - if (exprc.operator_count > MAX_OPERATORS) { + printf("** expr_op %ir\n", op); + struct crumb* ctx = &context[context_depth - 1]; + assert(ctx->type == EXPR_CRUMB); + struct expr_crumb* exprc = &ctx->data.expr; + if (exprc->operator_count > MAX_OPERATORS) { fprintf(stderr, "error: exceeded maximum number of operators in expression\n"); exit(1); } - exprc.operators[exprc.operator_count] = op; - exprc.operator_count++; + exprc->operators[exprc->operator_count] = op; + exprc->operator_count++; } void expr_string(char* string) { + printf("** expr_string %s\n", string); push_argument(lit_string(string)); } void expr_integer(int64_t num) { + printf("** expr_integer %lli\n", num); push_argument(lit((uint64_t) num)); } void expr_var(char* var) { + printf("** expr_var %s\n", var); push_argument(lookup_var(var)); } diff --git a/src/lex.h b/src/lex.h index ed35e61..d1f2437 100644 --- a/src/lex.h +++ b/src/lex.h @@ -45,6 +45,8 @@ enum operator_ { OP_TYPE, // : OP_FUN, // -> + + OP_JUXT, // space! but this is not emitted by the lexer. }; union token_data { diff --git a/src/parse.c b/src/parse.c index f08974b..56d48d7 100644 --- a/src/parse.c +++ b/src/parse.c @@ -5,6 +5,7 @@ #include #include +#include "lang.h" #include "lex.h" #include "parse.h" @@ -15,9 +16,12 @@ enum state { ST_BLOCK_CLOSE, ST_ASSIGN, ST_EXPR, + ST_EXPR_HACK, ST_EXPR_CONT, + ST_EXPR_END, ST_GROUP, ST_IF_ELSE, + ST_IF_END, ST_LOOP_VARS, ST_LOOP_VARS_CONT, }; @@ -46,6 +50,12 @@ const char* state_name(enum state st) { return "v"; case ST_LOOP_VARS_CONT: return ","; + case ST_EXPR_END: + return "E"; + case ST_EXPR_HACK: + return "H"; + case ST_IF_END: + return "i"; } } @@ -78,6 +88,7 @@ static enum state pop(void) { static _Bool is_assignment(struct token tok, struct token next) { return tok.type == TOK_NAME && next.type == TOK_OPERATOR && next.data.op == OP_EQ; + } @@ -104,6 +115,7 @@ void parse(void) { if (tok.type == TOK_OPEN_BLOCK) { push(ST_BLOCK_CLOSE); push(ST_BLOCK_BODY); + enter_block(); break; } syntax_error("expected beginning of block"); @@ -112,11 +124,13 @@ void parse(void) { if (is_assignment(tok, nxt)) { push(ST_BLOCK_CONT); push(ST_ASSIGN); + stmt_assign(tok.data.name); break; } if (is_expr(tok)) { push(ST_BLOCK_CONT); push(ST_EXPR); + stmt_expr(); continue; } continue; @@ -128,6 +142,7 @@ void parse(void) { continue; case ST_BLOCK_CLOSE: if (tok.type == TOK_CLOSE_BLOCK) { + exit_block(); break; } syntax_error("expected end of block"); @@ -136,20 +151,28 @@ void parse(void) { push(ST_EXPR); break; case ST_EXPR: + push(ST_EXPR_END); + push(ST_EXPR_HACK); + continue; + case ST_EXPR_HACK: if (tok.type == TOK_STRING) { push(ST_EXPR_CONT); + expr_string(tok.data.string); break; } if (tok.type == TOK_INTEGER) { push(ST_EXPR_CONT); + expr_integer(tok.data.int_); break; } if (tok.type == TOK_NAME) { char* name = tok.data.name; if (strcmp(name, "if") == 0) { + push(ST_IF_END); push(ST_IF_ELSE); push(ST_BLOCK); push(ST_EXPR); + enter_if(); break; } if (strcmp(name, "loop") == 0) { @@ -157,6 +180,9 @@ void parse(void) { push(ST_LOOP_VARS); if (nxt.type == TOK_LABEL) { next(); + enter_loop(nxt.data.label); + } else { + enter_loop(NULL); } break; } @@ -164,6 +190,9 @@ void parse(void) { push(ST_LOOP_VARS); if (nxt.type == TOK_LABEL) { next(); + expr_next(nxt.data.label); + } else { + expr_next(NULL); } break; } @@ -171,25 +200,32 @@ void parse(void) { push(ST_EXPR); if (nxt.type == TOK_LABEL) { next(); + expr_exit(nxt.data.label); + } else { + expr_exit(NULL); } break; } if (strcmp(name, "return") == 0) { push(ST_EXPR); + expr_return(); break; } push(ST_EXPR_CONT); + expr_var(tok.data.name); break; } if (tok.type == TOK_OPEN_GROUP) { push(ST_EXPR_CONT); push(ST_GROUP); push(ST_EXPR); + enter_group(); break; } if (tok.type == TOK_OPERATOR && is_unary(tok.data.op)) { push(ST_EXPR_CONT); - push(ST_EXPR); + push(ST_EXPR_HACK); + expr_op(tok.data.op); break; } if (tok.type == TOK_OPEN_BLOCK) { @@ -199,16 +235,22 @@ void parse(void) { syntax_error("expected expression"); case ST_EXPR_CONT: if (is_expr(tok)) { - push(ST_EXPR); + push(ST_EXPR_HACK); + expr_op(OP_JUXT); continue; } if (tok.type == TOK_OPERATOR && is_binary(tok.data.op)) { - push(ST_EXPR); + push(ST_EXPR_HACK); + expr_op(tok.data.op); break; } continue; + case ST_EXPR_END: + exit_expr(); + continue; case ST_GROUP: if (tok.type == TOK_CLOSE_GROUP) { + exit_group(); break; } syntax_error("mismatched parentheses"); @@ -218,14 +260,19 @@ void parse(void) { break; } continue; + case ST_IF_END: + exit_if(); + continue; case ST_LOOP_VARS: if (is_assignment(tok, nxt)) { push(ST_LOOP_VARS_CONT); push(ST_ASSIGN); + cvar_init(tok.data.name); break; } if (tok.type == TOK_NAME) { push(ST_LOOP_VARS_CONT); + cvar_pass(tok.data.name); break; } continue;