From 7dca141aae0d40f8e49b080bc92afa7b2df1011a Mon Sep 17 00:00:00 2001 From: Anachronaut Date: Sat, 5 Sep 2026 11:03:11 -0400 Subject: [PATCH] The vector's number goes beside its kind, not at the end of the line Kind and Number together are what names a thing: Vector 16 and Device 32 are identifiers in a way that Vector on its own is not. Everything after them - where it lives, what it is called, where it was written - says something about it rather than naming it, so with the number at the far end a line opened with a bare kind and closed with the fact that would have told you what you were reading. Fields are now Kind, Number, Address, Name, File, Line. A label still carries a dash where its number would be, which reads as "this kind is not numbered" rather than as a field that went missing. Manual and the docs check follow. Verified with break.sh by swapping the number and the address back. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01E2JrLzFvuFX9fgi1LDRjrW --- Source/Assembler/secondPass.c | 20 ++++++++++++++------ SplitBit Assembler Manual.md | 16 +++++++++------- Tests/docs.sh | 8 ++++---- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/Source/Assembler/secondPass.c b/Source/Assembler/secondPass.c index 2b82b35..119a664 100644 --- a/Source/Assembler/secondPass.c +++ b/Source/Assembler/secondPass.c @@ -66,6 +66,14 @@ int vectorArrayCount = 0; // and what a memory dump shows. Neither can be worked out from the other without knowing // which table it is in, so the file says both. // +// THE NUMBER SITS SECOND, beside the kind rather than out at the end, because the two of +// them together are what names the thing: "Vector 26" and "Device 32" are single identifiers +// in the way "Vector" alone is not. Everything after them - where it lives, what it is +// called, where it was written - is something about the thing rather than part of naming it, +// so the line reads as an identity followed by its properties. A label has no number and +// carries a dash in that column, which is the shape of the answer "this kind is not numbered" +// rather than an empty space that could be a missing field. +// // Sorted by kind and then address rather than by name, because the question asked of it is // always "what is at this address"; sorting by address alone would interleave separate // address spaces and make the first column flicker between them. The table is small enough @@ -146,17 +154,17 @@ void writeSymbolFile(const char *path) { for (int i = 0; i < n; i++) { char number[12]; // Wide enough for any int, which is more than a vector needs. if (rows[i].number < 0) { - // A LABEL HAS NO NUMBER, and the field says so rather than being left empty: - // a run of tabs with nothing between them is the one thing a reader of this - // file, human or otherwise, can miscount. + // A label has no number, and the field says so rather than being left empty: a + // run of tabs with nothing between them is the one thing a reader of this file, + // human or otherwise, can miscount. snprintf(number, sizeof(number), "-"); } else { snprintf(number, sizeof(number), "%d", rows[i].number); } - fprintf(file, "%s\t%04X\t%s\t%s\t%d\t%s\n", - kindName[rows[i].kind], rows[i].address, rows[i].name, + fprintf(file, "%s\t%s\t%04X\t%s\t%s\t%d\n", + kindName[rows[i].kind], number, rows[i].address, rows[i].name, rows[i].fileName ? rows[i].fileName : "?", - rows[i].lineNumber, number); + rows[i].lineNumber); } free(rows); fclose(file); diff --git a/SplitBit Assembler Manual.md b/SplitBit Assembler Manual.md index f23e178..3bc2f1d 100644 --- a/SplitBit Assembler Manual.md +++ b/SplitBit Assembler Manual.md @@ -430,21 +430,23 @@ Every option above that takes a \ names a file the assembler WRITES, and | Field | Meaning | | -- | -- | | Kind | Program, Data, Vector or Device. | +| Number | Which vector it is: the vector number, or the port for a device. A label has no number and the field is a dash. | | Address | Four hexadecimal digits: where the thing lives. For a label, the address it was given. For a vector, the slot in the vector table that holds its handler's address. | | Name | The label, or the vector's name. A device has no name of its own, so it is listed under its handler. | | File | The source file it was written in, named the way the assembler was given it. | | Line | Which line of that file, counting from one. | -| Number | Which vector it is: the vector number, or the port for a device. A label has no number and the field is a dash. | ``` -Program 5000 start game.asm 31 - -Program 670D int16add Libraries/math.asm 5 - -Vector FC20 osPrintString services.asm 24 16 -Vector FC80 gameFrame game.asm 402 64 -Device FE40 diskDone system.asm 812 32 -Data 3000 Score game.asm 118 - +Program - 5000 start game.asm 31 +Program - 670D int16add Libraries/math.asm 5 +Vector 16 FC20 osPrintString services.asm 24 +Vector 64 FC80 gameFrame game.asm 402 +Device 32 FE40 diskDone system.asm 812 +Data - 3000 Score game.asm 118 ``` +The kind and the number sit together at the front because the two of them are what names the thing: Vector 16 and Device 32 are identifiers in a way that Vector on its own is not. Everything after them says something about it rather than naming it, so a line reads as a thing followed by what is known about it. + Tabs rather than aligned columns, so that the file is a table every ordinary tool already reads without being taught anything, and no heading line, so that nothing has to know to skip one. The file field is what makes it worth having on a big program: a name defined once and called in forty places is hard to find by searching, and this says where it was written. The kind comes first because Program and Data are separate memories on this machine, so an address on its own does not say where something is. In a loadable program the two segments are usually based far enough apart that the difference is easy to overlook. In a boot image both start at 0x0000, and every address in the table appears twice. diff --git a/Tests/docs.sh b/Tests/docs.sh index 99d479e..0d35842 100755 --- a/Tests/docs.sh +++ b/Tests/docs.sh @@ -838,8 +838,8 @@ if "## Running the Assembler:" not in am: else: section = am.split("## Running the Assembler:")[1].split("\n## ")[0] said = [row.split(" |")[0] for row in re.findall(r'^\| (\w+ \|.*)$', section, re.M) - if row.split(" |")[0] in ("Kind", "Address", "Name", "File", "Line", "Number")] - if said != ["Kind", "Address", "Name", "File", "Line", "Number"]: + if row.split(" |")[0] in ("Kind", "Number", "Address", "Name", "File", "Line")] + if said != ["Kind", "Number", "Address", "Name", "File", "Line"]: problems.append("the Assembler Manual does not describe the symbol file's six" " fields in order; it lists %s" % (said or "none")) else: @@ -875,7 +875,7 @@ else: " Assembler Manual describes six" % (number, len(fields))) break - kind, address, name, source, where, index = fields + kind, index, address, name, source, where = fields kinds.add(kind) if kind not in ("Program", "Data", "Vector", "Device"): problems.append("a symbol file calls something a %r, and the" @@ -934,7 +934,7 @@ else: # drift lands on a line that has nothing to do with the name. sources = {} for row in open(dump).read().splitlines(): - kind, address, name, source, where, index = row.split("\t") + kind, index, address, name, source, where = row.split("\t") if source not in sources: try: sources[source] = open(source).read().splitlines()