From d5a7d5faf8659a28e96539abc75a621b58c82a35 Mon Sep 17 00:00:00 2001 From: Virgil Dupras Date: Thu, 12 Mar 2020 21:16:20 -0400 Subject: [PATCH] forth: add words "(fbr)", "(fbr?)", "'", "[']" --- apps/forth/dict.asm | 129 +++++++++++++++++++++++++++++++--------------- apps/forth/dictionary.txt | 23 ++++++--- apps/forth/util.asm | 10 ++-- 3 files changed, 110 insertions(+), 52 deletions(-) diff --git a/apps/forth/dict.asm b/apps/forth/dict.asm index ec2c9e7..3f8de77 100644 --- a/apps/forth/dict.asm +++ b/apps/forth/dict.asm @@ -11,7 +11,7 @@ ; "jp exit". ; ; That's for "regular" words (words that are part of the dict chain). There are -; also "special words", for example NUMBER, LIT, BRANCH, that have a slightly +; also "special words", for example NUMBER, LIT, FBR, that have a slightly ; different structure. They're also a pointer to an executable, but as for the ; other fields, the only one they have is the "flags" field. @@ -56,42 +56,6 @@ doesWord: push hl \ pop iy jr compiledWord -; This word is followed by 1b *relative* offset (to the cell's addr) to where to -; branch to. For example, The branching cell of "IF THEN" would contain 3. Add -; this value to RS. -branchWord: - push de - ld l, (ix) - ld h, (ix+1) - ld a, (hl) - call addHL - ld (ix), l - ld (ix+1), h - pop de - jp exit - - .db 0b10 ; Flags -BRANCH: - .dw branchWord - -; Conditional branch, only branch if TOS is zero -cbranchWord: - pop hl - ld a, h - or l - jr z, branchWord - ; skip next byte in RS - ld l, (ix) - ld h, (ix+1) - inc hl - ld (ix), l - ld (ix+1), h - jp exit - - .db 0b10 ; Flags -CBRANCH: - .dw cbranchWord - ; This is not a word, but a number literal. This works a bit differently than ; others: PF means nothing and the actual number is placed next to the ; numberWord reference in the compiled word list. What we need to do to fetch @@ -338,10 +302,53 @@ LITERAL: ld (HERE), hl jp exit + + .db "'" + .fill 6 + .dw LITERAL + .db 0 +APOS: + .dw nativeWord + call readLITBOS + call find + jr nz, .notfound + push de + jp exit +.notfound: + ld hl, .msg + call printstr + jp abort +.msg: + .db "word not found", 0 + + .db "[']" + .fill 4 + .dw APOS + .db 0b01 ; IMMEDIATE +APOSI: + .dw nativeWord + call readword + call find + jr nz, .notfound + ld hl, (HERE) + push de ; --> lvl 1 + ld de, NUMBER + call DEinHL + pop de ; <-- lvl 1 + call DEinHL + ld (HERE), hl + jp exit +.notfound: + ld hl, .msg + call printstr + jp abort +.msg: + .db "word not found", 0 + ; ( -- c ) .db "KEY" .fill 4 - .dw LITERAL + .dw APOSI .db 0 KEY: .dw nativeWord @@ -630,9 +637,49 @@ CMP: push bc jp exit +; This word's atom is followed by 1b *relative* offset (to the cell's addr) to +; where to branch to. For example, The branching cell of "IF THEN" would +; contain 3. Add this value to RS. + .db "(fbr)" + .fill 2 + .dw CMP + .db 0 +FBR: + .dw nativeWord + push de + ld l, (ix) + ld h, (ix+1) + ld a, (hl) + call addHL + ld (ix), l + ld (ix+1), h + pop de + jp exit + +; Conditional branch, only branch if TOS is zero + .db "(fbr?)" + .fill 1 + .dw FBR + .db 0 +FBRC: + .dw nativeWord + pop hl + ld a, h + or l + jr z, FBR+2 + ; skip next byte in RS + ld l, (ix) + ld h, (ix+1) + inc hl + ld (ix), l + ld (ix+1), h + jp exit + + +; : IF ' (fbr?) , HERE @ 0 C, ; IMMEDIATE .db "IF" .fill 5 - .dw CMP + .dw FBRC .db 1 ; IMMEDIATE IF: .dw nativeWord @@ -640,7 +687,7 @@ IF: ; push the address of that cell on the PS. ELSE or THEN will pick ; them up and set the offset. ld hl, (HERE) - ld de, CBRANCH + ld de, FBRC call DEinHL push hl ; address of cell to fill inc hl ; empty 1b cell @@ -666,7 +713,7 @@ ELSE: ; uncondition branching cell, which will then be picked up by THEN. ; First, let's spit our 4 bytes ld hl, (HERE) - ld de, BRANCH + ld de, FBR call DEinHL push hl ; address of cell to fill inc hl ; empty 1b cell diff --git a/apps/forth/dictionary.txt b/apps/forth/dictionary.txt index 7b9468c..55130ca 100644 --- a/apps/forth/dictionary.txt +++ b/apps/forth/dictionary.txt @@ -1,6 +1,7 @@ Stack notation: " -- ". Rightmost is top of stack (TOS). For example, in "a b -- c d", b is TOS before, d is TOS after. "R:" means -that the Return Stack is modified. +that the Return Stack is modified. "I:" prefix means "IMMEDIATE", that is, that +this stack transformation is made at compile time. DOES>: Used inside a colon definition that itself uses CREATE, DOES> transforms that newly created word into a "does cell", that is, a regular cell ( when @@ -25,29 +26,39 @@ Atom: A word of the type compiledWord contains, in its PF, a list of what we call "atoms". Those atoms are most of the time word references, but they can also be references to NUMBER and LIT. +Words between "()" are "support words" that aren't really meant to be used +directly, but as part of another word. + +"*I*" in description indicates an IMMEDIATE word. + *** Defining words *** : x ... -- Define a new word ; R:I -- Exit a colon definition , n -- Write n in HERE and advance it. +' x -- a Push addr of word x to a. +['] x -- *I* Like "'", but spits the addr as a number literal. ALLOT n -- Move HERE by n bytes C, b -- Write byte b in HERE and advance it. CREATE x -- Create cell named x. Doesn't allocate a PF. CONSTANT x n -- Creates cell x that when called pushes its value DOES> -- See description at top of file IMMEDIATE -- Flag the latest defined word as immediate. -LITERAL n -- Inserts number from TOS as a literal +LITERAL n -- *I* Inserts number from TOS as a literal VARIABLE c -- Creates cell x with 2 bytes allocation. *** Flow *** -ELSE -- Branch to THEN +(fbr?) f -- Conditionally branches forward by the number + specified in its atom's cell. +(fbr) -- Branches forward by the number specified in its + atom's cell. +ELSE I:a -- *I* Compiles a (fbr) and set branching cell at a. EXECUTE a -- Execute wordref at addr a -IF n -- Branch to ELSE or THEN if n is zero +IF -- I:a *I* Compiles a (fbr?) and pushes its cell's addr INTERPRET -- Get a line from stdin, compile it in tmp memory, then execute the compiled contents. QUIT R:drop -- Return to interpreter promp immediately RECURSE R:I -- R:I-2 Run the current word again. -THEN -- Does nothing. Serves as a branching merker for IF - and ELSE. +THEN I:a -- *I* Set branching cell at a. *** Stack *** DUP a -- a a diff --git a/apps/forth/util.asm b/apps/forth/util.asm index ea491b1..de04b5e 100644 --- a/apps/forth/util.asm +++ b/apps/forth/util.asm @@ -69,12 +69,12 @@ HLPointsLIT: pop de ret -HLPointsBRANCH: +HLPointsBR: push de - ld de, BRANCH + ld de, FBR call HLPointsDE jr z, .end - ld de, CBRANCH + ld de, FBRC call HLPointsDE .end: pop de @@ -93,7 +93,7 @@ HLPointsEXIT: compSkip: call HLPointsNUMBER jr z, .isNum - call HLPointsBRANCH + call HLPointsBR jr z, .isBranch call HLPointsLIT jr nz, .isWord @@ -171,7 +171,7 @@ readLIT: .notLIT: ; Alright, not a literal, but is it a word? call HLPointsUNWORD - jr nz, .notWord + jr z, .notWord ; Not a number, then it's a word. Copy word to pad and point to it. push hl ; --> lvl 1. we need it to set DE later call intoHL