diff --git a/include/gwrt.h b/include/gwrt.h index 32e92a0..2b4d930 100644 --- a/include/gwrt.h +++ b/include/gwrt.h @@ -41,6 +41,12 @@ extern jmp_buf gwrt_error_jmp; extern int gwrt_error_target; /* ON ERROR GOTO label, 0 = none */ extern int gwrt_resume_label; /* label for RESUME NEXT */ +/* Array element access (wraps gw_array_element) */ +gw_value_t *gwrt_array_elem(const char *name, int type, int ndims, int *subs); + +/* DIM statement (wraps gw_stmt_dim via text_ptr) */ +void gwrt_dim(const char *name, int type, int ndims, int *dims); + /* Print helpers (wrappers around existing print.c) */ void gwrt_print_sng(float v); void gwrt_print_dbl(double v); diff --git a/src/analysis.c b/src/analysis.c index 9628c99..8544add 100644 --- a/src/analysis.c +++ b/src/analysis.c @@ -140,6 +140,13 @@ static void scan_tokens(analysis_t *a, uint8_t *tokens, int len) continue; } + /* OPEN — skip the mode/filename tokens to avoid misidentifying + * OUTPUT/INPUT/APPEND/RANDOM as variable names */ + if (tok == TOK_OPEN) { + while (p < end && *p && *p != ':') p++; + continue; + } + /* GOTO/GOSUB/THEN/RESTORE/RESUME/RUN — mark targets */ if (tok == TOK_GOTO || tok == TOK_GOSUB || tok == TOK_THEN || tok == TOK_RESTORE || tok == TOK_RESUME || tok == TOK_RUN) { diff --git a/src/codegen.c b/src/codegen.c index ccda246..d6fe12e 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -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(); diff --git a/src/gwrt.c b/src/gwrt.c index 6dc2240..dcd8b6c 100644 --- a/src/gwrt.c +++ b/src/gwrt.c @@ -144,6 +144,74 @@ int gwrt_gosub_pop(void) return gosub_stack[--gosub_sp]; } +/* --- Array support --- */ + +/* Find or auto-create an array, then index into it */ +gw_value_t *gwrt_array_elem(const char *name, int type, int ndims, int *subs) +{ + char n[2] = {name[0], name[1]}; + + /* Find or auto-create the array */ + array_entry_t *arr = NULL; + for (int i = 0; i < gw.array_count; i++) { + if (gw.arrays[i].name[0] == n[0] && gw.arrays[i].name[1] == n[1] + && (int)gw.arrays[i].type == type) { + arr = &gw.arrays[i]; + break; + } + } + if (!arr) { + /* Auto-DIM with default size 10 per dimension */ + if (gw.array_count >= 64) gw_error(ERR_OM); + arr = &gw.arrays[gw.array_count++]; + arr->name[0] = n[0]; + arr->name[1] = n[1]; + arr->type = type; + arr->ndims = ndims; + arr->total_elements = 1; + for (int d = 0; d < ndims; d++) { + arr->dims[d] = 10; + arr->total_elements *= (11 - gw.option_base); + } + arr->data = calloc(arr->total_elements, sizeof(gw_value_t)); + if (!arr->data) gw_error(ERR_OM); + for (int j = 0; j < arr->total_elements; j++) + arr->data[j].type = type; + } + + /* Compute flat index (column-major) */ + int index = 0; + int stride = 1; + for (int d = 0; d < ndims; d++) { + int sub = subs[d] - gw.option_base; + int dim_size = arr->dims[d] + 1 - gw.option_base; + if (sub < 0 || sub >= dim_size) gw_error(ERR_FC); + index += sub * stride; + stride *= dim_size; + } + if (index < 0 || index >= arr->total_elements) gw_error(ERR_FC); + return &arr->data[index]; +} + +void gwrt_dim(const char *name, int type, int ndims, int *dims) +{ + if (gw.array_count >= 64) gw_error(ERR_OM); + array_entry_t *arr = &gw.arrays[gw.array_count++]; + arr->name[0] = name[0]; + arr->name[1] = name[1]; + arr->type = type; + arr->ndims = ndims; + arr->total_elements = 1; + for (int d = 0; d < ndims; d++) { + arr->dims[d] = dims[d]; + arr->total_elements *= (dims[d] + 1 - gw.option_base); + } + arr->data = calloc(arr->total_elements, sizeof(gw_value_t)); + if (!arr->data) gw_error(ERR_OM); + for (int j = 0; j < arr->total_elements; j++) + arr->data[j].type = type; +} + /* --- Event + GC check (called at each line boundary) --- */ void gwrt_check_line(uint16_t line_num)