Fixed bug: use references to mutate the stack instead of values.

master
James T. Martin 2022-09-10 09:07:38 -07:00
parent fcd61f6c5f
commit 4c4ebeecfc
Signed by: james
GPG Key ID: D6FB2F9892F9B225
3 changed files with 152 additions and 75 deletions

View File

@ -143,38 +143,38 @@ static void push_new_jump(label label) {
} }
static void push_argument(var ref) { static void push_argument(var ref) {
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 (exprc.argument_count > MAX_ARGUMENTS) { if (exprc->argument_count > MAX_ARGUMENTS) {
fprintf(stderr, "error: exceeded maximum number of arguments in expression\n"); fprintf(stderr, "error: exceeded maximum number of arguments in expression\n");
exit(1); exit(1);
} }
exprc.arguments[exprc.argument_count] = ref; exprc->arguments[exprc->argument_count] = ref;
exprc.argument_count++; exprc->argument_count++;
} }
static void push_cvar_name(char* name) { static void push_cvar_name(char* name) {
struct crumb ctx = context[context_depth - 1]; struct crumb* ctx = &context[context_depth - 1];
assert(ctx.type == LOOP_CRUMB); assert(ctx->type == LOOP_CRUMB);
struct loop_crumb loopc = ctx.data.loop; struct loop_crumb* loopc = &ctx->data.loop;
if (loopc.assignment_count == MAX_ASSIGNMENTS) { if (loopc->assignment_count == MAX_ASSIGNMENTS) {
fprintf(stderr, "error: exceed maximum number of assignments in loop cvars\n"); fprintf(stderr, "error: exceed maximum number of assignments in loop cvars\n");
exit(1); 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) { static void push_cvar(var ref) {
struct crumb ctx = context[context_depth - 1]; struct crumb* ctx = &context[context_depth - 1];
assert(ctx.type == LOOP_CRUMB); assert(ctx->type == LOOP_CRUMB);
struct loop_crumb loopc = ctx.data.loop; struct loop_crumb* loopc = &ctx->data.loop;
if (loopc.assignment_count > MAX_ASSIGNMENTS) { if (loopc->assignment_count > MAX_ASSIGNMENTS) {
fprintf(stderr, "error: exceed maximum number of assignments in loop cvars\n"); fprintf(stderr, "error: exceed maximum number of assignments in loop cvars\n");
exit(1); exit(1);
} }
loopc.initializers[loopc.assignment_count] = ref; loopc->initializers[loopc->assignment_count] = ref;
loopc.assignment_count++; loopc->assignment_count++;
} }
static var lookup_assignment( static var lookup_assignment(
@ -267,9 +267,17 @@ static label lookup_label(enum label_type type, char* name) {
exit(1); exit(1);
} }
void reduce_expression(struct expr_crumb* exprc) {
// TODO FIXME
return;
}
void enter_block(void) { void enter_block(void) {
struct crumb ctx = context[context_depth - 1]; printf("** enter_block\n");
switch (ctx.type) { struct crumb* ctx = &context[context_depth - 1];
switch (ctx->type) {
case BLOCK_CRUMB: case BLOCK_CRUMB:
// we should have seen a stmt_assign or stmt_expr first, // we should have seen a stmt_assign or stmt_expr first,
// either of which pushes an expr crumb. // either of which pushes an expr crumb.
@ -280,7 +288,7 @@ void enter_block(void) {
break; break;
} }
case IF_CRUMB: { case IF_CRUMB: {
struct if_crumb ifc = ctx.data.if_; struct if_crumb ifc = ctx->data.if_;
switch (ifc.state) { switch (ifc.state) {
case IF_COND: case IF_COND:
assert(0); assert(0);
@ -294,14 +302,14 @@ void enter_block(void) {
break; break;
} }
case LOOP_CRUMB: { case LOOP_CRUMB: {
struct loop_crumb loopc = ctx.data.loop; struct loop_crumb* loopc = &ctx->data.loop;
assert(loopc.state == LOOP_CLEAN); assert(loopc->state == LOOP_CLEAN);
loopc.state = LOOP_BODY; loopc->state = LOOP_BODY;
var args[MAX_ASSIGNMENTS]; var args[MAX_ASSIGNMENTS];
define(loopc.next, args); define(loopc->next, args);
// TODO NOTE: is this the correct order? // TODO NOTE: is this the correct order?
for (uint32_t i = 0; i < loopc.assignment_count; i++) { for (uint32_t i = 0; i < loopc->assignment_count; i++) {
loopc.assignments[i].ref = args[i]; loopc->assignments[i].ref = args[i];
} }
break; break;
} }
@ -312,29 +320,32 @@ void enter_block(void) {
} }
void stmt_assign(char* name) { void stmt_assign(char* name) {
struct crumb ctx = context[context_depth - 1]; printf("** stmt_assign\n");
assert(ctx.type == BLOCK_CRUMB); struct crumb* ctx = &context[context_depth - 1];
struct block_crumb blockc = ctx.data.block; assert(ctx->type == BLOCK_CRUMB);
assert(blockc.state == BLOCK_CLEAN); struct block_crumb* blockc = &ctx->data.block;
if (blockc.assignment_count == MAX_ASSIGNMENTS) { assert(blockc->state == BLOCK_CLEAN);
if (blockc->assignment_count == MAX_ASSIGNMENTS) {
fprintf(stderr, "error: exceeded maximum number of assignments in block\n"); fprintf(stderr, "error: exceeded maximum number of assignments in block\n");
exit(1); exit(1);
} }
blockc.state = BLOCK_ASSIGN; blockc->state = BLOCK_ASSIGN;
blockc.assignments[blockc.assignment_count].name = copy_str(name); blockc->assignments[blockc->assignment_count].name = copy_str(name);
push_new_expr(); push_new_expr();
} }
void stmt_expr(void) { void stmt_expr(void) {
struct crumb ctx = context[context_depth - 1]; printf("** stmt_expr\n");
assert(ctx.type == BLOCK_CRUMB); struct crumb* ctx = &context[context_depth - 1];
struct block_crumb blockc = ctx.data.block; assert(ctx->type == BLOCK_CRUMB);
assert(blockc.state == BLOCK_CLEAN); struct block_crumb* blockc = &ctx->data.block;
blockc.state = BLOCK_EXPR; assert(blockc->state == BLOCK_CLEAN);
blockc->state = BLOCK_EXPR;
push_new_expr(); push_new_expr();
} }
void exit_block(void) { void exit_block(void) {
printf("** exit_block\n");
struct crumb ctx = context[context_depth - 1]; struct crumb ctx = context[context_depth - 1];
assert(ctx.type == BLOCK_CRUMB); assert(ctx.type == BLOCK_CRUMB);
struct block_crumb blockc = ctx.data.block; struct block_crumb blockc = ctx.data.block;
@ -379,55 +390,58 @@ void exit_block(void) {
} }
void exit_expr(void) { void exit_expr(void) {
struct crumb ctx = context[context_depth - 1]; printf("** exit_expr\n");
assert(ctx.type == EXPR_CRUMB); struct crumb* ctx = &context[context_depth - 1];
struct expr_crumb exprc = ctx.data.expr; assert(ctx->type == EXPR_CRUMB);
assert(exprc.argument_count > 0); struct expr_crumb* exprc = &ctx->data.expr;
if (exprc.operator_count > 0 || exprc.argument_count > 1) { assert(exprc->argument_count > 0);
// TODO FIXME reduce_expression(exprc);
fprintf(stderr, "error: I don't know how to evaluate exprs yet\n"); if (exprc->operator_count > 0 || exprc->argument_count > 1) {
fprintf(stderr, "error: failed to reduce expression\n");
exit(1); 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];
switch (ctx.type) { switch (ctx->type) {
case BLOCK_CRUMB: { case BLOCK_CRUMB: {
struct block_crumb blockc = ctx.data.block; struct block_crumb* blockc = &ctx->data.block;
blockc.final = ret; blockc->final = ret;
switch (blockc.state) { switch (blockc->state) {
case BLOCK_CLEAN: case BLOCK_CLEAN:
assert(0); assert(0);
case BLOCK_EXPR: case BLOCK_EXPR:
blockc->state = BLOCK_CLEAN;
break; break;
case BLOCK_ASSIGN: case BLOCK_ASSIGN:
blockc.assignments[blockc.assignment_count].ref = ret; blockc->assignments[blockc->assignment_count].ref = ret;
blockc.assignment_count++; blockc->assignment_count++;
blockc->state = BLOCK_CLEAN;
break; break;
} }
break; break;
} }
case IF_CRUMB: { case IF_CRUMB: {
struct if_crumb ifc = ctx.data.if_; struct if_crumb* ifc = &ctx->data.if_;
assert(ifc.state == IF_COND); assert(ifc->state == IF_COND);
jump_if(ifc.then, ret, NULL); jump_if(ifc->then, ret, NULL);
jump(ifc.else_, NULL); jump(ifc->else_, NULL);
ifc.state = IF_THEN; ifc->state = IF_THEN;
break; break;
} }
case EXPR_CRUMB: case EXPR_CRUMB:
push_argument(ret); push_argument(ret);
break; break;
case LOOP_CRUMB: { case LOOP_CRUMB: {
struct loop_crumb loopc = ctx.data.loop; struct loop_crumb* loopc = &ctx->data.loop;
assert(loopc.state == LOOP_CVAR_INIT); assert(loopc->state == LOOP_CVAR_INIT);
push_cvar(ret); push_cvar(ret);
loopc.state = LOOP_CLEAN; loopc->state = LOOP_CLEAN;
break; break;
} }
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; label label = ctx->data.jump;
jump(label, &ret); jump(label, &ret);
// TODO: better way to handle returning impossible value // TODO: better way to handle returning impossible value
push_argument(ret); push_argument(ret);
@ -437,6 +451,7 @@ void exit_expr(void) {
} }
void enter_if(void) { void enter_if(void) {
printf("** enter_if\n");
enter(); enter();
label then = declare(0); label then = declare(0);
label else_ = declare(0); label else_ = declare(0);
@ -458,6 +473,7 @@ void enter_if(void) {
} }
void exit_if(void) { void exit_if(void) {
printf("** exit_if\n");
struct crumb ctx = context[context_depth - 1]; struct crumb ctx = context[context_depth - 1];
assert(ctx.type == IF_CRUMB); assert(ctx.type == IF_CRUMB);
struct if_crumb ifc = ctx.data.if_; struct if_crumb ifc = ctx.data.if_;
@ -479,6 +495,7 @@ void exit_if(void) {
} }
void enter_loop(char* label_name) { void enter_loop(char* label_name) {
printf("** enter_loop\n");
enter(); enter();
label exit = declare_exit(1); label exit = declare_exit(1);
struct loop_crumb loopc = { struct loop_crumb loopc = {
@ -497,62 +514,73 @@ void enter_loop(char* label_name) {
} }
void cvar_pass(char* name) { void cvar_pass(char* name) {
printf("** cvar_pass\n");
push_cvar_name(name); push_cvar_name(name);
push_cvar(lookup_var(name)); push_cvar(lookup_var(name));
} }
void cvar_init(char* name) { void cvar_init(char* name) {
struct crumb ctx = context[context_depth - 1]; printf("** cvar_init\n");
assert(ctx.type == LOOP_CRUMB); struct crumb* ctx = &context[context_depth - 1];
struct loop_crumb loopc = ctx.data.loop; assert(ctx->type == LOOP_CRUMB);
loopc.state = LOOP_CVAR_INIT; struct loop_crumb* loopc = &ctx->data.loop;
loopc->state = LOOP_CVAR_INIT;
push_cvar_name(name); push_cvar_name(name);
push_new_expr(); push_new_expr();
} }
void expr_next(char* label) { void expr_next(char* label) {
printf("** expr_next\n");
push_new_jump(lookup_label(NEXT_LABEL, label)); push_new_jump(lookup_label(NEXT_LABEL, label));
push_new_expr(); push_new_expr();
} }
void expr_exit(char* label) { void expr_exit(char* label) {
printf("** expr_exit\n");
push_new_jump(lookup_label(EXIT_LABEL, label)); push_new_jump(lookup_label(EXIT_LABEL, label));
push_new_expr(); push_new_expr();
} }
void expr_return(void) { void expr_return(void) {
printf("** expr_return\n");
push_new_jump(lookup_label(RETURN_LABEL, NULL)); push_new_jump(lookup_label(RETURN_LABEL, NULL));
push_new_expr(); push_new_expr();
} }
void enter_group(void) { void enter_group(void) {
printf("** enter_group\n");
push_new_expr(); push_new_expr();
} }
void exit_group(void) { void exit_group(void) {
printf("** exit_group\n");
// exit_expr is sufficient // exit_expr is sufficient
} }
void expr_op(enum operator_ op) { void expr_op(enum operator_ op) {
struct crumb ctx = context[context_depth - 1]; printf("** expr_op %ir\n", op);
assert(ctx.type == EXPR_CRUMB); struct crumb* ctx = &context[context_depth - 1];
struct expr_crumb exprc = ctx.data.expr; assert(ctx->type == EXPR_CRUMB);
if (exprc.operator_count > MAX_OPERATORS) { struct expr_crumb* exprc = &ctx->data.expr;
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);
} }
exprc.operators[exprc.operator_count] = op; exprc->operators[exprc->operator_count] = op;
exprc.operator_count++; exprc->operator_count++;
} }
void expr_string(char* string) { void expr_string(char* string) {
printf("** expr_string %s\n", string);
push_argument(lit_string(string)); push_argument(lit_string(string));
} }
void expr_integer(int64_t num) { void expr_integer(int64_t num) {
printf("** expr_integer %lli\n", num);
push_argument(lit((uint64_t) num)); push_argument(lit((uint64_t) num));
} }
void expr_var(char* var) { void expr_var(char* var) {
printf("** expr_var %s\n", var);
push_argument(lookup_var(var)); push_argument(lookup_var(var));
} }

View File

@ -45,6 +45,8 @@ enum operator_ {
OP_TYPE, // : OP_TYPE, // :
OP_FUN, // -> OP_FUN, // ->
OP_JUXT, // space! but this is not emitted by the lexer.
}; };
union token_data { union token_data {

View File

@ -5,6 +5,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "lang.h"
#include "lex.h" #include "lex.h"
#include "parse.h" #include "parse.h"
@ -15,9 +16,12 @@ enum state {
ST_BLOCK_CLOSE, ST_BLOCK_CLOSE,
ST_ASSIGN, ST_ASSIGN,
ST_EXPR, ST_EXPR,
ST_EXPR_HACK,
ST_EXPR_CONT, ST_EXPR_CONT,
ST_EXPR_END,
ST_GROUP, ST_GROUP,
ST_IF_ELSE, ST_IF_ELSE,
ST_IF_END,
ST_LOOP_VARS, ST_LOOP_VARS,
ST_LOOP_VARS_CONT, ST_LOOP_VARS_CONT,
}; };
@ -46,6 +50,12 @@ const char* state_name(enum state st) {
return "v"; return "v";
case ST_LOOP_VARS_CONT: case ST_LOOP_VARS_CONT:
return ","; 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) { static _Bool is_assignment(struct token tok, struct token next) {
return tok.type == TOK_NAME && next.type == TOK_OPERATOR && next.data.op == OP_EQ; 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) { if (tok.type == TOK_OPEN_BLOCK) {
push(ST_BLOCK_CLOSE); push(ST_BLOCK_CLOSE);
push(ST_BLOCK_BODY); push(ST_BLOCK_BODY);
enter_block();
break; break;
} }
syntax_error("expected beginning of block"); syntax_error("expected beginning of block");
@ -112,11 +124,13 @@ void parse(void) {
if (is_assignment(tok, nxt)) { if (is_assignment(tok, nxt)) {
push(ST_BLOCK_CONT); push(ST_BLOCK_CONT);
push(ST_ASSIGN); push(ST_ASSIGN);
stmt_assign(tok.data.name);
break; break;
} }
if (is_expr(tok)) { if (is_expr(tok)) {
push(ST_BLOCK_CONT); push(ST_BLOCK_CONT);
push(ST_EXPR); push(ST_EXPR);
stmt_expr();
continue; continue;
} }
continue; continue;
@ -128,6 +142,7 @@ void parse(void) {
continue; continue;
case ST_BLOCK_CLOSE: case ST_BLOCK_CLOSE:
if (tok.type == TOK_CLOSE_BLOCK) { if (tok.type == TOK_CLOSE_BLOCK) {
exit_block();
break; break;
} }
syntax_error("expected end of block"); syntax_error("expected end of block");
@ -136,20 +151,28 @@ void parse(void) {
push(ST_EXPR); push(ST_EXPR);
break; break;
case ST_EXPR: case ST_EXPR:
push(ST_EXPR_END);
push(ST_EXPR_HACK);
continue;
case ST_EXPR_HACK:
if (tok.type == TOK_STRING) { if (tok.type == TOK_STRING) {
push(ST_EXPR_CONT); push(ST_EXPR_CONT);
expr_string(tok.data.string);
break; break;
} }
if (tok.type == TOK_INTEGER) { if (tok.type == TOK_INTEGER) {
push(ST_EXPR_CONT); push(ST_EXPR_CONT);
expr_integer(tok.data.int_);
break; break;
} }
if (tok.type == TOK_NAME) { if (tok.type == TOK_NAME) {
char* name = tok.data.name; char* name = tok.data.name;
if (strcmp(name, "if") == 0) { if (strcmp(name, "if") == 0) {
push(ST_IF_END);
push(ST_IF_ELSE); push(ST_IF_ELSE);
push(ST_BLOCK); push(ST_BLOCK);
push(ST_EXPR); push(ST_EXPR);
enter_if();
break; break;
} }
if (strcmp(name, "loop") == 0) { if (strcmp(name, "loop") == 0) {
@ -157,6 +180,9 @@ void parse(void) {
push(ST_LOOP_VARS); push(ST_LOOP_VARS);
if (nxt.type == TOK_LABEL) { if (nxt.type == TOK_LABEL) {
next(); next();
enter_loop(nxt.data.label);
} else {
enter_loop(NULL);
} }
break; break;
} }
@ -164,6 +190,9 @@ void parse(void) {
push(ST_LOOP_VARS); push(ST_LOOP_VARS);
if (nxt.type == TOK_LABEL) { if (nxt.type == TOK_LABEL) {
next(); next();
expr_next(nxt.data.label);
} else {
expr_next(NULL);
} }
break; break;
} }
@ -171,25 +200,32 @@ void parse(void) {
push(ST_EXPR); push(ST_EXPR);
if (nxt.type == TOK_LABEL) { if (nxt.type == TOK_LABEL) {
next(); next();
expr_exit(nxt.data.label);
} else {
expr_exit(NULL);
} }
break; break;
} }
if (strcmp(name, "return") == 0) { if (strcmp(name, "return") == 0) {
push(ST_EXPR); push(ST_EXPR);
expr_return();
break; break;
} }
push(ST_EXPR_CONT); push(ST_EXPR_CONT);
expr_var(tok.data.name);
break; break;
} }
if (tok.type == TOK_OPEN_GROUP) { if (tok.type == TOK_OPEN_GROUP) {
push(ST_EXPR_CONT); push(ST_EXPR_CONT);
push(ST_GROUP); push(ST_GROUP);
push(ST_EXPR); push(ST_EXPR);
enter_group();
break; break;
} }
if (tok.type == TOK_OPERATOR && is_unary(tok.data.op)) { if (tok.type == TOK_OPERATOR && is_unary(tok.data.op)) {
push(ST_EXPR_CONT); push(ST_EXPR_CONT);
push(ST_EXPR); push(ST_EXPR_HACK);
expr_op(tok.data.op);
break; break;
} }
if (tok.type == TOK_OPEN_BLOCK) { if (tok.type == TOK_OPEN_BLOCK) {
@ -199,16 +235,22 @@ void parse(void) {
syntax_error("expected expression"); syntax_error("expected expression");
case ST_EXPR_CONT: case ST_EXPR_CONT:
if (is_expr(tok)) { if (is_expr(tok)) {
push(ST_EXPR); push(ST_EXPR_HACK);
expr_op(OP_JUXT);
continue; continue;
} }
if (tok.type == TOK_OPERATOR && is_binary(tok.data.op)) { if (tok.type == TOK_OPERATOR && is_binary(tok.data.op)) {
push(ST_EXPR); push(ST_EXPR_HACK);
expr_op(tok.data.op);
break; break;
} }
continue; continue;
case ST_EXPR_END:
exit_expr();
continue;
case ST_GROUP: case ST_GROUP:
if (tok.type == TOK_CLOSE_GROUP) { if (tok.type == TOK_CLOSE_GROUP) {
exit_group();
break; break;
} }
syntax_error("mismatched parentheses"); syntax_error("mismatched parentheses");
@ -218,14 +260,19 @@ void parse(void) {
break; break;
} }
continue; continue;
case ST_IF_END:
exit_if();
continue;
case ST_LOOP_VARS: case ST_LOOP_VARS:
if (is_assignment(tok, nxt)) { if (is_assignment(tok, nxt)) {
push(ST_LOOP_VARS_CONT); push(ST_LOOP_VARS_CONT);
push(ST_ASSIGN); push(ST_ASSIGN);
cvar_init(tok.data.name);
break; break;
} }
if (tok.type == TOK_NAME) { if (tok.type == TOK_NAME) {
push(ST_LOOP_VARS_CONT); push(ST_LOOP_VARS_CONT);
cvar_pass(tok.data.name);
break; break;
} }
continue; continue;