feat(v4): the ROM's symbol table
(FIND) ( -- rec | 0 ), (DEFINE) ( value kind -- ) and (OPCODE) ( -- op | -1 ), entries 3-5. Names are refused as text.c's define refuses them, compared case by case with text.c; a set variable may be set again. 256 hash heads, records growing up and names growing down in dictionary space, used only while the ROM assembles. text.c gains the data directives #, and ", (the ROM's language; its mnemonic and reserved-word tables are data); the nucleus image is byte-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
080811dbd2
commit
07911dcf91
+85
-12
@@ -65,7 +65,8 @@ static int is_reserved(const char *s)
|
||||
return strcmp(s, ":") == 0 || strcmp(s, "macro") == 0 || strcmp(s, "endmacro") == 0
|
||||
|| strcmp(s, "\\") == 0 || strcmp(s, "(") == 0
|
||||
|| strcmp(s, "FOR") == 0 || strcmp(s, "NEXT") == 0 || strcmp(s, "UNEXT") == 0
|
||||
|| strcmp(s, "header") == 0 || strcmp(s, "constant") == 0 || flag_of(s) != 0;
|
||||
|| strcmp(s, "header") == 0 || strcmp(s, "constant") == 0
|
||||
|| strcmp(s, "#,") == 0 || strcmp(s, "\",") == 0 || flag_of(s) != 0;
|
||||
}
|
||||
|
||||
static int is_label_def(const char *s)
|
||||
@@ -171,6 +172,23 @@ static void put_cell(v4_text *t, v4_cell value)
|
||||
as->here++;
|
||||
}
|
||||
|
||||
/* NAME as a counted string at the next word address: its count byte, then
|
||||
* its characters, four bytes to a cell, low byte first, zero-padded to a
|
||||
* whole cell. The layout of a header's name, and of `",`. */
|
||||
static void lay_name(v4_text *t, const char *name)
|
||||
{
|
||||
unsigned len = (unsigned)strlen(name), cells = (len + 4u) / 4u, i, b;
|
||||
for (i = 0; i < cells; i++) {
|
||||
v4_ucell w = 0;
|
||||
for (b = 0; b < 4; b++) {
|
||||
unsigned at = 4u * i + b; /* byte 0 is the count */
|
||||
unsigned ch = at == 0 ? len : (at <= len ? (unsigned char)name[at - 1u] : 0u);
|
||||
w |= (v4_ucell)ch << (8u * b);
|
||||
}
|
||||
put_cell(t, (v4_cell)w);
|
||||
}
|
||||
}
|
||||
|
||||
/* `header NAME`: a dictionary entry for NAME, as capsule/dict.v4 lays one
|
||||
* out, in front of the word the next `:` starts:
|
||||
* the name: its count byte, then its characters, four bytes to a cell,
|
||||
@@ -180,7 +198,7 @@ static void put_cell(v4_text *t, v4_cell value)
|
||||
static void header(v4_text *t, reader *r)
|
||||
{
|
||||
char name[V4_TEXT_MAX_TOKEN + 1u];
|
||||
unsigned len, cells, i;
|
||||
unsigned len;
|
||||
v4_cell nfa;
|
||||
|
||||
if (r->depth != 1) { fail(t, "not allowed in a macro", "header"); return; }
|
||||
@@ -190,16 +208,7 @@ static void header(v4_text *t, reader *r)
|
||||
if (len > 31) { fail(t, "a header's name is at most 31 characters", name); return; }
|
||||
end_word(t);
|
||||
nfa = v4_asm_label(&t->as);
|
||||
cells = (len + 4u) / 4u;
|
||||
for (i = 0; i < cells; i++) {
|
||||
v4_ucell w = 0;
|
||||
for (unsigned b = 0; b < 4; b++) {
|
||||
unsigned at = 4u * i + b; /* byte 0 is the count */
|
||||
unsigned ch = at == 0 ? len : (at <= len ? (unsigned char)name[at - 1u] : 0u);
|
||||
w |= (v4_ucell)ch << (8u * b);
|
||||
}
|
||||
put_cell(t, (v4_cell)w);
|
||||
}
|
||||
lay_name(t, name);
|
||||
put_cell(t, 0);
|
||||
put_cell(t, nfa);
|
||||
put_cell(t, t->latest);
|
||||
@@ -357,6 +366,68 @@ static void constant_directive(v4_text *t, reader *r)
|
||||
define(t, name, KIND_CONST, v);
|
||||
}
|
||||
|
||||
/* A VALUE in a directive: a number, a constant, CONST+N, or &NAME of a word
|
||||
* already defined. 1 and its value, or 0 having failed. */
|
||||
static int value_of(v4_text *t, const char *tok, v4_cell *out)
|
||||
{
|
||||
const v4_text_symbol *s;
|
||||
int big;
|
||||
if (number_of(tok, out, &big)) {
|
||||
if (big) { fail(t, "number does not fit a cell", tok); return 0; }
|
||||
return 1;
|
||||
}
|
||||
if (tok[0] == '&' && tok[1] != 0) {
|
||||
s = find(t, tok + 1);
|
||||
if (s && s->kind == KIND_WORD) { *out = s->value; return 1; }
|
||||
fail(t, "& needs a word that is already defined", tok + 1);
|
||||
return 0;
|
||||
}
|
||||
s = find(t, tok);
|
||||
if (s && s->kind == KIND_CONST) { *out = s->value; return 1; }
|
||||
if (!s) {
|
||||
const char *plus = strrchr(tok, '+');
|
||||
if (plus && plus != tok && plus[1] != 0) {
|
||||
char left[V4_TEXT_MAX_TOKEN + 1u];
|
||||
const v4_text_symbol *c;
|
||||
v4_cell n;
|
||||
size_t len = (size_t)(plus - tok);
|
||||
memcpy(left, tok, len);
|
||||
left[len] = 0;
|
||||
c = find(t, left);
|
||||
if (c && c->kind == KIND_CONST && number_of(plus + 1, &n, &big) && !big) {
|
||||
*out = (v4_cell)((v4_ucell)c->value + (v4_ucell)n);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
fail(t, "not a value", tok);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* `#, VALUE`: one cell of data at the next word address. */
|
||||
static void cell_directive(v4_text *t, reader *r)
|
||||
{
|
||||
char tok[V4_TEXT_MAX_TOKEN + 1u];
|
||||
v4_cell v;
|
||||
if (r->depth != 1) { fail(t, "not allowed in a macro", "#,"); return; }
|
||||
if (!next_token(t, r, tok)) { if (!t->failed) fail(t, "#, without a value", NULL); return; }
|
||||
if (!value_of(t, tok, &v)) return;
|
||||
(void)v4_asm_label(&t->as);
|
||||
put_cell(t, v);
|
||||
check_asm(t, "#,");
|
||||
}
|
||||
|
||||
/* `", TOKEN`: TOKEN, whatever its characters, as a counted string. */
|
||||
static void string_directive(v4_text *t, reader *r)
|
||||
{
|
||||
char tok[V4_TEXT_MAX_TOKEN + 1u];
|
||||
if (r->depth != 1) { fail(t, "not allowed in a macro", "\","); return; }
|
||||
if (!raw_token(t, r, tok)) { fail(t, "\", without a string, or one too long", NULL); return; }
|
||||
(void)v4_asm_label(&t->as);
|
||||
lay_name(t, tok);
|
||||
check_asm(t, tok);
|
||||
}
|
||||
|
||||
static void one_token(v4_text *t, reader *r, const char *tok)
|
||||
{
|
||||
const v4_text_symbol *s;
|
||||
@@ -381,6 +452,8 @@ static void one_token(v4_text *t, reader *r, const char *tok)
|
||||
}
|
||||
if (strcmp(tok, "macro") == 0) { define_macro(t, r); return; }
|
||||
if (strcmp(tok, "constant") == 0) { constant_directive(t, r); return; }
|
||||
if (strcmp(tok, "#,") == 0) { cell_directive(t, r); return; }
|
||||
if (strcmp(tok, "\",") == 0) { string_directive(t, r); return; }
|
||||
if (strcmp(tok, "endmacro") == 0) { fail(t, "endmacro without macro", NULL); return; }
|
||||
|
||||
if (is_label_def(tok)) {
|
||||
|
||||
Reference in New Issue
Block a user