rename env to scope, and free pointers before they leak

This commit is contained in:
me 2026-01-11 11:08:40 +02:00
parent 2f32c928d6
commit f36482afc7

View file

@ -17,7 +17,7 @@ struct Cell {
typedef struct { typedef struct {
struct Cell* next; struct Cell* next;
} Environment; } Scope;
Memory new_memory() { Memory new_memory() {
unsigned size = 1024; unsigned size = 1024;
@ -33,12 +33,12 @@ Memory new_memory() {
}; };
} }
Environment new_environment() { Scope new_scope() {
return (Environment) { .next = NULL }; return (Scope) { .next = NULL };
} }
int lookup_env(char* name, Environment env) { int lookup_scope(char* name, Scope scope) {
struct Cell* cell = env.next; struct Cell* cell = scope.next;
while (cell != NULL) { while (cell != NULL) {
if (strcmp(cell->name, name) == 0) { if (strcmp(cell->name, name) == 0) {
return cell->index; return cell->index;
@ -49,18 +49,18 @@ int lookup_env(char* name, Environment env) {
return -1; return -1;
} }
Environment insert(char* name, int n, Memory memory, Environment env) { Scope insert(char* name, int n, Memory memory, Scope scope) {
if (*memory.i + 1 < memory.memory.length) { if (*memory.i + 1 < memory.memory.length) {
((int*)(memory.memory.elements))[*memory.i] = n; ((int*)(memory.memory.elements))[*memory.i] = n;
struct Cell* cell = (struct Cell*)malloc(sizeof(struct Cell)); struct Cell* cell = (struct Cell*)malloc(sizeof(struct Cell));
*cell = (struct Cell) { *cell = (struct Cell) {
.name = name, .name = name,
.index = *memory.i, .index = *memory.i,
.next = env.next, .next = scope.next,
}; };
++*memory.i; ++*memory.i;
Environment new_env = (Environment) {.next = cell}; Scope new_scope = (Scope) {.next = cell};
return new_env; return new_scope;
} }
fprintf(stderr, "Error: out of memory."); fprintf(stderr, "Error: out of memory.");
exit(1); exit(1);
@ -73,8 +73,8 @@ int* lookup_mem(int index, Memory mem) {
return NULL; return NULL;
} }
int* lookup(char* name, Memory memory, Environment env) { int* lookup(char* name, Memory memory, Scope scope) {
int index = lookup_env(name, env); int index = lookup_scope(name, scope);
if (index >= 0) { if (index >= 0) {
int* result = lookup_mem(index, memory); int* result = lookup_mem(index, memory);
if (result != NULL) { if (result != NULL) {
@ -84,14 +84,14 @@ int* lookup(char* name, Memory memory, Environment env) {
return NULL; return NULL;
} }
int eval_expr(Expr expr, Memory memory, Environment env) { int eval_expr(Expr expr, Memory memory, Scope scope) {
switch (expr.tag) { switch (expr.tag) {
default: default:
case LITERAL: { case LITERAL: {
return expr.data.integer; return expr.data.integer;
} }
case VARIABLE: { case VARIABLE: {
int* result = lookup(expr.data.variable, memory, env); int* result = lookup(expr.data.variable, memory, scope);
if (result == NULL) { if (result == NULL) {
fprintf(stderr, "Error: variable not found '%s'\n", expr.data.variable); fprintf(stderr, "Error: variable not found '%s'\n", expr.data.variable);
exit(1); exit(1);
@ -102,7 +102,7 @@ int eval_expr(Expr expr, Memory memory, Environment env) {
case FUNCTION: { case FUNCTION: {
if (strcmp(expr.data.function.name, "print") == 0) { if (strcmp(expr.data.function.name, "print") == 0) {
if (expr.data.function.args.length == 1) { if (expr.data.function.args.length == 1) {
int arg = eval_expr(((Expr*)expr.data.function.args.elements)[0], memory, env); int arg = eval_expr(((Expr*)expr.data.function.args.elements)[0], memory, scope);
printf("%d\n", arg); printf("%d\n", arg);
return 0; return 0;
} else { } else {
@ -112,8 +112,8 @@ int eval_expr(Expr expr, Memory memory, Environment env) {
} }
else if (strcmp(expr.data.function.name, "add") == 0) { else if (strcmp(expr.data.function.name, "add") == 0) {
if (expr.data.function.args.length == 2) { if (expr.data.function.args.length == 2) {
int arg1 = eval_expr(((Expr*)expr.data.function.args.elements)[0], memory, env); int arg1 = eval_expr(((Expr*)expr.data.function.args.elements)[0], memory, scope);
int arg2 = eval_expr(((Expr*)expr.data.function.args.elements)[1], memory, env); int arg2 = eval_expr(((Expr*)expr.data.function.args.elements)[1], memory, scope);
return arg1 + arg2; return arg1 + arg2;
} else { } else {
fprintf(stderr, "Error: negate expects a single argument.\n"); fprintf(stderr, "Error: negate expects a single argument.\n");
@ -122,7 +122,7 @@ int eval_expr(Expr expr, Memory memory, Environment env) {
} }
else if (strcmp(expr.data.function.name, "negate") == 0) { else if (strcmp(expr.data.function.name, "negate") == 0) {
if (expr.data.function.args.length == 1) { if (expr.data.function.args.length == 1) {
int arg = eval_expr(((Expr*)expr.data.function.args.elements)[0], memory, env); int arg = eval_expr(((Expr*)expr.data.function.args.elements)[0], memory, scope);
return 0 - arg; return 0 - arg;
} else { } else {
fprintf(stderr, "Error: negate expects a single argument.\n"); fprintf(stderr, "Error: negate expects a single argument.\n");
@ -134,40 +134,47 @@ int eval_expr(Expr expr, Memory memory, Environment env) {
} }
} }
Environment interpret_stmt(Stmt stmt, Memory memory, Environment env) { Scope interpret_stmt(Stmt stmt, Memory memory, Scope scope) {
switch (stmt.tag) { switch (stmt.tag) {
case SET: { case SET: {
int result = eval_expr(stmt.data.Set.expr, memory, env); int result = eval_expr(stmt.data.Set.expr, memory, scope);
int* index = lookup(stmt.data.Set.name, memory, env); int* index = lookup(stmt.data.Set.name, memory, scope);
if (index != NULL) { if (index != NULL) {
*index = result; *index = result;
} else { } else {
return insert(stmt.data.Set.name, result, memory, env); return insert(stmt.data.Set.name, result, memory, scope);
} }
break; break;
} }
case WHILE: { case WHILE: {
while (eval_expr(stmt.data.While.condition, memory, env)) { while (eval_expr(stmt.data.While.condition, memory, scope)) {
Environment new_env = env; Scope new_scope = scope;
for (unsigned i = 0; i < stmt.data.While.block.length; ++i) { for (unsigned i = 0; i < stmt.data.While.block.length; ++i) {
Stmt current = ((Stmt*)stmt.data.While.block.elements)[i]; Stmt current = ((Stmt*)stmt.data.While.block.elements)[i];
new_env = interpret_stmt(current, memory, new_env); new_scope = interpret_stmt(current, memory, new_scope);
}
// free pointers before they leak
struct Cell* next = new_scope.next;
while (next != NULL && next != scope.next) {
struct Cell* nextnext = next->next;
free(next);
next = nextnext;
} }
} }
break; break;
} }
case EXPR: case EXPR:
eval_expr(stmt.data.Expr.expr, memory, env); eval_expr(stmt.data.Expr.expr, memory, scope);
break; break;
} }
return env; return scope;
} }
void execute(StmtArray stmts) { void execute(StmtArray stmts) {
Memory memory = new_memory(); Memory memory = new_memory();
Environment environment = new_environment(); Scope scope = new_scope();
for (unsigned pc = 0; pc < stmts.length; ++pc) { for (unsigned pc = 0; pc < stmts.length; ++pc) {
Stmt stmt = stmts.stmts[pc]; Stmt stmt = stmts.stmts[pc];
environment = interpret_stmt(stmt, memory, environment); scope = interpret_stmt(stmt, memory, scope);
} }
} }