FRONTEND.md 13 KB

Frontend export map: PASS1 + STATEMEN + EXPRESS (+ SYMTAB bodies)

No upstream .MOD exists for these — only MCode_disassembly/{pass1,statement,express,symtab,compile}.txt. This file pins every exported head (MCode offset, old name, proposed name, role, evidence) so body decompilation can proceed procedure by procedure. Names with ~ are internal (no head entry, called via single-byte f1..ff) and listed where identified.

Notation: word5 = Scanner.curSymbol, word9 = ident class, word11 = token text, word12 = ident type.

COMPILE link (compile.txt, 74 lines)

COMPILE.DIR/ = COMPILE.MCD (link stub) + PASS1/STATEMEN/EXPRESS.MCD, loaded by Scanner.Compile (Loader.Call("COMPILE")), then GENZ80 if Compiler.nativeCodeRequested. compile.txt itself is a char-compare loop over two strings (bound 67 = keyword-table size) plus a byte-copy loop with one call .proc24 (~StrCmp) — the link stub's keyword-hash helper, not a parser.

PASS1 — declarations/scopes/types (pass1.txt, 2975 lines)

Deps: COMPILER SCANNER FILES EXPRESS STATEMEN CODEGEN SYMTAB ERRORS TEXTS COMLINE LOADER.

offset old proposed evidence
0001 proc4 ~PushTempMark brackets EXPRESS.proc1(err 82); saves SYMTAB.word4 vs global word3
0016 proc5 ~PopTempMark mirror of proc4 (±1/±2 restore)
0032/0051 proc6/proc7 ~AllocSymEntry/~LinkSymEntry tiny allocators; proc7 feeds proc1
007c proc1 ~InsertSetConst SYMTAB.proc5 bitset build, SCANNER.proc6/7 alloc+copy, MOVE blocks
00f4/0113 proc2/proc3 ~CondInsert/~InsertEntry proc2 = if param4 then proc3 else 0
017b proc8 ~OpenScopeEmit CODEGEN.proc18/21/3, SCANNER.proc24; calls proc4
01a1 proc12 ~TypeSizeRec self call_with_frame proc12 (recursive size walk)
0201 proc13 ~GetIdent SCANNER.proc3 + proc13(3) + proc1, returns Scanner.word12
0211 proc16 ~ParseImportItem Expect(42) (FROM), SCANNER.proc14(5), proc19, word9/word13 checks
023e proc17 ~ParseConstDecl EXPRESS.proc7/9/13 const-eval + SCANNER.proc8 sync
027b proc18 ~ParseVarDecl nested-called from proc19 loop; SCANNER.proc4 tail
02e6 proc19 ~ParseType largest (~290 ins): enum/subrange (EXPRESS.proc9/13/7/14), pointer/PROC/record/array, SCANNER.proc17/18/19/20 entry building
0411 proc15 ~ParseFormalParams SCANNER.proc19, nested proc18, proc17/19 helpers
04f4/050b proc20/proc21 ~ParseValParam/~ParseVarParam —
0548 proc22 ~ParseFieldList record fields; proc8, SCANNER.proc12/20 sync
060a proc23 ~EvalConstExpr ERRORS.proc2, EXPRESS.proc7/13, SCANNER.proc8/9
0687 proc24 ~CheckConformant short, EXPRESS.proc1 + SCANNER.proc4/8
06a7 proc14 ~ParseRecordType incl. variant part (~160 ins, SCANNER.proc15/19, EXPRESS.proc7/13)
0783 proc25 ~CloseScopeFixup single SCANNER.proc4 + adjust
07a8 PROCDE ParseProcedureDecl header, formals, local DCLS, body, END ident match
0878 MODULD ParseModuleHead SCANNER.proc17 scope open, name capture
08b2 proc28 ~ParseExportList SCANNER.proc8 loop
08f1 DCL ParseOneDecl dispatch single CONST/TYPE/VAR/PROCEDURE decl
0943 DCLS ParseDeclarations sym 13/23 -> STATEMEN.* body hook, loop proc11 … proc29, guarded recovery (ERRORS.proc11, CODEGEN.proc22, save/restore SCANNER.word2/25, CODEGEN.word2, SYMTAB.word5)
09b9 IMEXDC ParseImportFrom sym 15/16 -> SYMTAB.proc2 + proc30; sym 23/13 -> STATEMEN.*; sym 17 -> SYMTAB.proc3
0a0c MODBLO ParseModuleBlock SCANNER.proc17 open, nested proc30, SYMTAB.proc4 link
0a56 proc9 ~WriteSymFile .SYM output; file/emit calls tail
0ae5 MAINDE ParseMainModule ~280 ins: DEFINITION vs IMPLEMENTATION vs PROGRAM, SYMTAB.proc2/3, proc30 frames
0c93 proc33 ~WriteMcdHeader tiny, CODEGEN linkait calls
0d17/0d2e proc35/proc34 ~EmitConstVal/~EmitTypeDesc paired; proc34 calls proc35 frame
0db2 proc32 ~SkipToDeclStart small sync helper before proc33
0e93 proc36 ~CheckForwardResolved final sweep before close
1027 PASS1 Pass1Main sets up globals, calls DCLS/MAINDE, triggers .SYM/.MCD output
105b 4NAZBA module init MCode init body

STATEMEN — statements (statement.txt, 1793 lines)

Deps: COMPILER LOADER FILES TEXTS SYMTAB EXPRESS CODEGEN SCANNER ERRORS.

offset old proposed evidence
0001 proc2 ~CalcMemOffset bit/arith descriptor math, no scanner calls
003b proc3 ~SyncToStatStart —
0078 proc5 ParseFor frame −23, largest: EXPRESS.proc12/9/14, Accept(1), CODEGEN.proc10/12/14/16/17, BY loop, nesting via global4
018b proc6 ~ParseIf ~350 ins, ELSIF/ELSE chains
0341..0509 proc7..proc14 ~ParseWhile/~ParseRepeat/~ParseLoop/~ParseWith/~ParseAssign/~ParseCall/~ParseReturn/~ParseExit order follows keyword codes 121–130 (confirm vs keyword table)
0566 STMT ParseStatement switch (Scanner.word5): 121→proc10 … 130→proc5; ident-led: word9=4 call (EXPRESS.proc15+Expect(43)=(), =5 assign (EXPRESS.proc17/18, Expect(27)=:=), =0 error 128
0634 STATSE GuardedStatSeq saves SCANNER.word2/25+CODEGEN.word2+SYMTAB.word5; proc15+Expect(9); loop proc4; ERRORS.proc11+CODEGEN.proc22 recovery
0683 proc16 ParseCase CODEGEN.proc16 fixup list, , loops, ELSE@10 tail
0738/0808/0863 proc17/18/19 block tails ~90–120 ins each: END-match, fixup close, result check
08a4 BODY ParseBeginBlock BEGIN StatSeq END [ident]
0a25 proc0 module init —
— (internal proc1/proc4/proc15) ~NextSymWrap/~ParseStatSeqLoop/~EmitJumpFixup no head entry; proc4 called in every stat-seq loop

EXPRESS — expressions (express.txt, 3898 lines)

Deps: COMPILER SCANNER ERRORS CODEGEN SYMTAB PASS1 DOUBLES.

offset old proposed evidence
004a/00c0 proc4/proc5 ~PushExprDesc/~PopExprDesc —
0095/017d/01c5/0212 proc32/33/34/35 ~IsOrdinal/~IsSet/~BaseTypeOf/~FoldConstOp proc35 called from EXPRES after each operator
0275/02ac/02be proc7/8/9 ~ConstToCard/~ConstToInt/~MatchOpClass proc9 called with immediates 16/501/389/405…
02d0 proc21 ~ParseDesignatorBase frame −17, SCANNER.proc8 sync
0358 proc20 ~ParseSelector (/[/./^ chains, CODEGEN.proc17
032f proc36 ~CheckAssignable —
0470 proc16 ~EvalConstExpr —
0510 proc15 ~ParseDesignatorTail also called from STMT assign branch
06a2/0657/0704/06bb/06da proc37/38/40/41/42 ~ParseTerm/~ParseFactor/~ParseSetCons/~ParseFuncCall/~ParseTypeCast —
087f..09a2 proc43..46 ~ExpandStdProc INC/DEC/INCL/EXCL/…
09e0 proc39 ~ParseSetOrCastTail —
0c61/0c74/0d1a proc47/51/50 ~FoldRelation/~CheckRelationTypes/~EmitCompare —
0e45 proc49 ~EmitRangeCheck frame −17
1025 proc48 ~ParseSimpleExpression nested-called by EXPRES
0bd2/0c0c proc18/19 ~LoadOperand/~StoreOperand CODEGEN.proc17/18
1221 EXPRES ParseExpression proc48, then relops 51–57 (=/#/</<=/>/>=/IN); const-fold via CODEGEN.proc4, general CODEGEN.proc10(4); shared exit @13df
13f3/1400 proc13/14 ~GetConstVal/~GetTypeDesc —
144c/1471 ASSIGN ParseAssignment two entries: statement-assign + function-result assign
1516 proc0 module init —
fda9/ff1a/ff6b… AAAAAA ×13 Z80 helpers address-ordered stubs (removed names); map to Allocate/FindIdent-style helpers during body work

SYMTAB bodies (symtab.txt, 2365 lines; SYMTAB.DEF done)

SYMTAB.MOD does not exist upstream. Head map (offset → name from docs/compiler/40-symtab-errors.md): 0001 proc8 SymbolAssert, 000c/0040 proc9/10 FindModule/EnterModule, 0083/00a6 proc11/12 LookupChain/MatchSym, 01d7/0259 proc14/13 AllocSym/EnterChained, 00d4/0268/0281/0106/0305/03c9 proc17/21/22/18/20/19 NewString/GetName/GetAttr/PutAttr/EnterIdent/Unlink, 03de proc23 InitHeaps, 0432/0448 proc25/24 InsertBuiltin/EnterStandards, 048a/04a0 proc27/26 LibRead/LoadSymFile, 0553/0579/05be/05dd proc29/30/31/28 FindExport/ListExports/ImportOne/ImportAll, 07ad proc32 SkipQualident, 07d8/089a/0914 proc2/3/4 DoDefinition/DoProgram/InitCompile, 0997/09c8 proc34/33 NoteImported/DoImportList, 0a0c/0aa7 proc35/36 CompileBody/CheckForwards, 0b1c IMDCLS TryCompile, 0b6e proc1 CompileDispatch, 0bdb/0b99/0c5e proc6/38/7 SaveSymFile/Checksum7w/Unlock, 0c62 proc0 init.

Shared cross-module procedures (decompile once)

  • Scanner API: GetSym/AcceptSymbol/ExpectSymbol/TestSymbolInSet/ExpectIdentKind/OpenScope/NewSizedNode/NewNode/DeclareIdentifier/InsertSymbol/MakeIdentifierNode.
  • EXPRESS.proc1 = central error (codes 47/52/61/82/73/74); proc9 = op/set test; proc7/13/14 = const/type fetch; proc17/18/19 = Load/Store helpers; proc12 = boolean-cond helper.
  • CodeGen emitters: proc1/3/4/6/10/12/13/14/16/17/18/19/21/22 (see 50-codegen.md).

Decompile order (unchanged)

EXPRES/proc48/proc35/proc9 → STMT/STATSE/proc4 → CASE/FOR → Pass1 proc13 (ident) → proc19/14 (types) → DCL/DCLS/IMEXDC → PROCDE/MODBLO/MAINDE → proc9 (SYM writer). SYMTAB bodies interleave as needed (EnterIdent/LookupChain/ImportAll first).

EXPRESS internals found during draft v1 (not in the head map above)

Group 2 reverse-engineered the head convention (leave NN operand = param count) and identified: proc1 CentralError, proc2/3 PushOperand/PopOperand, proc6 EmitOp, proc10 NormalizeOperand, proc11 LoadIndirect, proc12 BoolCondHelper (= group3's ParseCondValue), proc22 CheckAndStore, proc25 GetRangeBase, proc26 IsPointer, proc27 TypeKindOf (≠ proc34 BaseTypeOf!), proc28 EmitAddress, proc29 ParseActualList, proc31 EmitIndexed/EmitOperand31. Declared FORWARD in EXPRESS.MOD = remaining body work. AAAAAA heads = Z80 stubs.

Corrections 2026-10-03 (STATEMEN body evidence + frame mechanics proof)

  • proc5 = CASE, proc6 = FOR (were swapped in the tables above).
  • STMT dispatch: 121 Loop, 122 Exit, 123 Result, 124 If, 125 For, 126 Repeat, 127 While, 128 With, 129 Return, 130 Case (125 = default arm).
  • proc5 (STMT-driven, STMT case 130) vs proc16 (BODY-driven via Accept(14)): kept distinct as ParseCaseStmt vs ParseCaseTail — why BODY re-enters case parsing on symbol 14 is unexplained.
  • Frame mechanics (MCode_specification/Stack.mod: fp^[3] = LAST pushed word = disassembler's "param1"): multi-param body readings assuming param1=formal1 are backwards; call sites from pushes stay order-correct. Proven instances: Express.MatchOpClass(allowed, errCode) [was swapped], Express.proc1 CentralError(ok, code) [was 1-param]. FULL per-proc signature audit across SYMTAB/EXPRESS drafts still PENDING (next workstream).
  • STATEMEN globals: word2 needEpilogue, word3 withPending, word4 nestDepth, word5 exitDepth, word6 curBlockNode, word7 caseActive, word8 withDesc, word9 exitEmitted.

Corrections 2026-10-03 (PASS1 body evidence)

  • D1/D2 (re-read verdict 2026-10-04): arity is frame-correct as mapped (0-param @0411, 3-param @02e6 — only @02e6 can host the 3-push call sites); dispute is NAMES-only (proc15=ParseType vs ParseFormalParams). Map kept.
  • D3/D4: proc17 builds ARRAY descriptors, proc18 parses [lo..hi] SUBRANGEs (kept as ParseConstDecl/ParseVarDecl pending const/var-decl cross-check).
  • proc9 = ParseProcBody (parses procedure bodies, NO file calls) — NOT the .SYM writer; the writer is probably proc32 @0db2 (NOT decompiled yet).
  • Missing/stubbed: proc10/11/26/27/29/30 (no bytes anywhere), proc36 body (patched over by link-stub hash helper), PASS1 @1027 / 4NAZBA @105b.
  • Discovery: SCANNER.proc24 = 2-param length-prefix function (CappedStrLen); CodeGen EmitWord=proc3 / EmitString=proc21 body-proven.
  • PASS1 globals: word2 emitBase, word3 emitTop, word4 nestDepth.
  • ConstToCard/ConstToInt call shapes (type-first) vs EXPRESS.DEF order (errPos, c) disagree — signature-audit item (frame rule applied).

Signature audit 2026-10-03 (all four drafts; frame rule applied)

Method per proc: body paramK roles vs frame arity vs call-site push shapes. STMT+PASS1: all KEEP (only change: ParseBeginBlock drops unused VAR rest; CappedStrLen = SCANNER F4FCT2 StrLen with explicit HIGH). D1/D2 swap REFUTED by arity (@0411 is 0-param) — map names stand. SYMTAB applied SWAPs (accumulator-first): NewString/GetName/PutAttr/GetAttr/ AllocSym/EnterChained/EnterIdent/UnlinkScope; rest KEEP; DefineProgramModule UNKNOWN (now (setAddr, tag) + FIXME). EXPRESS applied: PushExprDesc/IsSet/BaseTypeOf/ConstToCard/ConstToInt/ ParseTerm/ParseSetCons/GetTypeDesc/ParseSelector swaps (def headers; bodies and push-order call sites untouched by construction); CheckRelationTypes drops unused op; ParseDesignatorBase (6->4) + ParseFactor (mirror) recorded as FIXME (need frame re-read); FoldRelation LONGREAL-param noted. proc32 = WriteOutputFiles (refutes ~SkipToDeclStart); called from Pass1Main path.