feat(v4): the ROM assembles text as text.c does -- words, labels, macros, FOR, directives, start

word.f18: (NEXT-TOKEN) reads the console or a macro being expanded; labels,
branches by name (a label of the word, or a word, now or later), the
table of branches waiting, end of word, FOR/NEXT/UNEXT, macros, &NAME,
CONST+N, and (ONE), which dispatches a token.  A forward branch to a name
not yet defined waits on a placeholder symbol, filled in by (DEFINE).
dir.f18: constant set here #, ", store, and start, which resolves, clears
the tables the ROM used and runs the word it names.  main.f18: the ROM
itself, entry 12; on an error it stops at (ROM-FAILED) with the code and
line in its state, for the loader to report.  sym.f18 generalized: any
counted string, placeholders, a hash of only a name's own cells.

test_host_rom_asm.c gives test_text.c's own texts (accepted and refused),
its four real definitions and the ROM's directives to text.c and to the
ROM: the same words, the same errors on the same lines, at both widths.
The ROM is 2036 words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-15 12:24:08 -04:00
co-authored by Claude Opus 5.5
parent c233cb6536
commit 084c520a54
10 changed files with 1047 additions and 39 deletions
+49
View File
@@ -149,6 +149,38 @@
#define ROM_PTR (OUT_W - 124) /* (SAME?), (DEFINE): where in a name */
#define ROM_I (OUT_W - 123) /* where in the token */
#define ROM_WI (OUT_W - 122) /* (WALK): which entry of a table */
#define ROM_NREF (OUT_W - 121) /* word.f18: how many branches wait for a target */
#define ROM_NLAB (OUT_W - 120) /* how many labels the word being assembled has */
#define ROM_WNP (OUT_W - 119) /* cells of the word's name area used */
#define ROM_NFOR (OUT_W - 118) /* how many FORs are open */
#define ROM_FORS (OUT_W - 117) /* where each began, 8 cells */
#define ROM_RDEPTH (OUT_W - 109) /* how many macros are being expanded */
#define ROM_RPTRS (OUT_W - 108) /* where each is reading, 8 cells */
#define ROM_T1 (OUT_W - 100) /* working cells */
#define ROM_T2 (OUT_W - 99)
#define ROM_T3 (OUT_W - 98)
#define ROM_T4 (OUT_W - 97)
#define ROM_CFROM (OUT_W - 96)
#define ROM_CTO (OUT_W - 95)
#define ROM_CN (OUT_W - 94)
#define ROM_RAW (OUT_W - 93) /* in.f18: 1 while a token is read raw, ( and \ being names */
#define ROM_T5 (OUT_W - 92)
#define ROM_T6 (OUT_W - 91)
#define ROM_MLEN (OUT_W - 90) /* the length of the token saved in ROM_MTEMP */
#define ROM_ORIGIN 16 /* where the system's code begins */
/* The ROM's other tables, used only while it assembles (cleared at `start`): in the block window, the branches
* waiting -- four cells each: the word, the line, a symbol record (or, while local, a name), 1 if local -- the
* labels of the word being assembled -- a name and an address -- and their names; in the text input buffer, a
* saved token, a character to a cell, a macro's name and its body being collected. */
#define ROM_REFS BUF0_W /* 128 entries */
#define ROM_REFS_MAX 128
#define ROM_LABELS (BUF0_W + 512) /* 64 entries */
#define ROM_WNAMES (BUF0_W + 640) /* 384 cells */
#define ROM_WN_SIZE 384
#define ROM_TSAVE TIB_W /* 16 cells */
#define ROM_MTEMP (TIB_W + 16) /* 64 cells */
#define ROM_MBODY (TIB_W + 80) /* 180 cells */
#define ROM_MBODY_SIZE 180
/* THE ROM'S SYMBOL TABLE, used only while it assembles, in dictionary space (cleared at `start`): 256 hash heads,
* then records growing up -- link, name, kind, value -- and names, as counted strings, growing down from the top. */
#define ROM_SYMH DICT_W
@@ -170,6 +202,23 @@
#define ROM_ERR_NAMES 5 /* the symbol table is full: "too many names" */
#define ROM_ERR_FIT 6 /* memory is full, or a branch cannot reach: "does not fit" */
#define ROM_ERR_OPCODE 7 /* not an opcode the packer takes there */
#define ROM_ERR_IN_MACRO 8 /* "not allowed in a macro" */
#define ROM_ERR_MACRO 9 /* "macro without endmacro", "endmacro without macro" */
#define ROM_ERR_LABEL_DUP 10 /* "label already defined in this word" */
#define ROM_ERR_LABELS 11 /* "too many labels in one word" */
#define ROM_ERR_FOR 12 /* FOR nested too deep, NEXT or UNEXT without FOR, FOR without NEXT */
#define ROM_ERR_UNEXT 13 /* "FOR ... UNEXT must fit one instruction word and hold no literal" */
#define ROM_ERR_TARGET 14 /* "not something to branch to" */
#define ROM_ERR_UNDEFINED 15 /* "never defined" */
#define ROM_ERR_BIG 16 /* "number does not fit a cell" */
#define ROM_ERR_AMP 17 /* "& needs a word that is already defined" */
#define ROM_ERR_FETCH_P 18 /* "write the number, not @p" */
#define ROM_ERR_MISSING 19 /* a name, a target, a value or a string missing at the end */
#define ROM_ERR_DEEP 20 /* "macros nested too deep" */
#define ROM_ERR_REFS 21 /* "too many unresolved branches" */
#define ROM_ERR_VALUE 22 /* "not a value", "not a number" */
#define ROM_ERR_NO_START 23 /* the input ended with no start */
#define ROM_ERR_START 24 /* start: not a word */
#define ROM_ADDR_TOP ((v4_cell)(V4_NODE_WORDS + V4_ROM_WORDS - 1u)) /* the top of the address space */
#define WORD_DEFINED (BUF0_W - 11) /* the xt of the word that is told of each new entry, or 0 */
#define WORD_FORGOTTEN (BUF0_W - 12) /* the xt of the word that is told when entries go, or 0 */
+115
View File
@@ -0,0 +1,115 @@
/* rom_asm_cases.h -- the texts of v4/tests/test_text.c, accepted and refused, that the ROM's language has
* (no header and no flags). Extracted once from test_text.c; each is given to text.c and to the ROM, and
* test_host_rom_asm.c requires the same outcome. */
static const char *const rom_asm_cases[] = {
": T 123 ;",
": T -5 ;",
": T $FF ;",
": T $ff $Ab + ;",
": T 0 ;",
": T 1 2 3 4 5 6 7 + + + + + + ;",
": T 4294967295 ;",
": T -2147483648 ;",
": T $FFFFFFFF ;",
": T 4294967296 ;",
": T -2147483649 ;",
": T $100000000 ;",
": T 18446744073709551615 ;",
": T -9223372036854775808 ;",
": T $FFFFFFFFFFFFFFFF ;",
": T 18446744073709551616 ;",
": T -9223372036854775809 ;",
": T $10000000000000000 ;",
": T 99999999999999999999999999 ;",
": T VAR ;",
": ST ( x -- ) VAR a! ! ; : LD ( -- x ) VAR a! @ ;",
"\\ a line comment\n: T ( a stack comment ) 7 \\ another\n ( and\n one over two lines ) 8 + ; \\ the end",
": (T) 5 ; : T (T) (T) + ;",
": T 1 ( never closed",
": T @p ;",
": A 3 ; : T A A + ;",
": T A A + ; : A 4 ;",
": T jump A : A 9 ;",
": T call A 1 + ; : A 9 ;",
": A 1 ; : B A A + ; : C B B + ; : T C C + ;",
": T 5 \n : U 1 + ;",
": T ( n -- 1|2 ) if Z drop 1 ; Z: drop 2 ;",
": T ( n -- 0 ) L: if DONE -1 + jump L DONE: ;",
": T ( n -- f ) -if P drop -1 ; P: drop 0 ;",
": A ( n -- 1|2 ) if L drop 1 ; L: drop 2 ; : T ( n -- 3|4 ) if L drop 3 ; L: drop 4 ;",
": L 50 ; : T ( n -- x ) if L drop 1 ; L: drop 2 ;",
": L 50 ; : T ( n -- x ) L: if DONE -1 + jump L DONE: drop 3 ;",
": L drop 50 ; : T ( n -- x ) if L drop 1 ; : U 2 ;",
": L drop 50 ; : T ( n -- x ) if L drop 1 ;",
": T ( n -- x ) if OUT drop 1 ; : OUT drop 77 ;",
": T L: 1 L: 2 ;",
": T if NOWHERE ;\n: U 1 ;",
"\n\n: T 1 MISSING + ;",
": T jump",
": T jump 5 ;",
": T jump VAR ;",
": T jump dup ;",
": T ( n -- n+5 ) 4 FOR 1 + NEXT ;",
": T ( n -- n*8 ) 2 FOR 2* UNEXT ;",
": T ( n -- x ) 1 FOR 2 FOR 2* UNEXT NEXT ;",
": T ( n -- x ) 2 FOR 2* UNEXT 1 + ;",
": T ( n -- x ) 2 FOR dup + 2* nop UNEXT ;",
": T 2 FOR dup + 2* nop nop nop UNEXT ;",
": T 2 FOR 1 + UNEXT ;",
": T NEXT ;",
": T UNEXT ;",
": T 3 FOR 1 + ;\n: U ;",
": T 0 FOR 0 FOR 0 FOR 0 FOR 0 FOR 0 FOR 0 FOR 0 FOR 0 FOR ;",
"macro SWAP over push push drop pop pop endmacro : T ( a b -- b ) SWAP drop ;",
"macro 1+ 1 + endmacro macro 2+ 1+ 1+ endmacro : T 2+ 2+ ;",
"macro TEN ( a comment ) 10 \\ and another\n endmacro : T TEN TEN + ;",
"macro SHL3 2 FOR 2* UNEXT endmacro : T SHL3 ;",
": A 6 ; macro CALLS A A + endmacro : T CALLS ;",
"macro NOTHING endmacro : T 5 NOTHING ;",
"macro M L: endmacro",
"macro M : X ; endmacro",
"macro M macro N endmacro endmacro",
"macro M 1 2 3",
"macro",
": T endmacro ;",
"macro M M endmacro : T M ;",
": A 1 ;\n: A 2 ;",
": VAR 1 ;",
"macro A 1 endmacro : A 2 ;",
": dup 1 ;",
": 12 1 ;",
": FOR 1 ;",
"macro + 1 endmacro",
": X: 1 ;",
":",
": T THIS-NAME-IS-MUCH-TOO-LONG-TO-BE-A-NAME-IN-THIS-ASSEMBLER-BY-A-WIDE-MARGIN ;",
": Dup 3 ; : T Dup Dup + ;",
": 2DUP over over ; : 1+ 1 + ; : T ( a b -- 2a+2b+1 ) 2DUP + + + 1+ ;",
": T VAR+3 ;",
": T VAR+0 VAR+10 + ;",
": VAR+1 77 ; : T VAR+1 ;",
": T VAR+ ;",
": T VAR+x ;",
": T NOPE+1 ;",
": A 5 ; : T &A ;",
": A 5 ; : T &A push ;",
": T &A ; : A 5 ;",
": T &VAR ;",
": &X 1 ;",
": T 1 ;",
": T 1 ;\n: T 2 ;",
"constant SEVEN 7 constant MINUS -2 constant BIG $7F : T SEVEN MINUS + BIG + ;",
"constant K 3 : T K+2 ;",
"constant K 3 constant K 4",
"constant dup 3",
"constant K",
"constant K x",
": constant ;",
"constant K 9 : T ; #, 5 #, -1 #, K #, K+2 #, &T \", ab \", ( \", abcde",
": T dup #, 7 ;",
"#, x",
"#,",
"\",",
": #, ;",
": \", ;",
};
+1 -1
View File
@@ -30,7 +30,7 @@ extern const unsigned v4_rom_32_words;
/* The entry table, in its fixed order: entry i is at V4_ROM_BASE + i. */
static const char *const rom_entries[] = {
"(KEY)", "(TOKEN)", "(NUMBER)", "(FIND)", "(DEFINE)", "(OPCODE)",
"(OP)", "(LIT)", "(BRANCH)", "(BRANCH>)", "(RESOLVE)", "(LABEL)"
"(OP)", "(LIT)", "(BRANCH)", "(BRANCH>)", "(RESOLVE)", "(LABEL)", "(ROM)"
};
#define ROM_ENTRIES (sizeof rom_entries / sizeof rom_entries[0])
+191
View File
@@ -0,0 +1,191 @@
/* test_host_rom_asm.c -- the ROM assembles text exactly as v4/src/text.c does.
*
* Plan Tasks 6 and 7. The ROM is started at its entry (12) and fed a text
* through the console, ending with `start`; text.c assembles the same text.
* Where text.c accepts it, the ROM must lay down the same words and jump to
* the word start names; where text.c refuses it, the ROM must stop at
* (ROM-FAILED) with the same class of error, on the same line. The texts
* are test_text.c's own (rom_asm_cases.h), test_text.c's four real
* definitions, and the ROM's own directives: set, here, store, start.
*/
#include "rom_harness.h"
#include "v4/text.h"
#include "rom_asm_cases.h"
static int failures = 0, checks = 0;
#define CHECK(c,...) do{checks++; if(!(c)){failures++; printf("FAIL %s:%d: ",__FILE__,__LINE__); printf(__VA_ARGS__); printf("\n");}}while(0)
#define VARS ((v4_cell)(V4_NODE_WORDS - 16u)) /* test_text.c's VAR */
static v4_node a, b;
static v4_text tx;
static char in[1u << 16];
/* the ROM error code for one of text.c's messages */
static v4_cell code_of(const char *m)
{
static const struct { const char *s; v4_cell c; } map[] = {
{ "label already defined", ROM_ERR_LABEL_DUP }, { "& needs", ROM_ERR_AMP },
{ "macros nested too deep", ROM_ERR_DEEP }, { "macro without", ROM_ERR_MACRO },
{ "endmacro without", ROM_ERR_MACRO }, { "nested too deep", ROM_ERR_FOR },
{ "NEXT without", ROM_ERR_FOR }, { "FOR without", ROM_ERR_FOR },
{ "already defined", ROM_ERR_DEFINED }, { "cannot be used as a name", ROM_ERR_BAD_NAME },
{ "does not fit a cell", ROM_ERR_BIG }, { "does not fit", ROM_ERR_FIT },
{ "branch cannot reach", ROM_ERR_FIT }, { "name too long", ROM_ERR_TOO_LONG },
{ "comment not closed", ROM_ERR_COMMENT }, { "not allowed in a macro", ROM_ERR_IN_MACRO },
{ "too many labels", ROM_ERR_LABELS }, { "must fit one instruction word", ROM_ERR_UNEXT },
{ "not something to branch to", ROM_ERR_TARGET }, { "never defined", ROM_ERR_UNDEFINED },
{ "write the number", ROM_ERR_FETCH_P }, { "too many unresolved", ROM_ERR_REFS },
{ "not a value", ROM_ERR_VALUE }, { "not a number", ROM_ERR_VALUE },
{ "too many names", ROM_ERR_NAMES }, { "out of name space", ROM_ERR_NAMES },
{ "without", ROM_ERR_MISSING },
};
unsigned i;
for (i = 0; i < sizeof map / sizeof map[0]; i++) if (strstr(m, map[i].s)) return map[i].c;
return -1;
}
static unsigned line_of(const char *m)
{
unsigned l = 0;
return sscanf(m, "line %u:", &l) == 1 ? l : 0;
}
/* Run the ROM on `text` (EOT is added). 1: it started -- P left the ROM for
* RAM; 0: it stopped at (ROM-FAILED); -1: neither within the steps allowed. */
static int rom_run(const char *text)
{
static long failed_lo = -1, failed_hi = -1;
size_t len = strlen(text), fed = 0;
long steps = 0;
if (failed_lo < 0) { /* where (ROM-FAILED) is: looked up once */
FILE *f = fopen(V4_ROM_SYM, "r");
char sym[80]; long ad, lo = -1, hi = -1;
while (f && fscanf(f, "%79s %ld", sym, &ad) == 2) if (strcmp(sym, "(ROM-FAILED)") == 0) lo = ad;
if (f) rewind(f);
while (f && fscanf(f, "%79s %ld", sym, &ad) == 2) if (ad > lo && (hi < 0 || ad < hi)) hi = ad;
if (f) fclose(f);
failed_lo = lo; failed_hi = hi < 0 ? (long)V4_ROM_BASE + (long)ROM_IMAGE_WORDS : hi;
}
rom_boot(&b);
b.p = V4_ROM_BASE + 12;
while (steps++ < 50000000L) {
if (fed <= len) fed += v4_node_console_feed(&b, text + fed, (unsigned)(len + 1 - fed));
if (b.p < V4_ROM_BASE) return 1;
if ((long)b.p >= failed_lo && (long)b.p < failed_hi) return 0;
(void)v4_exec_step_word(&b, &rom_es, &rom_h);
if (b.stopped) return -1;
}
return -1;
}
/* text.c and the ROM on the same text, with a word to start at after it */
static void same(const char *text)
{
static char ta[1u << 15];
int okA, rb;
v4_cell w, hereA, endA;
snprintf(ta, sizeof ta, "constant VAR %ld\nconstant N-1 %d\n%s\n: ZZEND ;\n", (long)VARS, V4_CELL_BITS - 1, text);
v4_node_reset(&a);
v4_text_begin(&tx, &a, ROM_ORIGIN);
okA = v4_text_assemble(&tx, ta) && v4_text_finish(&tx);
snprintf(in, sizeof in, "%s", ta); /* start on ZZEND's line: the ROM sees as many lines as text.c */
in[strlen(in) - 1] = 0;
strcat(in, " start ZZEND\n\x04");
rb = rom_run(in);
if (okA) {
hereA = v4_text_here(&tx);
endA = v4_text_word(&tx, "ZZEND");
CHECK(rb == 1, "[%s] text.c accepts; the ROM %s (code %ld line %ld)", text,
rb == 0 ? "refused" : "did not finish", (long)b.mem[ROM_FAILED], (long)b.mem[ROM_ERRLINE] + 1);
if (rb != 1) return;
CHECK(b.p == endA, "[%s] the ROM started at ZZEND: P %ld, text.c %ld", text, (long)b.p, (long)endA);
CHECK(b.mem[ROM_HERE] == hereA, "[%s] here: ROM %ld, text.c %ld", text, (long)b.mem[ROM_HERE], (long)hereA);
for (w = ROM_ORIGIN; w < hereA; w++) if (a.mem[w] != b.mem[w]) break;
CHECK(w == hereA, "[%s] word %ld differs: text.c %lx, ROM %lx", text, (long)w,
(unsigned long)a.mem[w], (unsigned long)b.mem[w]);
} else {
const char *m = v4_text_error(&tx);
v4_cell want = code_of(m);
unsigned l = line_of(m);
CHECK(rb == 0, "[%s] text.c refuses (%s); the ROM %s", text, m, rb == 1 ? "accepted" : "did not finish");
if (rb != 0) return;
CHECK(b.mem[ROM_FAILED] == want, "[%s] text.c: %s; ROM code %ld, want %ld", text, m, (long)b.mem[ROM_FAILED], (long)want);
if (l > 2) CHECK((unsigned)b.mem[ROM_ERRLINE] + 1u == l, "[%s] line: text.c %u, ROM %ld", text, l, (long)b.mem[ROM_ERRLINE] + 1);
}
}
int main(void)
{
unsigned i;
for (i = 0; i < sizeof rom_asm_cases / sizeof rom_asm_cases[0]; i++) same(rom_asm_cases[i]);
/* test_text.c's four real definitions, and more of the notation together */
same("macro SWAP over push push drop pop pop endmacro\n"
": SWAP' ( a b -- b a ) SWAP ;\n"
": UM/MOD ( ulo uhi ud -- urem uquot )\n"
" a! N-1 FOR\n"
" -if L0\n"
" 2* over -if L1 drop 1 + jump L2\n"
" L1: drop L2: push 2* pop\n"
" jump SUB\n"
" L0:\n"
" 2* over -if L3 drop 1 + jump L4\n"
" L3: drop L4: push 2* pop\n"
" dup a xor -if L5\n"
" drop -if NOSUB jump SUB\n"
" L5: drop dup inv a + inv -if L6\n"
" drop jump NOSUB\n"
" L6: push drop pop jump SETBIT\n"
" SUB: inv a + inv\n"
" SETBIT: push 1 + pop\n"
" NOSUB:\n"
" NEXT\n"
" SWAP ;\n"
": C@ ( baddr -- c )\n"
" dup 2/ 2/ a! 3 and\n"
" if K0 -1 + if K1 -1 + if K2\n"
" drop @ 23 FOR 2/ UNEXT 255 and ;\n"
" K2: drop @ 15 FOR 2/ UNEXT 255 and ;\n"
" K1: drop @ 7 FOR 2/ UNEXT 255 and ;\n"
" K0: drop @ 255 and ;\n"
": C! ( c baddr -- )\n"
" dup 2/ 2/ a! 3 and push 255 and pop\n"
" if K0 -1 + if K1 -1 + if K2\n"
" drop 23 FOR 2* UNEXT @ 4278190080 inv and + ! ;\n"
" K2: drop 15 FOR 2* UNEXT @ -16711681 and + ! ;\n"
" K1: drop 7 FOR 2* UNEXT @ -65281 and + ! ;\n"
" K0: drop @ -256 and + ! ;\n"
": ROUNDTRIP ( c baddr -- c' ) dup push C! pop jump C@\n");
same(": A B C ; : B jump D ; : C if E D E: ; : D ; macro TWO dup dup endmacro macro FOUR TWO TWO endmacro\n"
": F FOUR &A VAR+3 \\ a comment\n ( and another ) ;\n#, 5 \", ( #, &F \", abcdefgh");
/* the ROM's own directives */
CHECK(rom_run("set S 5 set S 9 : T S ;\nstore 7000 S store 7001 here\n#, here\n: Z ;\nstart Z\n\x04") == 1,
"set, here and store assemble: code %ld", (long)b.mem[ROM_FAILED]);
CHECK(b.mem[7000] == 9 && b.mem[7001] == 18 && b.mem[18] == 18, "set takes its last value, here is the next word: %ld %ld %ld",
(long)b.mem[7000], (long)b.mem[7001], (long)b.mem[18]);
CHECK(rom_run(": T ;\n\x04") == 0 && b.mem[ROM_FAILED] == ROM_ERR_NO_START, "no start: refused");
CHECK(rom_run(": T ;\nconstant K 1\nstart K\n\x04") == 0 && b.mem[ROM_FAILED] == ROM_ERR_START, "start of a constant: refused");
CHECK(rom_run(": T ;\nstart\n\x04") == 0 && b.mem[ROM_FAILED] == ROM_ERR_MISSING, "start alone: refused");
CHECK(rom_run(": T here ;\n: Z ;\nstart Z\n\x04") == 0 && b.mem[ROM_FAILED] == ROM_ERR_TARGET, "here alone is not code");
CHECK(rom_run("store 9000\n: Z ;\nstart Z\n\x04") == 0, "store needs two values");
/* a blob split over two feeds, and a forward call resolved in the second (Review Focus 1) */
CHECK(rom_run(": A B ;\n: B 7 ;\n: Z ;\nstart Z\n\x04") == 1 && (b.mem[ROM_ORIGIN] & 0xFFFFFFFF) != 0, "a forward call across words");
/* the tables are cleared at start (Review Focus 4) */
rom_run(": A B ;\n: B 7 ;\nmacro M dup endmacro\n: Z M ;\nstart Z\n\x04");
for (i = 0; i < (unsigned)(DICT_END_W - DICT_W); i++) if (b.mem[DICT_W + (v4_cell)i] != 0) break;
CHECK(i == (unsigned)(DICT_END_W - DICT_W), "the symbol table is cleared: cell %u is not", i);
for (i = 0; i < 1024u; i++) if (b.mem[BUF0_W + (v4_cell)i] != 0) break;
CHECK(i == 1024u, "the block window is cleared: cell %u is not", i);
for (i = 0; i < 260u; i++) if (b.mem[TIB_W + (v4_cell)i] != 0) break;
CHECK(i == 260u, "the text input buffer is cleared: cell %u is not", i);
printf("test_host_rom_asm: %d checks, %d failures\n", checks, failures);
return failures != 0;
}
+51
View File
@@ -61,6 +61,57 @@ int main(void)
constant("ADDR-TOP", (long)ROM_ADDR_TOP);
constant("ERR-FIT", (long)ROM_ERR_FIT);
constant("ERR-OPCODE", (long)ROM_ERR_OPCODE);
constant("(NREF)", (long)ROM_NREF);
constant("(NLAB)", (long)ROM_NLAB);
constant("(WNP)", (long)ROM_WNP);
constant("(NFOR)", (long)ROM_NFOR);
constant("(FORS)", (long)ROM_FORS);
constant("(RDEPTH)", (long)ROM_RDEPTH);
constant("(RPTRS)", (long)ROM_RPTRS);
constant("(T1)", (long)ROM_T1);
constant("(T2)", (long)ROM_T2);
constant("(T3)", (long)ROM_T3);
constant("(T4)", (long)ROM_T4);
constant("(CFROM)", (long)ROM_CFROM);
constant("(CTO)", (long)ROM_CTO);
constant("(CN)", (long)ROM_CN);
constant("(RAW)", (long)ROM_RAW);
constant("(T5)", (long)ROM_T5);
constant("(T6)", (long)ROM_T6);
constant("(MLEN)", (long)ROM_MLEN);
constant("(REFS)", (long)ROM_REFS);
constant("(LABELS)", (long)ROM_LABELS);
constant("(WNAMES)", (long)ROM_WNAMES);
constant("(TSAVE)", (long)ROM_TSAVE);
constant("(MTEMP)", (long)ROM_MTEMP);
constant("(MBODY)", (long)ROM_MBODY);
constant("ORIGIN", (long)ROM_ORIGIN);
constant("REFS-MAX", (long)ROM_REFS_MAX);
constant("WN-SIZE", (long)ROM_WN_SIZE);
constant("MBODY-SIZE", (long)ROM_MBODY_SIZE);
constant("DICT-W", (long)DICT_W);
constant("DICT-END", (long)DICT_END_W);
constant("BUF0", (long)BUF0_W);
constant("TIB-W", (long)TIB_W);
constant("ERR-IN-MACRO", (long)ROM_ERR_IN_MACRO);
constant("ERR-MACRO", (long)ROM_ERR_MACRO);
constant("ERR-LABEL-DUP", (long)ROM_ERR_LABEL_DUP);
constant("ERR-LABELS", (long)ROM_ERR_LABELS);
constant("ERR-FOR", (long)ROM_ERR_FOR);
constant("ERR-UNEXT", (long)ROM_ERR_UNEXT);
constant("ERR-TARGET", (long)ROM_ERR_TARGET);
constant("ERR-UNDEFINED", (long)ROM_ERR_UNDEFINED);
constant("ERR-BIG", (long)ROM_ERR_BIG);
constant("ERR-AMP", (long)ROM_ERR_AMP);
constant("ERR-FETCH-P", (long)ROM_ERR_FETCH_P);
constant("ERR-MISSING", (long)ROM_ERR_MISSING);
constant("ERR-DEEP", (long)ROM_ERR_DEEP);
constant("ERR-REFS", (long)ROM_ERR_REFS);
constant("ERR-VALUE", (long)ROM_ERR_VALUE);
constant("ERR-NO-START", (long)ROM_ERR_NO_START);
constant("ERR-START", (long)ROM_ERR_START);
constant("DSTACK-REG", (long)DSTACK_REG);
constant("RSTACK-REG", (long)RSTACK_REG);
/* the cell width's constants (NUMBER) needs, written as signed cells */
constant("MSB", (long)(v4_cell)V4_MSB);
constant("DEC-LIMIT", (long)(v4_cell)(~(v4_ucell)0 / 10u));