Jump to content
  • entries
    45
  • comments
    10
  • views
    10,549

Dealer Demo, part 8: Who compiles the compiler?


Atari_Ace

603 views

We pick up decompiling again at $148C, where we find 1+ (ONEP). It is followed by 2+ (TWOP), HERE, ALLOT, , (COMMA), C, (CCOMM), - (SUB), = (EQUAL), > (GREAT), ROT, SPACE and -DUP (DDUP). All of these are identical to the fig-Forth listing, which implements these as colon-definitions, which is expected. Although SUB, EQUAL and ROT are sometimes rewritten as primitives to speed up Forth (cf. val-Forth), optimizing these was not done in this Forth.

TRAVERSE is the next word in the listing and it is implemented completed differently. It's used to traverse a name field forwards or backwards to find start or end of the name. Here's the version from fig-Forth:

0A84: D6 07     TRAV    .WORD DOCOL
0A86: 22 07             .WORD SWAP
0A88: 08 07     L1312   .WORD OVER
0A8A: 99 06             .WORD PLUS
0A8C: 67 02             .WORD CLIT
0A8E: 7F                .BYTE $7F
0A8F: 08 07             .WORD OVER
0A91: 8E 07             .WORD CAT
0A93: 1F 0A             .WORD LESS
0A95: 56 03             .WORD ZBRAN
0A97: F1 FF     L1320   .WORD $FFF1
0A99: 22 07             .WORD SWAP
0A9B: 19 07             .WORD DROP
0A9D: 0C 06             .WORD SEMIS

and here's the smaller and faster version from Dealer Demo.

154A: 4C 15     TRAV    .WORD *+2
154C: B4 00             LDY 0,X
154E: 98        TRAV1   TYA
154F: 18                CLC
1550: 75 02             ADC 2,X
1552: 95 02             STA 2,X
1554: B5 01             LDA 1,X
1556: 75 03             ADC 3,X
1558: 95 03             STA 3,X
155A: A1 02             LDA (2,X)
155C: 10 F0             BPL TRAV1
155E: 4C 4D 0E          JMP POP

The Dealer Demo version is a nice improvement, perhaps motivated to speed up Forth compilation.

From here on in our decompilation we'll largely omit details where the implementation follows the fig-Forth implementation exactly

The next words, LATEST, LFA, CFA, NFA, PFA, !CSP, ?ERR, ?COMP, ?EXEC, ?PAIR, ?CSP, ?LOAD, COMP, LBRAC, RBRAC and SMUDGE are colon definitions to support the compiler. HEX and DECIMAL follow, and then more compiler/runtime support with (;CODE), ;CODE and then <BUILD, DOES> followed by some assembly code DODOE to support <BUILD … DOES> and then the word COUNT.

If we run -refs now, we'll see that (;CODE), labeled PSCOD, is the routine that finishes all the various dictionary adding definitions we've already seen (e.g. CONSTANT, VARIABLE, colon). I would have expected this routine to be a primitive, but it in fact is a colon definition:

16D4: 4C 12     PSCOD   .WORD DOCOL
16D6: 85 10             .WORD RFROM
16D8: 6A 15             .WORD LATES
16DA: AC 15             .WORD PFA
16DC: 89 15             .WORD CFA
16DE: 13 12             .WORD STORE
16E0: 45 10             .WORD SEMIS

This just sets the code field of the latest word to the code that follows the PSCOD address. It's used in all definitions because all those definitions finish adding to the dictionary in the same way, so it might as well be shared code.

DODOE deserves a little study:

171E: A5 F9     DODOE   LDA IP+1
1720: 48                PHA
1721: A5 F8             LDA IP
1723: 48                PHA
1724: A0 02             LDY #2
1726: B1 FB             LDA (W),Y
1728: 85 F8             STA IP
172A: C8                INY
172B: B1 FB             LDA (W),Y
172D: 85 F9             STA IP+1
172F: 18                CLC
1730: A5 FB             LDA W
1732: 69 04             ADC #4
1734: 48                PHA
1735: A5 FC             LDA W+1
1737: 69 00             ADC #0
1739: 4C 3B 0D          JMP PUSH

This routine configures Forth to resume execution at the word after DODOE, but first puts the current IP on the return stack, and the address of the subsequent word on the data stack. This is similar to how DOCOL works, but in practice it means we restart execution inside another DOCOL definition (the address after a DODOE is not the start of a definition) with the top of the stack set to a particular value. In modern terms, we'd probably call this a continuation, since it allows us to continue another routine with a modified environment. In the Forth kernel, it is used only to implement particular vocabularies (e.g. FORTH, ASSEMBLER), which can configure the set of words in the dictionary available to the compiler, but the assembler itself will use this extensively to create a table driven assembler from a handful of words.

The next word that is different is TYPE. In place of a real implementation, a stub implementation is here (.WORD DOCOL, XTYPE, SEMIS), deferring the implementation to later in the listing. This is partially understandable, TYPE depends on being able to use the Atari CIO routines which have yet to be defined. But if Dealer Demo was bootstrapped using an assembler, this isn't really necessary, the assembler can handle the backward references just fine. Perhaps the implementation started by following the original fig-Forth, where XTYPE would have been a primitive defined later in the listing, but at some point it was converted to a colon definition and the original forward definition adjusted. As a result, we have two definitions of TYPE which are equivalent, which wastes some memory but otherwise works fine.

I think that's enough decompiling for this post. Let's fix up the values -refs show can now be replaced with labels, and pick up again later.

dealerdemo.lst

0 Comments


Recommended Comments

There are no comments to display.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...