Compiler: add array support, fix number format, OPEN variable clash

Arrays: DIM creates arrays via gwrt_dim() runtime call. Array element
read/write uses gwrt_array_elem() with buffered subscript expressions
(open_memstream) to correctly determine dimension count. Auto-DIM with
default size 10 for undeclared arrays.

Number formatting: PRINT now uses gw_print_value() (same as interpreter)
instead of gwrt_print_sng(), producing correct type-specific output.

OPEN fix: analysis pass skips OPEN statement arguments to avoid
misidentifying OUTPUT/INPUT/APPEND as variable names.

OPEN/CLOSE/INPUT: emit skip stubs (file I/O compilation is Phase 3).

19 of 72 tests now pass (up from 17). New: hanoi, text_adventure.
This commit is contained in:
Eremey Valetov
2026-03-29 10:41:02 -04:00
parent 248dfaae11
commit 7ff24ae85e
4 changed files with 227 additions and 14 deletions
+146 -14
View File
@@ -363,12 +363,45 @@ static void emit_atom(void)
}
}
/* Variable */
/* Variable or array element */
if (is_letter(tok)) {
char name[2];
gw_valtype_t type = parse_var(name);
skip_spaces();
if (cur() == '(') {
/* Array element access — buffer subscripts to get ndims */
advance(); /* skip ( */
char *sub_bufs[8];
int ndims = 0;
do {
if (ndims > 0 && cur() == ',') advance();
FILE *orig = out;
char *sbuf = NULL; size_t ssz = 0;
out = open_memstream(&sbuf, &ssz);
emit_num_expr();
fclose(out);
out = orig;
sub_bufs[ndims++] = sbuf;
} while (cur() == ',' && ndims < 8);
if (cur() == ')') advance();
EMIT("gwrt_array_elem(\"%c%c\", %d, %d, (int[]){",
name[0], name[1] ? name[1] : 0, type, ndims);
for (int d = 0; d < ndims; d++) {
if (d > 0) EMIT(", ");
EMIT("(int)(%s)", sub_bufs[d]);
free(sub_bufs[d]);
}
EMIT("})->");
switch (type) {
case VT_INT: EMIT("ival"); break;
case VT_SNG: EMIT("fval"); break;
case VT_DBL: EMIT("dval"); break;
default: EMIT("fval"); break;
}
return;
}
if (type == VT_STR) {
/* String var used in numeric context — likely LEN or similar */
EMIT("0 /* str var in num ctx */");
} else {
emit_varname(name, type);
@@ -562,10 +595,34 @@ static void emit_str_expr(void)
}
}
/* String variable */
/* String variable or array element */
if (is_letter(tok)) {
char name[2];
gw_valtype_t type = parse_var(name);
skip_spaces();
if (cur() == '(' && type == VT_STR) {
/* String array element */
advance();
char *sub_bufs[8]; int ndims = 0;
do {
if (ndims > 0 && cur() == ',') advance();
FILE *orig = out; char *sb = NULL; size_t ss = 0;
out = open_memstream(&sb, &ss);
emit_num_expr();
fclose(out); out = orig;
sub_bufs[ndims++] = sb;
} while (cur() == ',' && ndims < 8);
if (cur() == ')') advance();
EMIT("gw_str_copy(&gwrt_array_elem(\"%c%c\", %d, %d, (int[]){",
name[0], name[1] ? name[1] : 0, type, ndims);
for (int d = 0; d < ndims; d++) {
if (d > 0) EMIT(", ");
EMIT("(int)(%s)", sub_bufs[d]);
free(sub_bufs[d]);
}
EMIT("})->sval)");
return;
}
if (type == VT_STR) {
EMIT("gw_str_copy(&");
emit_varname(name, type);
@@ -628,9 +685,9 @@ static void emit_print(void)
emit_str_expr();
EMIT("; gwrt_print_str(_s); gw_str_free(&_s); }\n");
} else {
EMIT(" gwrt_print_sng((float)(");
EMIT(" { gw_value_t _pv = {.type = VT_SNG, .fval = (float)(");
emit_num_expr();
EMIT("));\n");
EMIT(")}; gw_print_value(&_pv); }\n");
}
need_newline = true;
}
@@ -645,11 +702,44 @@ static void emit_assignment(void)
gw_valtype_t type = parse_var(name);
skip_spaces();
/* Array element? */
/* Array element assignment: A(i) = expr */
if (cur() == '(') {
/* TODO: array assignment */
EMIT(" /* TODO: array assignment */\n");
while (cur() && cur() != ':') tp++;
advance(); /* skip ( */
EMIT(" { int _subs[] = {(int)(");
emit_num_expr();
int ndims = 1;
while (cur() == ',') {
advance();
EMIT("), (int)(");
emit_num_expr();
ndims++;
}
EMIT(")};\n");
if (cur() == ')') advance();
skip_spaces();
if (cur() == TOK_EQ) advance();
/* Call runtime to get element pointer */
EMIT(" gw_value_t *_elem = gwrt_array_elem(\"%c%c\", %d, %d, _subs);\n",
name[0], name[1] ? name[1] : 0, type, ndims);
if (type == VT_STR) {
EMIT(" gw_str_free(&_elem->sval);\n");
EMIT(" _elem->sval = ");
emit_str_expr();
EMIT(";\n _elem->type = VT_STR;\n");
} else {
EMIT(" *_elem = (gw_value_t){.type=%d};\n", type);
switch (type) {
case VT_INT: EMIT(" _elem->ival = (int16_t)("); break;
case VT_SNG: EMIT(" _elem->fval = (float)("); break;
case VT_DBL: EMIT(" _elem->dval = (double)("); break;
default: EMIT(" _elem->fval = (float)("); break;
}
emit_num_expr();
EMIT(");\n");
}
EMIT(" }\n");
return;
}
@@ -895,9 +985,37 @@ static void emit_stmt(void)
/* DIM */
if (tok == TOK_DIM) {
advance();
/* DIM is handled at compile time for static arrays — skip for now */
EMIT(" /* DIM (compile-time) */\n");
while (cur() && cur() != ':' && cur() != 0) tp++;
while (cur() && cur() != ':' && cur() != 0) {
skip_spaces();
if (!is_letter(cur())) break;
char name[2];
gw_valtype_t type = parse_var(name);
skip_spaces();
if (cur() != '(') break;
advance();
/* Buffer dimensions */
char *dim_bufs[8]; int ndims = 0;
do {
if (ndims > 0 && cur() == ',') advance();
FILE *orig = out; char *db = NULL; size_t ds = 0;
out = open_memstream(&db, &ds);
emit_num_expr();
fclose(out); out = orig;
dim_bufs[ndims++] = db;
} while (cur() == ',' && ndims < 8);
if (cur() == ')') advance();
EMIT(" gwrt_dim(\"%c%c\", %d, %d, (int[]){",
name[0], name[1] ? name[1] : 0, type, ndims);
for (int d = 0; d < ndims; d++) {
if (d > 0) EMIT(", ");
EMIT("(int)(%s)", dim_bufs[d]);
free(dim_bufs[d]);
}
EMIT("});\n");
skip_spaces();
if (cur() == ',') advance();
else break;
}
return;
}
@@ -1014,6 +1132,20 @@ static void emit_stmt(void)
return;
}
/* OPEN / CLOSE — file I/O (Phase 3: needs inline argument parsing) */
if (tok == TOK_OPEN || tok == TOK_CLOSE) {
EMIT(" /* %s — file I/O not yet compiled */\n", tok == TOK_OPEN ? "OPEN" : "CLOSE");
while (cur() && cur() != ':' && cur() != 0) tp++;
return;
}
/* INPUT */
if (tok == TOK_INPUT) {
advance();
EMIT(" /* INPUT — not yet compiled */\n");
while (cur() && cur() != ':' && cur() != 0) tp++;
return;
}
/* TRON/TROFF */
if (tok == TOK_TRON) { advance(); return; }
if (tok == TOK_TROFF) { advance(); return; }
@@ -1065,9 +1197,9 @@ static void emit_stmt(void)
EMIT("; gwrt_print_str(_s); gw_str_free(&_s); }\n");
EMIT(" gwrt_print_cstr(\"\\\"\");\n");
} else {
EMIT(" gwrt_print_sng((float)(");
EMIT(" { gw_value_t _pv = {.type = VT_SNG, .fval = (float)(");
emit_num_expr();
EMIT("));\n");
EMIT(")}; gw_print_value(&_pv); }\n");
}
skip_spaces();
if (cur() == ',') advance();