home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-05-19 | 129.0 KB | 5,074 lines |
- TITLE jax4th.a
- PAGE ,116
-
- ; jax4th.a ... 32-bit ANS Forth for Windows NT
- ; copyright (c) 1993, 1994 by jack j. woehr
- ; p.o. box 51, golden, co 80402-0051
- ; jax@well.sf.ca.us | JAX on GEnie | 72203.1320@compuserve.com
- ; sysop, rcfb (303) 278-0364
-
- COMMENT !
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details. (COPYING.TXT)
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
- !
-
- .386P
-
- .XLIST
- include listing.inc ; this may not be needed
- .LIST
-
- include jax4th.i
-
- .XLIST
- include windows.i
- .LIST
-
- _TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
- _TEXT ENDS
- _DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
- _DATA ENDS
-
- .MODEL FLAT
-
- _DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
-
- .SALL ; suppress listing of Unicode macro expansion
-
- myMsg: unicode <Jax4th for Windows NT>
- DW 0ah, 0dh
- unicode <Copyright (c) 1993, 1994 Jack J. Woehr>
- DW 0ah, 0dh
- unicode <Covered under the GNU Public License.>
- DW 0ah, 0dh
- myMsgLen = ($-myMsg)/tchar
- orderMsg0: unicode <Search Order: >
- orderMsg0Len = ($-orderMsg0)/tchar
- orderMsg1: unicode <Current Compilation Wordlist: >
- orderMsg1Len = ($-orderMsg1)/tchar
- throwMsg: unicode <THROW #>
- throwMsgLen = ($-throwMsg)/tchar
- byeMsg: unicode <Goodbye from Jax4th.>
- DW 0ah, 0dh
- byeMsgLen = ($-byeMsg)/tchar
- gnuMsg: unicode < Jax4th $Revision: 1.25 $ (C) 1993, 1994 Jack J. Woehr>
- DW 0ah, 0dh
- unicode < Jax4th comes with ABSOLUTELY NO WARRANTY.>
- DW 0ah, 0dh
- unicode < This is free software, and you are welcome to redistribute it >
- DW 0ah, 0dh
- unicode < under certain conditions. See file COPYING.TXT for more info.>
- DW 0ah, 0dh
- unicode < Type ABOUT to see this message again.>
- DW 0ah, 0dh
- gnuMsgLen = ($-gnuMsg)/tchar
-
- ;--( Forth Messages )
-
- okPrompt dw 3
- unicode < ok>
- listMsg1 dw 7
- unicode <Block: >
- listMsg2 dw 9
- unicode <File ID: >
- stackUnderMsg dw 12
- unicode <Stack under.>
- undefinedMsg dw 10
- unicode <Undefined.>
- compOnlyMsg dw 17
- unicode <Compilation only.>
- toBodyMsg dw 22
- unicode <Not a child of CREATE.>
- blockWriteMsg dw 18
- unicode <BLOCK write error.>
- blockReadMsg dw 17
- unicode <BLOCK read error.>
- blockNumMsg dw 21
- unicode <Invalid BLOCK number.>
- fileIOMsg dw 20
- unicode <File I/O exception: >
- cStackMsg dw 20
- unicode <Control stack error.>
- conStructMsg dw 26
- unicode <Control structure mismatch.>
- zeroStringMsg dw 17
- unicode <Zero-length name.>
- srchOverMsg dw 22
- unicode <Search order overflow.>
- srchUnderMsg dw 23
- unicode <Search order underflow.>
- compNestMsg dw 17
- unicode <Compiler nesting.>
-
- ;--( Various Messages )
-
- dumpHdr dw 56
- unicode <Address 0100 0302 0504 0706 0908 0B0A 0D0C 0F0E Unicode>
-
- unnamedHdr dw 3, 0fffeH, 0fffeH, 0fffeH ; invalid name character for headerless
-
- widMsg dw 5
- unicode <named>
-
- wlHdr dw 11
- unicode <Wordlists: >
- .XALL ; back to normal listing of macro expansion
-
- ;--( Kernel Variables)
-
- numWritten DD ? ; for calls to WriteConsoleW
- secAttrib SECURITY_ATTRIBUTES <> ; for calls to CreateFileW
- fileInfo _BY_HANDLE_FILE_INFORMATION <> ; for calls to GetFileInformationByHandle
- saveFile OPENFILENAME <> ; for calls to GetSaveFileName
- numRead DD ? ; number of chars read
- distMoveHigh DD ? ; used by REPOSITION-FILE
- lastReadConW DW ? ; used by KEY and others
-
- inRecArray INPUT_RECORD 256 DUP (<>) ; for KEY?
-
- _DATA ENDS
-
- _TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
-
- ;-------------------------------;
- ; Define API Entry ;
- ;-------------------------------;
-
- ;PUBLIC _main ; satisfies console subsystem
-
- ;-----------------------;
- ; Main Program ;
- ;-----------------------;
-
- _main PROC NEAR ; enter program
- ;--( We have to create an NT app exception frame by hand in our assembly-language program.)
- push ebp
- mov ebp, esp
- sub esp, 20
- push ebx
- push esi
- push edi
-
- ;--( Now off we go)
- cld ; !!!***!!! NEXT depends on it, it's this way at boot anyway, but for good luck!
- jmp boot ; apropos the above, see MOVE
-
- ;---------------;
- ; Forth ;
- ;---------------;
-
- ;--( Execution )
-
- ; Implementation detail
- zname <NEST> ; this doesn't have an exe engine, it *is* one, musn't be called from Forth interpretively
- nest: pushrp ip ; @(--RP) := IP
- lea ip,cell[wp] ; IP := @(WP+4)
- next
-
- zname <DOCONST> ; -- x
- push DWORD PTR cell[wp] ; Implementation detail
- next ; Execution engine, works for VARIABLE, also
-
- zname <DODEFER> ; i*x -- j*x, deferred word engine
- mov wp,cell[wp] ; get exe vector storage offset
- add wp,dp ; add base address
- mov wp,[wp] ; deref to get token store there
- innext ; go fer it
-
- zname <DODOES> ; -- x ; Implementation detail
- push DWORD PTR cell[wp] ; push data pointer for this CREATE child
- mov wp,((2*cell))[wp] ; WP := xt for DOES> code
- dereftok ; now is a pointer
- jmp nest
-
- zname <UNNEST> ; -- x R: nest-sys --
- docode ; Implementation detail
- poprpto ip ; IP := @RP++
- next
-
- ; Same routine as above but different name for a debugger to recognize
- fname <EXIT> ; -- R: nest-sys --
- docode ; CORE
- poprpto ip ; IP := @RP++
- next
-
- zname <DOKWORDLIST> ; -- abs-addr
- ; Implementation detail, Execution engine for wordlists declared in the kernel
- lea edx,cell[wp] ; self-pointer to cell in wordlist code body where data address stored
- push edx ; push
- next
-
- zname <DOWORDLIST> ; -- a-addr
- ; Implementation detail, Execution engine for wordlists created by user
- lea edx,cell[wp] ; get self-pointer of a Wordlist code body where data address stored
- add edx,cp ; convert from user dict address to abs address
- push eax ; push
- next
-
- fname <EXECUTE> ; i*x xt -- j*x
- docode ; CORE
- pop wp
- innext
-
- zname <DOLIT> ; -- x
- docode ; Implementation detail
- lodsd ; advance instruction pointer fetching literal value
- push eax ; push literal
- next
-
- zname <DODLIT> ; --
- docode ; Implementation detail
- lodsd ; advance instruction pointer fetching literal value
- mov edx,eax ; save hi 32 bits
- lodsd ; advance instruction pointer fetching literal value
- push eax ; push literal loword
- push edx ; push literal hiword
- next
-
- zname <DOIF> ; flag --
- docode ; Implementation detail, also is UNTIL
- pop eax
- and eax,eax ; test flag
- je doelse ; if zero, we branch
- add ip,cell ; wasn't zero, we advance IP
- next
-
- zname <DOELSE> ; --
- docode ; Implementation detail, also is AGAIN, REPEAT
- doelse: mov wp,[ip]
- dereftok
- mov ip,wp
- next
-
- zname <DOUNTIL> ; flag --
- docode ; Implementation detail
- pop eax
- and eax,eax ; test flag
- je doelse ; if zero, we branch
- add ip,cell ; was zero, we advance IP
- next
-
- zname <DOUNTILNOT> ; flag --
- docode ; Implementation detail, used this once, not sure why ..
- pop eax
- and eax,eax ; test flag
- jne doelse ; if nonzero, we branch
- add ip,cell ; was zero, we advance IP
- next
-
- zname <DODO> ; u1 u2 --
- docode ; Implementation detail
- dodo: lodsd ; WP := exit address
- dereftok
- pushrp wp ; save exit address on return stack
- pop eax ; inner loop index
- pop edx ; outer loop index
- add edx,80000000H ; add overflow limit to outer
- sub eax,edx ; massage inner
- pushrp edx ; push massaged outer to RStack
- pushrp eax ; push massaged inner to RStack
- next
-
- zname <DOQDO> ; u1 u2 --
- docode ; Implementation detail
- mov edx,[esp] ; copy of TOS
- cmp cell[esp],edx ; compare to other index
- jne dodo ; they are different: go ahead and DO
- add esp,(2*cell) ; same: clear stack
- lodsd ; WP := @IP++
- dereftok
- mov ip,wp ; IP := WP i.e., exit address compiled in cell ahead of DOQDO token
- next ; onwards
-
- zname <DOLOOP> ; --
- docode ; Implementation detail
- doloop: poprpto eax ; massaged inner index
- inc eax ; increment
- jo doloop1 ; overflow flag, we're done
- pushrp eax ; not done, return incremented count
- lodsd ; WP := @IP++, i.e., WP is loaded with branchback address
- dereftok
- mov ip,wp ; IP := branch back
- next ; continue
- doloop1:
- add rp,(2*cell) ; clear return stack
- add ip,cell ; branch past loopback address
- next ; onwards and outwards
-
- zname <DOPLUSLOOP> ; n1 --
- docode ; Implementation detail
- poprpto eax ; massaged inner index
- pop edx ; increment
- add eax,edx ; add increment to index
- jo doloop1 ; overflow flag, we're done, we can re-use the above code
- pushrp eax ; not done, return incremented count
- lodsd ; WP := @IP++, i.e., WP is loaded with branchback address
- dereftok
- mov ip,wp ; IP := branch back
- next ; continue
-
- ; Strings for S" and TYPE must reside in data space. In the dictionary they are recorded /DOSQUOTE/D-ADDR/
- zname <DOSQUOTE> ; -- c-addr u
- docode ; Implementation detail
- lodsd ; count address in ax
- xor edx,edx ; clear dx
- mov dx,[eax][dp] ; get count
- add eax,tchar ; form data address of string
- push eax ; push c-addr
- push edx ; push u
- next
-
- zname <DODOTQUOTE> ; --
- docode ; Implementation detail
- lodsd ; count address in wp (EAX)
- xor edx,edx ; clear dx
- mov dx,[eax+dp] ; get count
- add eax,tchar ; form data address of string
- push eax ; push c-addr
- push edx ; push u
- jmp ftype ; goto type
-
- zname <DOKDOTQUOTE> ; -- Print strings stored in the kernel exe data section
- docode ; Implementation detail.
- lodsd ; count address in wp (EAX)
- sub eax,dp ; convert to data-relative address
- xor edx,edx ; clear dx
- mov dx,[eax+dp] ; get count
- add eax,tchar ; form data address of string
- push eax ; push c-addr
- push edx ; push u
- jmp ftype ; goto typ
-
- ;--( Stack Operators )
-
- fname <DROP> ; x --
- docode ; CORE
- pop eax
- next
-
- fnamemanque <2DROP> ; x1 x2 --
- fw_TWO_DROP:
- docode ; CORE
- pop eax
- pop eax
- next
-
- fnamemanque <?DUP> ; x -- x x | 0
- fw_QDUP:
- docode ; CORE
- cmp DWORD PTR [esp],0
- jne dupe
- next
-
- fname <DUP> ; x -- x x
- docode ; CORE
- dupe: push [esp]
- next
-
- fnamemanque <2DUP> ; x1 x2 -- x1 x2 x1 x2
- fw_TWO_DUP:
- docode ; CORE
- push cell[esp]
- push cell[esp]
- next
-
- fname <OVER> ; x1 x2 -- x1 x2 x1
- dd over ; CORE
- over: push cell[esp]
- next
-
- fnamemanque <2OVER> ; x1 x2 x3 x4-- x1 x2 x3 x4 x1 x2
- fw_TWO_OVER:
- docode ; CORE
- push (3*cell)[esp]
- push (3*cell)[esp]
- next
-
- fname <ROT> ; x1 x2 x3 -- x2 x3 x1
- docode ; CORE
- pop eax
- pop ecx
- pop edx
- push ecx
- push eax
- push edx
- next
-
- nnamemanque <-ROT> ; x1 x2 x3 -- x3 x1 x2
- fw_NEGROT: ; Not in Standard
- docode
- pop eax
- pop ecx
- pop edx
- push eax
- push edx
- push ecx
- next
-
- fname <SWAP> ; x1 x2 -- x2 x1
- docode ; CORE
- pop eax
- pop edx
- push eax
- push edx
- next
-
- fnamemanque <2SWAP> ; x1 x2 x3 x4-- x3 x4 x1 x2
- fw_TWO_SWAP: ; CORE
- docode
- mov eax,(3*cell)[esp]
- mov edx,cell[esp]
- mov (3*cell)[esp],edx
- mov cell[esp],eax
- mov eax,((2*cell))[esp]
- mov edx,[esp]
- mov ((2*cell))[esp],edx
- mov [esp],eax
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 2
- db '>',0,'R',0 ; x -- R: -- x
- align 4 ; CORE
- fw_TO_R:
- docode
- sub rp,cell
- pop [rp]
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 3
- db '2',0,'>',0,'R',0 ; x1 x2 -- R: -- x1 x2
- align 4 ; CORE EXT
- fw_TWO_TO_R:
- docode
- pop eax
- sub rp,cell
- pop [rp]
- sub rp,cell
- mov [rp],eax
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 2
- db 'R',0,'>',0 ; -- x R: x --
- align 4 ; CORE
- fw_R_FROM:
- docode
- push [rp]
- add rp,cell
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 3
- db '2',0,'R',0,'>',0 ; -- x1 x2 R: x1 x2 --
- align 4 ; CORE EXT
- fw_TWO_R_FROM:
- docode
- mov eax,[rp]
- add rp,cell
- push [rp]
- add rp,cell
- push eax
- next
-
- fnamemanque <R@> ; -- x R: x -- x
- fw_R_FETCH: ; CORE
- docode
- push DWORD PTR [rp]
- next
-
- ; Can't use our name header macros with this one!
- linkme nlinkptr
- countcell 3
- db 'R',0,'P',0,'!',0 ; addr --
- align 4 ; Implementation
- fw_RP_STORE:
- docode
- pop rp
- next
-
- nnamemanque <RP@>
- fw_RP_FETCH: ; -- addr
- docode ; Implementation
- push rp
- next
-
- fname <TUCK> ; x1 x2 -- x2 x1 x2
- docode ; CORE EXT
- pop eax
- pop edx
- push eax
- push edx
- push eax
- next
-
- fname <NIP> ; x1 x2 -- x2
- docode ; CORE EXT
- pop eax
- pop edx
- push eax
- next
-
- fname <PICK> ; xu .. x1 x0 u -- xu .. x1 x0 xu
- docode ; CORE EXT
- pop eax
- push [esp][eax*cell]
- next
-
- fname <DEPTH> ; i*x -- i*x i
- ctok NEST ; CORE
- ctok SP_FETCH ; -- @esp
- ctok SP0
- ctok FETCH ; -- @esp @orig-esp
- ctok SWAP
- ctok MINUS ; -- diff
- literal 1
- ctok CELLS ; -- diff cell-size
- ctok SLASH ; -- cells-diff
- ctok UNNEST
-
- ; Get current data stack pointer value, an absolute address
- nnamemanque <SP@> ; -- abs-addr
- fw_SP_FETCH: ; Not in Standard
- docode
- push esp
- next
-
- ; Can't use our name header macros with this one!
- linkme nlinkptr
- countcell 3
- db 'S',0,'P',0,'!' ; abs-addr -- Set data stack pointer value, an absolute address
- align 4
- fw_SP_STORE: ; Not in Standard
- docode
- pop esp
- next
-
- ; Get saved-at-boot data stack pointer value
- nname <SP0> ; -- a-addr
- ctok DOCONST ; Not in Standard
- dd ntConESP
-
- ;--( Data Movement )
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 1
- db '!',0 ; x a-addr --
- align 4 ; CORE
- fw_STORE:
- docode
- pop eax
- pop [eax][dp]
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 2
- db '+',0,'!',0 ; x a-addr --
- align 4 ; CORE
- fw_PL_STORE:
- docode
- pop eax
- pop edx
- add [eax][dp],edx
- next
-
- fnamemanque <@> ; a-addr -- x
- fw_FETCH:
- docode ; CORE
- pop eax
- push [eax][dp]
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 2
- db 'C',0,'!',0 ; c c-addr --
- align 4 ; CORE
- fw_C_STORE:
- docode
- pop eax
- pop edx
- mov [eax][dp],dx
- next
-
- fnamemanque <C@> ; c-addr -- c
- fw_C_FETCH:
- docode ; CORE
- mov eax,[esp]
- mov dx,[eax][dp]
- movzx eax,dx
- mov [esp],eax
- next
-
- ; Can't use our name header macros with this one!
- linkme nlinkptr
- countcell 2
- db 'B',0,'!',0 ; byte c-addr --
- align 4 ; Not in Standard
- fw_B_STORE:
- docode
- pop eax
- pop edx
- mov [eax][dp],dl
- next
-
- nnamemanque <B@> ; c-addr -- byte
- fw_B_FETCH:
- docode ; Not in Standard
- mov eax,[esp]
- mov dl,[eax][dp]
- movzx eax,dl
- mov [esp],eax
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 2
- db '2',0,'!',0 ; x1 x2 a-addr --
- align 4 ; CORE
- fw_TWO_STORE:
- docode
- pop eax
- pop [eax][dp]
- pop [eax+cell][dp]
- next
-
- fnamemanque <2@> ; a-addr -- x1 x2
- fw_TWO_FETCH:
- docode ; CORE
- pop eax
- push [eax+cell][dp]
- push [eax][dp]
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 1
- db ',',0 ; x --
- align 4 ; CORE
- fw_COMMA:
- docode
- mov eax,[dp+datap] ; get data space pointer
- pop [eax][dp] ; pop to that offset in data space
- add DWORD PTR datap[dp],cell ; post-increment pointer
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 2
- db 'C',0,',',0 ; char --
- align 4 ; CORE
- fw_CCOMMA:
- docode
- mov eax,[dp+datap] ; get data space pointer
- pop edx ; get char
- mov [eax][dp],dx ; pop char to that offset in data space
- add DWORD PTR datap[dp],tchar ; post-increment pointer
- next
-
- fname <MOVE> ; addr1 addr2 u --
- docode
- pop ecx ; count
- pop eax ; destination
- pop edx ; source
- and ecx,ecx ; is count zero?
- je move2 ; if zero count, exit
- cld ; now set to move string upwards
- cmp eax,edx ; destination - source
- jb move1 ; jump if destination < source, continue further on
- add eax,ecx
- dec eax
- add edx,ecx
- dec edx
- std ; destination >= source, copy downwards
- move1: add eax,dp ; absolute destination
- add edx,dp ; absolute source
- push edi ; save edi
- push esi ; save esi
- push edx ; load source
- pop esi
- push eax ; load dest
- pop edi
- push ds ; same seg ..
- pop es ; .. for source and dest
- rep movsb ; copy address units ... this can be optimized later
- pop esi ; restore esi
- pop edi ; restore edi
- cld ; !!!***!!! VERY IMPORTANT because NEST depends on it !!!***!!!
- move2: next
-
- ;--( Comparisons )
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 2
- db '0',0,'<',0 ; x -- flag
- align 4 ; CORE
- fw_ZEROLT:
- docode
- mov eax,[esp]
- shl eax,1
- sbb edx,edx
- mov [esp],edx
- next
-
- fnamemanque <0=> ; x -- flag
- fw_ZEROEQ:
- docode ; CORE
- mov eax,[esp]
- and eax,eax
- je zeroeq1
- mov DWORD PTR [esp],FALSE
- next
- zeroeq1:
- mov DWORD PTR [esp],TRUE
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 3
- db '0',0,'<',0,'>',0 ; x -- flag
- align 4 ; CORE EXT
- fw_ZERONE:
- docode
- mov eax,[esp]
- and eax,eax
- jne zeroeq1 ; reuse code above
- mov DWORD PTR [esp],FALSE
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 2
- db '0',0,'>',0 ; x -- flag
- align 4 ; CORE EXT
- fw_ZEROGT:
- ctok NEST
- ctok DUP ; -- x x
- ctok ZEROLT ; -- x flag
- ctok SWAP ; -- flag x
- ctok ZEROEQ ; -- flag1 flag2
- ctok OR ; -- flag
- ctok ZEROEQ ; -- flag'
- ctok UNNEST
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 1
- db '<',0 ; n1 n2 -- flag
- align 4 ; CORE
- fw_LESS:
- docode
- pop eax
- mov edx,[esp]
- cmp edx,eax
- jl less1
- mov DWORD PTR [esp],FALSE
- next
- less1: mov DWORD PTR [esp],TRUE
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 2
- db 'U',0,'<',0 ; u1 u2 -- flag
- align 4 ; CORE
- fw_U_LESS:
- docode
- pop eax
- mov edx,[esp]
- cmp edx,eax
- jb less1 ; we can re-use code from above
- mov DWORD PTR [esp],FALSE
- next
-
- ; Can't use our name header macros with this one!
- linkme nlinkptr
- countcell 3
- db 'U',0,'D',0,'<',0 ; ud1 ud2 -- flag
- align 4 ; Not in standard
- fw_UD_LESS:
- docode
- pop edx ; ud2h
- pop eax ; ud2l
- pop ecx ; ud1h
- cmp edx,ecx ; ud2h
- ja udless ; if ud2h > ud1h, TRUE
- jb nudless ; if ud2h < ud1h, FALSE
- cmp eax,[esp] ; they were equal, try low half
- ja udless ; now if ud2l > ud1l, TRUE
- nudless: ; ud2l =< ud1l, FALSE
- mov DWORD PTR [esp],FALSE
- next
- udless: mov DWORD PTR [esp],TRUE
- next
-
- nname <UDMIN> ; ud1 ud2 -- ud1|ud2
- ctok NEST ; Not in standard
- ctok TWO_OVER
- ctok TWO_OVER ; -- ud1 ud2 ud1 ud2
- ctok D_EQUAL ; -- ud1 ud2 flag
- compif udmin1 ; they're the same, drop the top
- ctok TWO_DROP
- ctok EXIT
- udmin1:
- ctok TWO_OVER
- ctok TWO_OVER ; -- ud1 ud2 ud1 ud2
- ctok UD_LESS ; -- ud1 ud2 flag
- compif udmin2 ; is ud1 ud< u2?
- ctok TWO_DROP ; -- ud1, yes, leave ud1
- ctok EXIT
- udmin2: ; no, so ud1 u> ud2
- ctok ROT
- ctok DROP
- ctok ROT
- ctok DROP ; -- ud2
- ctok UNNEST
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 2
- db 'D',0,'=',0 ; xd1 xd2 -- flag
- align 4 ; DOUBLE
- fw_D_EQUAL:
- docode
- pop edx ; d2h
- pop eax ; d2l
- pop ecx ; d1h
- cmp edx,ecx ; d2h == d1h?
- jne dnequal ; no
- cmp eax,[esp] ; yes, try lower
- jne dnequal ; d2l != d1l
- mov DWORD PTR [esp],TRUE ; d2l == d1l
- next
- dnequal:
- mov DWORD PTR [esp],FALSE
- next
-
- fnamemanque <D0=> ; xd -- flag
- fw_D_ZEROEQ: ; DOUBLE
- docode
- pop eax
- and eax,eax
- jne dzeroeq1
- or eax,[esp]
- jne dzeroeq1
- mov DWORD PTR [esp],TRUE
- next
- dzeroeq1:
- mov DWORD PTR [esp],FALSE
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 1
- db '=',0 ; x1 x2 -- flag
- align 4 ; CORE
- fw_EQUAL:
- docode
- pop eax
- mov edx,[esp]
- cmp eax,edx
- je equal1
- mov DWORD PTR [esp],FALSE
- next
- equal1: mov DWORD PTR [esp],TRUE
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 2
- db '<',0,'>',0 ; x1 x2 -- flag
- align 4 ; CORE EXT
- fw_NEQUAL:
- docode
- pop eax
- mov edx,[esp]
- cmp eax,edx
- jne equal1 ; re-using above code
- mov DWORD PTR [esp],FALSE
- next
-
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 1
- db '>',0 ; n1 n2 -- flag
- align 4 ; CORE
- fw_GREATER:
- docode
- pop eax
- mov edx,[esp]
- cmp edx,eax
- jg greater1
- mov DWORD PTR [esp],FALSE
- next
- greater1:
- mov DWORD PTR [esp],TRUE
- next
-
- fname <MAX> ; n1 n2 -- n3
- docode ; CORE
- pop eax
- pop edx
- cmp eax,edx
- jl f_max1
- push eax
- next
- f_max1: push edx
- next
-
- fname <MIN> ; n1 n2 -- n3
- docode ; CORE
- pop edx
- pop eax
- cmp eax,edx
- jg f_max1 ; reuse code from above
- push eax
- next
-
- fname <WITHIN> ; n|u1 n|u2 n|u3 -- flag
- ctok NEST ; CORE EXT
- ctok OVER
- ctok MINUS ; -- n1 n2 diffn3n2
- ctok TO_R ; -- n1 n2 R: -- diffn3n2
- ctok MINUS ; -- diffn1n2 R: -- diffn3n2
- ctok R_FROM ; -- diffn1n2 diffn3n2 R: --
- ctok U_LESS ; -- flag
- ctok UNNEST
-
- ;--( Integer Math )
-
- fnamemanque <1+> ; n|u1 -- n|u2
- fw_ONE_PLUS:
- docode
- add DWORD PTR [esp],1
- next
-
- fnamemanque <1-> ; n|u1 -- n|u2
- fw_ONE_MINUS:
- docode
- sub DWORD PTR [esp],1
- next
-
- fname <ABS> ; n -- u
- ctok NEST ; CORE
- ctok DUP
- ctok ZEROLT ; -- n flag
- compif abs1
- ctok NEGATE
- abs1: ctok UNNEST ; -- _n_
-
- fname <DABS> ; d -- ud
- ctok NEST ; DOUBLE
- ctok DUP
- ctok ZEROLT ; -- d flag
- compif dabs1
- ctok DNEGATE
- dabs1: ctok UNNEST ; -- _d_
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 3
- db 'S',0,'>',0,'D',0 ; n1 -- d1
- align 4 ; CORE
- fw_S_TO_D:
- docode
- mov eax,[esp]
- cdq
- push edx
- next
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 3
- db 'D',0,'>',0,'S',0 ; d1 -- s1
- align 4 ; DOUBLE
- fw_D_TO_S:
- docode
- pop eax
- next
-
- fname <NEGATE> ; n1 -- n2
- docode ; CORE
- mov eax,[esp]
- neg eax
- mov [esp],eax
- next
-
- fname <DNEGATE> ; d1 -- d2
- docode ; DOUBLE
- xor eax,eax
- xor edx,edx
- sub eax,cell[esp]
- sbb edx,[esp]
- mov cell[esp],eax
- mov [esp],edx
- next
-
- fnamemanque <+> ; n|u1 n|u2 -- n|u3
- fw_PLUS: ; CORE
- docode
- pop eax
- add [esp],eax
- next
-
- fnamemanque <D+> ; ud|d1 ud|d2 -- ud|d3
- fw_D_PLUS: ; DOUBLE
- docode
- pop edx ; d2h
- pop eax ; d2l
- add cell[esp],eax ; d1l+d2l
- adc [esp],edx ; d1h+d2h+carry
- next
-
- fnamemanque <-> ; n|u1 n|u2 -- n|u3
- fw_MINUS: ; CORE
- docode
- pop eax
- sub [esp],eax
- next
-
- fnamemanque <D-> ; ud|d1 ud|d2 -- ud|d3
- fw_D_MINUS: ; DOUBLE
- docode
- pop edx ; d2h
- pop eax ; d2l
- sub cell[esp],eax ; d1l-d2l
- sbb [esp],edx ; d1h-d2h-borrow
- next
-
- fnamemanque <*> ; n|u1 n|u2 -- n|u3
- fw_STAR: ; CORE
- docode
- pop eax
- imul DWORD PTR[esp]
- mov [esp],eax
- next
-
- fnamemanque </> ; n1 n2 -- n3
- fw_SLASH: ; CORE
- docode
- pop ecx ; n2
- pop eax ; n1
- cdq ; high order for div
- idiv ecx ; n1 / n2
- push eax ; quotient
- next ; -- n3
-
- fnamemanque </MOD> ; n1 n2 -- n3 n4
- fw_SLMOD: ; CORE
- docode
- pop ecx ; n2
- pop eax ; n1
- cdq ; high order for div
- idiv ecx ; n1 / n2
- push edx ; remainder
- push eax ; quotient
- next ; -- n3 n4
-
- fname <MOD> ; n1 n2 -- n3
- ctok NEST
- ctok SLMOD
- ctok DROP
- ctok UNNEST
-
- fnamemanque <*/> ; n1 n2 n3 -- n4
- fw_STARSL: ; CORE
- docode
- pop ecx ; n3
- pop edx ; n2
- pop eax ; n1
- imul edx ; n1 * n2
- idiv ecx ; intermediate / n3
- push eax ; quotient
- next ; -- n4
-
- fnamemanque <*/MOD> ; n1 n2 n3 -- n4 n5
- fw_STARSLMOD: ; CORE
- docode
- pop ecx ; n3
- pop edx ; n2
- pop eax ; n1
- imul edx ; n1 * n2
- idiv ecx ; intermediate / n3
- push edx ; remainder
- push eax ; quotient
- next ; -- n4 n5
-
- nnamemanque <DUM/MOD> ; d1 n1 -- n2 d2
- fw_DUMSLMOD: ; not in Standard
- ctok NEST
- ctok TO_R ; -- d1l d1h R: -- n1
- literal 0 ; -- d1l d1h 0 R: -- n1
- ctok R_FETCH ; -- d1l d1h 0 n1 R: -- n1
- ctok UMSLMOD ; -- d1l r1 q1 R: -- n1
- ctok R_FROM ; -- d1l r1 q1 n1 R: --
- ctok SWAP ; -- d1l r1 n1 q1 R: --
- ctok TO_R ; -- d1l r1 n1 R: -- d2h
- ctok UMSLMOD ; -- r2 q2 R: -- d2h
- ctok R_FROM ; -- n2 d2
- ctok UNNEST ; -- n2 d2
-
- fnamemanque <FM/MOD> ; d1 n1 -- n2 n3
- fw_FMSLMOD: ; CORE
- ctok NEST
- ctok DUP ; -- d1 n1
- ctok TO_R ; -- d1 n1 R: -- n1
- ctok ZEROLT ; -- d1 flag R: -- n1
- compif fmslmod1
- ctok DNEGATE
- fmslmod1:
- ctok S_TO_D ; -- d1l d1hl d1hh R: -- n1
- ctok R_FETCH ; -- d1l d1hl d1hh n1 R: -- n1
- ctok ABS ; -- d1l d1hl d1hh _n1_ R: -- n1
- ctok AND ; -- d1l d1hl d1hh _n1_ R: -- n1
- ctok PLUS ; -- d1l intermed R: -- n1
- ctok R_FETCH ; -- d1l intermed n1 R: -- n1
- ctok ABS ; -- d1l intermed _n1_ R: -- n1
- ctok UMSLMOD ; -- n2' n3 R: -- n1
- ctok SWAP ; -- n3 n2' R: -- n1
- ctok R_FROM ; -- n3 n2' n1 R: --
- ctok ZEROLT ; -- n3 n2' flag
- compif fmslmod2
- ctok NEGATE ; -- n3 n2
- fmslmod2:
- ctok SWAP ; -- n2 n3
- ctok UNNEST
-
- fnamemanque <SM/REM> ; d1 n1 -- n2 n3
- fw_SMSLREM: ; CORE
- docode
- pop ecx ; u1
- pop edx ; udh
- pop eax ; udl
- idiv ecx
- push edx ; remainder
- push eax ; quotient
- next ; -- u2 u3
-
- fnamemanque <UM*> ; u1 u2 -- ud
- fw_UMSTAR: ; CORE
- docode
- mov eax,cell[esp] ; u1
- mul DWORD PTR [esp] ; u1*u2
- mov cell[esp],eax ; udl
- mov [esp],edx ; udh
- next ; -- ud
-
- fnamemanque <UM/MOD> ; ud u1 -- u2 u3)
- fw_UMSLMOD: ; CORE
- docode
- pop ecx ; u1
- pop edx ; udh
- pop eax ; udl
- div ecx
- push edx ; remainder
- push eax ; quotient
- next ; -- u2 u3
-
- fnamemanque <M*> ; n1 n2 -- d
- fw_MSTAR: ; CORE
- docode
- mov eax,cell[esp] ; n1
- imul DWORD PTR [esp] ; n1*n2
- mov cell[esp],eax ; dl
- mov [esp],edx ; dh
- next ; -- ud
-
- nnamemanque <UD*U> ; ud1 u1 -- ud2
- fw_UDSTARU: ; not in standard
- docode
- pop ecx ; u1
- pop eax ; ud1h
- mul ecx ; produce extended ud2h
- mov edx,ecx ; discard upper dword of ud2he, move multiplier into edx
- mov ecx,eax ; save lower portion of ud2he in ecx
- pop eax ; ud1l
- mul edx ; ud2l in eax
- push eax ; return ud2l
- add edx,ecx ; form ud2h
- push edx ; return ud2h
- next ; -- ud2
-
- ;--( Bit Operators )
-
- fname <TRUE> ; -- flag
- ctok DOCONST ; CORE EXT
- dd TRUE
-
- fname <FALSE> ; -- flag
- ctok DOCONST ; CORE EXT
- dd FALSE
-
- fname <AND> ; x1 x2 -- x3
- docode ; CORE
- pop eax
- and [esp],eax
- next
-
- fname <OR> ; x1 x2 -- x3
- docode ; CORE
- pop eax
- or [esp],eax
- next
-
- fname <XOR> ; x1 x2 -- x3
- docode ; CORE
- pop eax
- xor [esp],eax
- next
-
- fname <INVERT> ; x1 -- x2
- docode ; CORE
- mov eax,[esp]
- not eax
- mov [esp],eax
- next
-
- fnamemanque <2*> ; x1 -- x2
- fw_TWO_STAR: ; CORE
- docode
- mov eax,[esp]
- shl eax,1
- mov [esp],eax
- next
-
- fnamemanque <2/> ; x1 -- x2
- fw_TWO_SLASH: ; CORE
- docode
- mov eax,[esp]
- sar eax,1
- mov [esp],eax
- next
-
- fname <LSHIFT> ; x1 u -- x2
- docode ; CORE
- pop ecx
- mov eax,[esp]
- shl eax,cl
- mov [esp],eax
- next
-
- fname <RSHIFT> ; x1 u -- x2
- docode ; CORE
- pop ecx
- mov eax,[esp]
- shr eax,cl
- mov [esp],eax
- next
-
- ;--( Characters )
-
- fname <BL> ; -- char
- ctok DOCONST ; CORE
- dd 20H
-
- fname <CHAR> ; -- char
- ctok NEST ; CORE
- ctok BL
- ctok WORD
- ctok CHAR_PLUS
- ctok C_FETCH
- ctok UNNEST
-
- finamemanque <[CHAR]> ; -- Execution: -- char
- fw_BRACHETCHAR:
- ctok NEST ; CORE
- ctok CHAR
- ctok LITERAL
- ctok UNNEST
-
- fname <SPACE> ; --
- ctok NEST ; CORE
- ctok BL
- ctok EMIT
- ctok UNNEST
-
- fname <SPACES> ; n --
- ctok NEST ; CORE
- literal 0
- ctok MAX
- literal 0
- compqdo spaces1
- spaces0:
- ctok SPACE
- comploop spaces0
- spaces1:
- ctok UNNEST
-
- fnamemanque <CHAR+> ; c-addr1 -- c-addr2
- fw_CHAR_PLUS: ; CORE
- docode
- add DWORD PTR [esp],tchar
- next
-
- fname <CHARS> ; n1 -- n2
- ctok NEST ; CORE
- literal tchar
- ctok STAR
- ctok UNNEST
-
- fname <FILL> ; c-addr u char --
- docode ; CORE
- pop eax ; char
- pop ecx ; count
- pop edx ; dest
- jecxz fill_done ; zero count? we're done before we start
- add edx,dp ; abs addr
- push ds
- pop es ; same seg, this is default, but user might have changed it in a CODE word
- push edi ; save edi
- push edx
- pop edi ; load destination
- rep stosw ; store char
- pop edi ; restore edi
- fill_done:
- next
-
- ;--( Strings )
-
- fnamemanque </STRING> ; c-addr1 u1 n -- c-addr2 u2
- fw_SLSTRING:
- ctok NEST
- ctok ROT ; -- u1 n c-a1
- ctok OVER ; -- u1 n c-a1 n
- ctok CHARS ; -- u1 n c-a1 nbytes
- ctok PLUS ; -- u1 n c-a2
- ctok NEGROT ; -- c-a2 u1 n
- ctok MINUS ; -- c-a2 u2
- ctok UNNEST
-
- fname <CMOVE> ; c-addr1 c-addr2 u --
- ctok NEST ; STRING
- ctok QDUP ; -- c-addr1 c-addr2 [ u u | 0 ]
- ctok ZEROEQ
- compif cmove1
- ctok TWO_DROP ; --
- ctok EXIT
- cmove1: literal 0
- compdo cmove3
- cmove2: ctok OVER ; -- c-addr1 c-addr2 c-addr1
- ctok C_FETCH ; -- c-addr1 c-addr2 char
- ctok OVER ; -- c-addr1 c-addr2 char c-addr2
- ctok C_STORE ; -- c-addr1 c-addr2
- ctok CHAR_PLUS ; -- c-addr1 c-addr2'
- ctok SWAP
- ctok CHAR_PLUS ; -- c-addr2' c-addr1'
- ctok SWAP ; -- c-addr1' c-addr2'
- comploop cmove2
- cmove3: ctok TWO_DROP
- ctok UNNEST ; --
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 6
- db 'C',0,'M',0,'O',0,'V',0,'E',0,'>',0 ; c-addr1 c-addr2 u --
- align 4 ; STRING
- fw_CMOVER:
- ctok NEST
- ctok QDUP ; -- c-addr1 c-addr2 [ u u | 0 ]
- ctok ZEROEQ
- compif cmover1
- ctok TWO_DROP ; --
- ctok EXIT
- cmover1:
- ctok DUP ; -- c-addr1 c-addr2 u u
- ctok TO_R ; -- c-addr1 c-addr2 u R: -- u
- ctok CHARS ; -- c-addr1 c-addr2 u' R: -- u
- ctok TUCK ; -- c-addr1 u' c-addr2 u' R: -- u
- ctok PLUS ; -- c-addr1 u' c-addr2' R: -- u
- ctok TO_R ; -- c-addr1 u' R: -- u c-addr2'
- ctok PLUS ; -- c-addr1' R: -- u c-addr2'
- ctok R_FROM
- ctok R_FROM ; -- c-addr1' c-addr2' u
- literal 0
- compdo cmover3
- cmover2:
- literal tchar ; -- c-addr1' c-addr2' n
- ctok MINUS ; -- c-addr1' c-addr2''
- ctok SWAP
- literal tchar
- ctok MINUS ; -- c-addr2'' c-addr1''
- ctok SWAP ; -- c-addr1'' c-addr2''
- ctok OVER ; -- c-addr1'' c-addr2'' c-addr1''
- ctok C_FETCH ; -- c-addr1'' c-addr2'' char
- ctok OVER ; -- c-addr1'' c-addr2'' char c-addr2''
- ctok C_STORE ; -- c-addr1'' c-addr2''
- comploop cmover2
- cmover3:
- ctok TWO_DROP ; --
- ctok UNNEST
-
- fname <COUNT> ; c-addr1 -- c-addr2 u
- docode
- mov eax,[esp]
- xor edx,edx
- mov dx,[eax][dp]
- add eax,tchar
- mov [esp],eax
- push edx
- next
-
- fname <COMPARE> ; c-addr1 u1 c-addr2 u2 -- n
- docode ; STRING
- pop ecx ; u2
- pop edx ; c-addr2
- add edx,dp ; convert to abs addr
- pop eax ; u1
- cmp ecx,eax ; counts equal?
- je compare_e ; yes, continue further on
- jl compare_u1 ; if u2 (in ecx) is lesser, continue further on
- mov ecx,eax ; u2 > u1
- mov eax,[esp] ; c-addr1
- add eax,dp ; convert to abs addr
- push esi ; preserve
- push edi ; preserve
- push ds ;
- pop es ; set ES, this is probably redundant in view of system requirements
- mov esi,eax ; c-addr1
- mov edi,edx ; c-addr2
- cld ; direction upwards
- repe cmpsw ; unicode is 2-byte chars
- je compare_neg1 ; all matched, u2 > u1
- mov ax,[esi]
- cmp ax,[edi] ; compare non-match c-addr1 char to c-addr2 char
- jl compare_neg1 ; c-addr1 char is less
- jmp SHORT compare_1 ; c-addr2 char is less
- compare_u1: ; u1 > u2
- mov eax,[esp] ; c-addr1
- add eax,dp ; convert to abs addr
- push esi ; preserve
- push edi ; preserve
- push ds ;
- pop es ; set ES, this is probably redundant in view of system requirements
- mov esi,eax ; c-addr1
- mov edi,edx ; c-addr2
- cld ; direction upwards
- repe cmpsw ; unicode is 2-byte chars
- je compare_1 ; all matched, u1 > u2
- mov ax,[esi]
- cmp ax,[edi] ; compare non-match c-addr1 char to c-addr2 char
- jl compare_neg1 ; c-addr1 char is less
- jmp SHORT compare_1 ; c-addr2 char is less
- compare_e: ; u1 = u2
- mov eax,[esp] ; c-addr1
- add eax,dp ; convert to abs addr
- push esi ; preserve
- push edi ; preserve
- push ds ;
- pop es ; set ES, this is probably redundant in view of system requirements
- mov esi,eax ; c-addr1
- mov edi,edx ; c-addr2
- cld ; direction upwards
- repe cmpsw ; unicode is 2-byte chars
- je compare_0 ; all matched
- mov ax,[esi-2] ; since we're pointing one past the unmatching char
- cmp ax,[edi-2] ; compare non-match c-addr1 char to c-addr2 char
- jl compare_neg1 ; c-addr1 char is less
- jmp SHORT compare_1 ; c-addr2 char is less
- compare_0:
- xor eax,eax
- mov ((2*cell))[esp],eax ; strings are equal and u1 = u2
- jmp SHORT compare_done
- compare_1:
- mov eax,1
- mov ((2*cell))[esp],eax ; char at first non-match in c-addr1 .gt. corresponding in c-addr2
- jmp SHORT compare_done ; or strings equal, and u1 > u2
- compare_neg1:
- mov eax,-1
- mov ((2*cell))[esp],eax ; char at first non-match in c-addr1 .lt. corresponding in c-addr2
- jmp SHORT compare_done ; or strings equal, and u1 < u2
- compare_done:
- pop edi
- pop esi
- next
-
- nname <PLACE> ; c-addr1 u c-addr2
- ctok NEST ; Not in Standard
- ctok TWO_DUP ; c-addr1 u c-addr2 u c-addr2
- ctok C_STORE ; c-addr1 u c-addr2
- ctok CHAR_PLUS ; c-addr1 u c-addr2'
- ctok SWAP ; c-addr1 c-addr2' u
- ctok CHARS ; c-addr1 c-addr2' u'
- ctok MOVE ; --
- ctok UNNEST
-
- nname <SKIP> ; ( c-addr1 u1 char --- c-addr2 u2)
- docode ; Not in standard, skip to first non-match
- pop eax ; -- c-addr u1
- pop ecx ; -- c-addr1 u count to iteration register
- pop edx ; -- address of start of string
- add edx,dp ; -- add offset to base of data region, forming absolute address
- push edi ; -- edi preserve edi
- push ds ; -- edi ds
- pop es ; -- edi load es from ds
- push edx ; -- edi abs-addr1
- pop edi ; -- edi load edi
- cld ; ascending search
- repe scasw ; search for non-match
- je skip_fail ; zero is set if no non-match was found
- pop eax ; -- saved di
- push edi ; -- abs-addr2 address after end of string, abs
- pop edx ; -- get it back
- sub edx,tchar ; -- move it back to point to non-match char
- sub edx,dp ; -- convert back to data-relative address
- push edx ; -- c-addr2 return it
- inc ecx ; -- c-addr2 back count up to match point
- push ecx ; -- c-addr2 u2 return count of remainder of string
- push eax ; -- c-addr2 u2 di
- pop edi ; -- c-addr2 u2 restore edi
- next
- skip_fail:
- pop eax ; saved edi
- push edi ; address after end of string, abs
- pop edx ; get it back
- sub edx,dp ; convert back to data-relative address
- push edx ; return it
- push ecx ; return zero which will be in ecx in this branch
- push eax ; that ol' saved di
- pop edi ; restore, -- c-addr2 u2
- next
-
- nname <SCAN> ; ( c-addr1 u1 char --- c-addr2 u2)
- docode ; Not in Standard, point to head of substring c-addr2 u2 where char first found
- pop eax ; char
- pop ecx ; count to iteration register
- pop edx ; address of start of string
- add edx,dp ; add offset to base of data seg
- push edi ; save edi
- push ds
- pop es ; load es from ds
- push edx
- pop edi ; load edi
- cld ; ascending search
- repne scasw ; search for match
- jne scan_fail ; zero is set if char was ever found
- pop eax ; saved edi
- push edi ; address after end of string, abs
- pop edx ; get it back
- sub edx,tchar ; move it back to match char
- sub edx,dp ; convert back to data-relative address
- push edx ; return it
- inc ecx ; back count up to match point
- push ecx ; return count of remainder of string
- push eax ; that ol' saved edi
- pop edi ; restore, -- c-addr2 u2
- next
- scan_fail:
- pop eax ; saved edi
- push edi ; address after end of string, abs
- pop edx ; get it back
- sub edx,dp ; convert back to data-relative address
- push edx ; return it
- push ecx ; return zero which will be in ecx in this branch
- push eax ; that ol' saved edi
- pop edi ; restore, -- c-addr2 u2
- next
-
- fnamemanque <-TRAILING> ; c-addr1 u1 -- c-addr1 u2
- fw_DASH_TRAILING: ; STRING
- docode
- mov ecx,[esp] ; count
- mov edx,cell[esp] ; string address
- add edx,ecx ; do this twice to handle wide character size
- add edx,ecx ; point past end of string
- sub edx,tchar ; point to last character in string
- add edx,dp ; absolute address
- mov ax,20h ; blank
- push edi ; preserve edi
- push edx ; end-of-string abs address
- pop edi ; load edi
- push ds
- pop es ; same seg, probably redundant
- std ; backwards search
- repe scasw ; seek non-match with char
- je none_trailing ; no non-blanks
- pop edi ; restore edi
- inc cx ; adjust count to point back to end of string
- mov [esp],ecx ; new count
- cld ; !!!***!!! important, NEXT won't work unless direction flag set this way
- next
- none_trailing: ; no non-blanks at all
- pop edi ; restore edi
- mov DWORD PTR [esp],FALSE ; zero count
- cld ; !!!***!!! important, NEXT won't work unless direction flag set this way
- next
-
- finame <SLITERAL> ; c-addr1 u Execution: -- c-addr2 u
- ctok NEST ; STRING
- ctok STATEABORT
- ctok ALIGN
- ctok DUP ; -- c-addr1 u u
- ctok HERE ; -- c-addr1 u u here
- ctok TWO_SWAP ; -- u here c-addr1 u
- ctok HERE ; -- u here c-addr1 u here
- ctok PLACE ; -- u here
- ctok DOLIT
- ctok DOSQUOTE ; -- u here xt
- ctok COMPCOMMA
- ctok COMPCOMMA ; -- u
- ctok ONE_PLUS ; -- u' account for count character
- ctok CHARS ; -- chars
- ctok ALLOT ; --
- ctok UNNEST
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell <2 or immedMask>
- db 'S',0,'"',0 ; Interp: "ccc<"> -- c-addr u Compile: "ccc<"> -- Execute: c-addr u
- align 4 ; FILE
- fw_S_QUOTE:
- ctok NEST
- charlit '"' ; -- char
- ctok PARSE ; -- c-addr u
- ctok STATE ; -- c-addr u a-addr
- ctok FETCH ; -- c-addr u flag
- compif s_quote1 ; are we compiling?
- ctok ALIGN ; for good luck -- maybe this should be removed
- ctok HERE ; -- c-addr1 u c-addr2
- ctok DUP ; -- c-addr1 u c-addr2 c-addr2
- ctok TO_R ; -- c-addr1 u c-addr2 R: -- c-addr2
- ctok OVER ; -- c-addr1 u c-addr2 u R: -- c-addr2
- ctok ONE_PLUS ; -- c-addr1 u c-addr2 u' R: -- c-addr2
- ctok CHARS ; -- c-addr1 u c-addr2 chars R: -- c-addr2
- ctok ALLOT ; -- c-addr1 u c-addr2 R: -- c-addr2
- ctok PLACE ; -- R: -- c-addr2
- literal 0
- ctok CCOMMA ; -- null pad
- ctok DOLIT
- ctok DOSQUOTE ; -- xt R: -- c-addr2
- ctok COMPCOMMA ; -- R: -- c-addr2
- ctok R_FROM ; -- c-addr2 R: --
- ctok COMPCOMMA ; --
- ctok EXIT
- s_quote1:
- literal stringBuffer ; -- c-addr1 u c-addr2
- ctok PLACE ; --
- literal stringBuffer ; -- c-addr2
- ctok COUNT ; -- c-addr2 u
- ctok TWO_DUP
- ctok CHARS
- ctok PLUS
- literal 0
- ctok SWAP
- ctok C_STORE ; append null terminator
- ctok UNNEST
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell <2 or immedMask>
- db '.',0,'"',0 ; Interp: -- c-addr u Compile --
- align 4 ; CORE
- fw_DOT_QUOTE:
- ctok NEST
- ctok STATEABORT
- ctok DP
- ctok FETCH ; -- dictionary-pointer
- ctok S_QUOTE ; -- dp S" has stored string and embedded execution engine
- ctok DOLIT
- ctok DODOTQUOTE
- ctok SWAP ; -- xt dp
- ctok CODETODATA
- ctok STORE ; -- overwrite S" exe engine with ." exe engine
- ctok UNNEST
-
- fname <PAD> ; -- c-addr
- ctok DOCONST ; CORE EXT
- dd tickpad
-
- ;--( Number Conversion )
-
- fname <BASE> ; a-addr
- ctok DOCONST ; CORE
- dd var_base
-
- fname <DECIMAL> ; --
- ctok NEST ; CORE
- literal 10
- ctok BASE
- ctok STORE
- ctok UNNEST
-
- fname <HEX> ; --
- ctok NEST ; CORE
- literal 16
- ctok BASE
- ctok STORE
- ctok UNNEST
-
- fname <HLD> ; a-addr
- ctok DOCONST ; Implementation detail
- dd var_hld
-
- fname <HOLD> ; char --
- ctok NEST ; CORE
- literal -1
- ctok CHARS
- ctok HLD
- ctok PL_STORE ; predecrement offset pointer which was set by <#
- ctok HLD
- ctok FETCH
- ctok C_STORE ; store character in numeric format buffer
- ctok UNNEST
-
- ; Is char a digit in base n?
- nname <DIGIT> ; char n1 -- n2 true | char false
- docode ; Not in Standard
- pop edx ; base
- pop eax ; char
- mov ecx,eax ; save copy of char
- sub ax,'0' ; is char >= '0'
- jb not_digit ; if not, jump not_digit
- cmp ax,9 ; is char <= 9
- jbe digit1 ; yes, jump to digit_1
- cmp ax,'A'-'0' ; no, see if it's an alpha number
- jb not_digit ; it ain't, jump away
- sub ax,'A'-'0'-10 ; it is, subtract offset of that portion of char set to make correct digit
- digit1: cmp ax,dx ; now compare resultant number to base
- jnb not_digit ; it ain't a digit if it ain't below the value of the base
- push eax ; it is a digit, push
- push TRUE ; TRUE for success
- next
- not_digit:
- push ecx ; char
- xor eax,eax ; false, failure
- push eax
- next
-
- nname <DPL> ; -- a-addr
- ctok DOCONST ; Not in Standard
- dd var_dpl
-
- nname <NUMBER> ; c-addr1 u1 -- d TRUE | x x FALSE
- ctok NEST ; Not in Standard
- ctok TRUE
- ctok DPL
- ctok STORE ; indicate no dot in number input as default
- ctok OVER ; -- c-a1 u1 c-a1
- ctok C_FETCH ; -- c-a1 u1 char
- charlit '-' ; -- c-a1 u1 char1 char2
- ctok EQUAL ; -- c-a1 u1 flag
- ctok DUP ; -- c-a1 u1 flag flag
- ctok TO_R ; -- c-a1 u1 flag flag R: -- flag save negative flag
- compif number1 ; was there a prepended negative sign?
- ctok ONE_MINUS ; -- c-a1 u1' R: -- flag yes, dec count
- ctok SWAP
- ctok CHAR_PLUS ; -- u1' c-a1' R: -- flag advance address
- ctok SWAP ; -- c-a1' u1' R: -- flag
- number1:
- ctok FALSE
- ctok FALSE ; -- c-a1' u1' ud R: -- flag
- ctok TWO_SWAP ; -- ud c-a1' u1' R: -- flag
- number2:
- ctok TO_NUMBER ; -- ud c-a2 u2 R: -- flag
- ctok QDUP ; -- ud c-a2 [ u2 u2 | 0 ] R: -- flag
- compif number_success ; did number conversion complete leave non-zero count of chars left?
- ctok OVER ; -- ud c-a2 u2 c-a2 R: -- flag
- ctok C_FETCH ; -- ud c-a2 u2 char R: -- flag
- charlit '.' ; -- ud c-a2 u2 char1 char2 R: -- flag
- ctok EQUAL ; -- ud c-a2 u2 flag R: -- flag
- compif number_fail ; was the character which stopped the conversion a "dot"?
- ctok DUP ; -- ud c-a2 u2 u2 R: -- flag
- ctok ONE_MINUS ; -- ud c-a2 u2 u2' R: -- flag
- ctok DPL ; -- ud c-a2 u2 u2' a-addr R: -- flag ; right-justified count to dot-place-marker
- ctok STORE ; -- ud c-a2 u2 R: -- flag
- ctok ONE_MINUS ; -- ud c-a2 u2' R: -- flag
- ctok SWAP ; -- ud u2' c-a2 R: -- flag
- ctok CHAR_PLUS ; -- ud u2' c-a2' R: -- flag
- ctok SWAP ; -- ud c-a2' u2' R: -- flag
- ctok DUP ; -- ud c-a2' u2' R: -- flag
- ctok DOUNTILNOT ; more chars? try it some more! This allows multiple dots in a number ... sounds ok
- dd number2 ; otherwise, we're done if parsing the "dot" exhausted the string
- ctok DROP ; -- ud c-a2' R: -- flag
- compelse number_success
- number_fail: ; -- ud c-a u R: -- flag
- ctok TWO_DROP ; -- ud R: -- flag
- ctok FALSE ; -- ud 0 R: -- flag
- ctok R_FROM ; -- ud 0 flag R: --
- ctok DROP ; -- ud 0
- ctok EXIT ; -- x x 0
- number_success: ; -- ud c-addr R: -- flag
- ctok DROP ; -- ud R: -- flag
- ctok R_FROM ; -- ud flag R: --
- compif number_done ; did we mark this negative?
- ctok DNEGATE ; -- d
- number_done:
- ctok TRUE ; -- d true
- ctok UNNEST
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 7
- db '>',0,'N',0,'U',0,'M',0,'B',0,'E',0,'R',0 ; ud1 c-addr1 u1 -- ud2 c-addr2 u2
- fw_TO_NUMBER:
- ctok NEST
- tonum1: ctok DUP ; BEGIN -- ud1 c-addr1 u1 u1
- compif tonum4 ; WHILE
- ctok SWAP ; -- ud1 u1 c-addr1
- ctok COUNT ; -- ud1 u1 c-addr char
- ctok BASE ; -- ud1 u1 c-addr char a-addr
- ctok FETCH ; -- ud1 u1 c-addr char n
- ctok DIGIT ; -- ud1 u1 c-addr n flag
- compif tonum2 ; if it's a digit
- ctok TO_R ; -- ud1 u1 c-addr R: -- n
- ctok TWO_SWAP ; -- u1 c-addr ud1 R: -- n
- ctok BASE
- ctok FETCH ; -- u1 c-addr ud1 n R: -- n
- ctok UDSTARU ; -- u1 c-addr ud R: -- n
- ctok R_FROM
- literal 0 ; -- u1 c-addr ud "udx" R: --
- ctok D_PLUS ; -- u1 c-addr ud'
- ctok TWO_SWAP ; -- ud' u1 c-addr
- ctok SWAP ; -- ud2 c-addr u1
- compelse tonum3 ; ELSE
- tonum2: ctok DROP ; -- ud2 u2 c-addr
- literal tchar
- ctok MINUS ; -- ud2 u2 c-addr2
- ctok SWAP ; -- ud2 c-addr2 u2
- ctok EXIT ; THEN
- tonum3: ctok ONE_MINUS ; -- ud c-addr u
- compelse tonum1 ; REPEAT
- tonum4: ctok UNNEST ; -- ud2 c-addr2 u2
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 2
- db '<',0,'#',0 ; --
- align 4 ; CORE
- fw_LSHARP:
- ctok NEST
- literal ticknumend
- ctok HLD
- ctok STORE ; set up pointer to numeric output string format buffer
- ctok UNNEST
-
- fnamemanque <#> ; ud1 -- ud2
- fw_SHARP:
- ctok NEST
- ctok BASE
- ctok FETCH
- ctok DUMSLMOD ; -- r ud'
- ctok ROT
- ctok DUP
- literal 10
- ctok LESS ; -- ud' r flag ; is this within the numeric Unicode chars?
- compif sharp1
- ctok DOLIT
- db '0',0,0,0 ; -- ud' r char ; yes, we'll need to add its number to the char '0'
- compelse sharp2
- sharp1: literal 'A'-10 ; -- ud' r char ; no we'll need to add its number to an offset from 'A'
- sharp2: ctok PLUS ; -- ud' char'
- ctok HOLD ; -- ud' ; store char
- ctok UNNEST
-
- fnamemanque <#S> ; ud1 -- ud2
- fw_SHARPS:
- ctok NEST
- sharps:
- ctok SHARP ; -- ud' loop converting chars
- ctok TWO_DUP ; -- ud' ud'
- ctok OR ; -- ud' flag
- ctok DOUNTILNOT ; -- ud' loop until it's 0.0
- dd sharps
- ctok UNNEST
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 2
- db '#',0,'>',0 ; ud -- c-addr u
- align 4 ; CORE
- fw_SHARPR:
- ctok NEST
- ctok TWO_DROP ; -- discard what's left of double which was to be formatted
- ctok HLD
- ctok FETCH ; -- c-addr
- literal ticknumend ; -- c-addr1 c-addr2
- ctok OVER ; -- c-addr1 c-addr2
- ctok MINUS ; -- c-addr1 n
- literal 1
- ctok CHARS ; -- c-addr1 n sizeofchar address diff has to be divided by char size
- ctok SLASH ; -- c-addr u
- ctok UNNEST
-
- ;--( I/O )
-
- fname <CR> ; --
- ctok NEST ; CORE
- literal 0DH
- ctok EMIT
- literal 0AH
- ctok EMIT
- ctok UNNEST
-
- fname <SIGN> ; n --
- ctok NEST ; CORE
- ctok ZEROLT
- compif sign1
- charlit '-'
- ctok HOLD
- sign1: ctok UNNEST
-
- fnamemanque <.> ; n --
- fw_DOT: ctok NEST ; CORE
- ctok PDOT
- ctok TYPE ; --
- ctok BL
- ctok EMIT
- ctok UNNEST
-
- fnamemanque <.R> ; n1 n2 --
- fw_DOT_R:
- ctok NEST ; CORE EXT
- ctok SWAP ; -- n2 n1
- ctok PDOT ; -- n2 c-addr u
- ctok ROT ; -- c-addr u n2
- ctok OVER ; -- c-addr u n2 u
- ctok MINUS ; -- c-addr u1 u2
- literal 0
- ctok MAX ; -- c-addr u1 u2'
- ctok SPACES ; -- c-addr u
- ctok TYPE ; --
- ctok UNNEST
-
- znamemanque <(.)> ; n -- c-addr u
- fw_PDOT:
- ctok NEST
- ctok DUP ; -- n n
- ctok ABS ; -- n _n_
- ctok S_TO_D ; -- n d
- ctok LSHARP ; -- n d
- ctok SHARPS ; -- n d'
- ctok ROT ; -- d' n
- ctok SIGN ; -- d
- ctok SHARPR ; -- c-addr u
- ctok UNNEST
-
- fnamemanque <D.> ; d --
- fw_D_DOT:
- ctok NEST ; CORE
- ctok TUCK ; -- dh d
- ctok DABS ; -- dh _d_
- ctok LSHARP ; -- dh _d_
- ctok SHARPS ; -- dh d'
- ctok ROT ; -- d' dh
- ctok SIGN ; -- d'
- ctok SHARPR ; -- c-addr u
- ctok TYPE ; --
- ctok BL
- ctok EMIT
- ctok UNNEST
-
- fnamemanque <U.> ; u --
- fw_U_DOT: ; CORE
- ctok NEST
- literal 0
- ctok UD_DOT
- ctok UNNEST
-
- nnamemanque <UD.> ; ud --
- fw_UD_DOT: ; Not in Standard
- ctok NEST
- ctok LSHARP
- ctok SHARPS
- ctok SHARPR
- ctok TYPE
- ctok BL
- ctok EMIT
- ctok UNNEST
-
- fnamemanque <U.R> ; u n --
- fw_U_DOT_R: ; Not in Standard
- ctok NEST
- literal 0
- ctok SWAP
- ctok UD_DOT_R
- ctok UNNEST
-
- nnamemanque <UD.R> ; ud n --
- fw_UD_DOT_R: ; Not in Standard
- ctok NEST
- ctok TO_R
- ctok LSHARP
- ctok SHARPS
- ctok SHARPR
- ctok R_FROM
- ctok OVER
- ctok MINUS
- literal 0
- ctok MAX
- ctok SPACES
- ctok TYPE
- ctok BL
- ctok EMIT
- ctok UNNEST
-
- fnamemanque <.S> ; i*x -- i*x
- fw_DOT_S: ; CORE EXT
- ctok NEST
- ctok DEPTH
- literal 0
- ctok MAX
- ctok DUP
- literal 0
- compqdo dot_s1
- dot_s0:
- ctok DUP
- ctok I
- ctok MINUS
- ctok PICK
- ctok U_DOT
- comploop dot_s0
- dot_s1: ctok DROP
- ctok UNNEST
-
- zname <DEBDOTS> ; i*j char -- i*j
- ctok NEST
- ctok EMIT
- ctok SPACE
- ctok DOT_S
- ctok KEY
- ctok DROP
- ctok CR
- ctok UNNEST
-
- fnamemanque <KEY?> ; -- flag
- fw_KEY_Q: ; FACILITY
- docode
- mov DWORD PTR lastError[dp],TRUE ; No windows error code has all bits set
- mov eax,256 ; number of records to try for per Microsoft
- INVOKE PeekConsoleInputW, [dp+stdIn], OFFSET FLAT:inRecArray, eax, OFFSET FLAT:numRead
- and eax,eax ; "C" TRUE is success
- jne keyq1 ; on success, continue further on
- push eax ; push failure
- jmp doLastErr ; on failure, return via set error code routine
- keyq1: mov ecx,[numRead] ; number of input records successfully peeked
- and ecx,ecx
- je keyq_none ; none? fergit it!
- mov eax,OFFSET FLAT:inRecArray
- keyq2: .IF (WORD PTR [eax].INPUT_RECORD.EventType == KEY_EVENT) && \ ; is it a key event?
- (DWORD PTR [eax].INPUT_RECORD.Event.KeyEvent.bKeyDown != 0) && \ ; a press?
- ((WORD PTR [eax].INPUT_RECORD.Event.KeyEvent.uChar.UnicodeChar >= 1BH) || \ ; part of char set?
- (WORD PTR [eax].INPUT_RECORD.Event.KeyEvent.uChar.UnicodeChar == 0DH))
- jmp keyq_found ; if C-language "true", a key is down, we're done
- .ENDIF
- keyq_continue:
- add eax,SIZE INPUT_RECORD
- loop keyq2
- keyq_none: ; nope
- push FALSE
- next
- keyq_found: ; yup
- push TRUE
- next
-
- fname <KEY> ; -- char
- docode ; CORE
- xor ecx,ecx ; clear character holder
- lea eax,[dp+conMode] ; in order to preserve con mode
- INVOKE GetConsoleMode, [dp+stdIn], eax ; let's find out what it is
- and eax,eax ; success is "C" TRUE
- jne key2 ; if GetConsoleMode succeeds, continue
- mov eax,UniNotAChar ; on failure, push invalid char
- push eax
- jmp doLastErr ; return to NEXT via doLastErr
- key2: INVOKE SetConsoleMode, [dp+stdIn], 0 ; set no echo, no line input, no window/mouse/processed
- and eax,eax ; success is "C" TRUE
- jne key3 ; if SetConsoleMode succeeds, continue
- mov eax,UniNotAChar ; on failure, push invalid char
- push eax
- jmp doLastErr ; return to NEXT via doLastErr
- key3: INVOKE ReadConsoleW, [dp+stdIn], OFFSET FLAT:lastReadConW, 1, OFFSET FLAT:numRead, 0 ; get a char
- and eax,eax ; "C" TRUE is success
- je key4 ; on failure, get error code
- mov DWORD PTR lastError[dp],TRUE ; success, return TRUE, no Windows error code has all bits set
- cmp DWORD PTR numRead,0 ; did we get any?
- je key3 ; loop waiting
- xor ecx,ecx ; clear for character
- mov cx,WORD PTR lastReadConW ; retrieve char, ecx ostensibly clear for now
- push ecx ; push to stack
- mov eax,conMode[dp] ; get saved console mode
- INVOKE SetConsoleMode, [dp+stdIn], eax ; restore previous console mode, don't worry about err here
- next
- key4: INVOKE GetLastError ; on this error, don't worry about console mode
- mov lastError[dp],eax ; save error return
- mov eax,UniNotAChar
- push eax
- next
-
- fnamemanque <EKEY?> ; -- flag
- fw_EKEY_Q: ; FACILITY
- docode
- mov DWORD PTR lastError[dp],TRUE ; No windows error code has all bits set
- mov eax,256 ; number of records to try for per Microsoft
- INVOKE PeekConsoleInputW, [dp+stdIn], OFFSET FLAT:inRecArray, eax, OFFSET FLAT:numRead
- and eax,eax ; "C" TRUE is success
- jne ekeyq1 ; on success, continue further on
- push eax ; push failure
- jmp doLastErr ; on failure, return via set error code routine
- ekeyq1: mov ecx,[numRead] ; number of input records successfully peeked
- and ecx,ecx
- je ekeyq_none ; none? fergit it!
- mov eax,OFFSET FLAT:inRecArray
- ekeyq2: cmp WORD PTR [eax].INPUT_RECORD.EventType,KEY_EVENT
- ; loop comparing the EventType field in each struc
- jne ekeyq_continue ; not a KEY_EVENT, loop
- cmp DWORD PTR [eax].INPUT_RECORD.Event.KeyEvent.bKeyDown,0 ; test if we have a key down
- jne ekeyq_found ; if C-language "true", a key is down, we're done
- ekeyq_continue:
- add eax,SIZE INPUT_RECORD
- loop ekeyq2
- ekeyq_none: ; nope
- push FALSE
- next
- ekeyq_found: ; yup
- push TRUE
- next
-
- fname <EKEY> ; -- u
- ctok NEST ; FACILITY EXT
- ekey1: ctok pEKEY ; -- u flag
- compif ekey2
- ctok EXIT
- ekey2: ctok DROP
- compelse ekey1 ; loop until got one
-
- zname <pEKEY> ; -- u flag
- docode
- mov DWORD PTR lastError[dp],TRUE ; No windows error code has all bits set
- lea eax,[dp+conMode] ; in order to preserve con mode
- INVOKE GetConsoleMode, [dp+stdIn], eax ; let's find out what it is
- and eax,eax ; success is "C" TRUE
- jne pekey_setcon ; if GetConsoleMode succeeds, continue
- pekey_setfail:
- push eax
- push eax ; -- u flag
- INVOKE GetLastError
- mov lastError[dp],eax ; save error return
- mov eax,conMode[dp] ; get saved console mode
- INVOKE SetConsoleMode, [dp+stdIn], eax ; restore previous console mode, don't worry about err here
- next
- pekey_setcon:
- INVOKE SetConsoleMode, [dp+stdIn], 0 ; set no echo, no line input, no window/mouse/processed
- and eax,eax ; success is "C" TRUE
- je pekey_setfail ; if couldn't set console mode
- pkey0: INVOKE ReadConsoleInputW, [dp+stdIn], OFFSET FLAT:inRecArray, 1, OFFSET FLAT:numRead
- and eax,eax ; "C" TRUE is success
- jne pekey1 ; on success, continue further on
- push eax ; push failure
- push eax ; -- u flag
- INVOKE GetLastError
- mov lastError[dp],eax ; save error return
- mov eax,conMode[dp] ; get saved console mode
- INVOKE SetConsoleMode, [dp+stdIn], eax ; restore previous console mode, don't worry about err here
- next
- pekey1: mov eax,OFFSET FLAT:inRecArray
- .IF WORD PTR [eax].INPUT_RECORD.EventType != KEY_EVENT
- jmp pekey_none ; it ain't a key event, we don't care
- .ENDIF
- .IF [eax].INPUT_RECORD.Event.KeyEvent.bKeyDown == 0
- jmp pekey_none
- .ENDIF
- mov dx,[eax].INPUT_RECORD.Event.KeyEvent.wVirtualKeyCode
- mov cl,16
- shl edx,cl
- mov dx,[eax].INPUT_RECORD.Event.KeyEvent.uChar.UnicodeChar
- push edx
- push TRUE ; -- u flag
- mov eax,conMode[dp] ; get saved console mode
- INVOKE SetConsoleMode, [dp+stdIn], eax ; restore previous console mode, don't worry about err here
- next
- pekey_none:
- push FALSE
- push FALSE ; -- u flag
- mov eax,conMode[dp] ; get saved console mode
- INVOKE SetConsoleMode, [dp+stdIn], eax ; restore previous console mode, don't worry about err here
- next
-
- fname <TYPE> ; c-addr u --
- dd ftype
- ftype: pop eax
- pop edx
- lea edx,[edx][dp]
- INVOKE WriteConsoleW, [dp+stdOut], edx, eax, OFFSET FLAT:numWritten, 0
- jmp SHORT doLastErr ; returns to NEXT via doLastErr
-
- fname <EMIT>
- dd emit
- emit: pop DWORD PTR [dp+outChar]
- lea eax,[dp+outChar]
- INVOKE WriteConsoleW, [dp+stdOut], eax, 1, OFFSET FLAT:numWritten,0
- jmp SHORT doLastErr ; returns to NEXT via doLastErr
-
- ; Serve these I/O words to set our local LastError variable either TRUE for success or to return from LastError.
- doLastErr:
- and eax,eax ; "C" TRUE is success
- je dLE1 ; on failure, get error code
- mov DWORD PTR lastError[dp],TRUE ; success, return TRUE
- next ; No Windows error code has all bits set
- dLE1: INVOKE GetLastError
- mov lastError[dp],eax ; save error return
- next
-
- ; Calls factor (ACCEPT), then handles trailing CR/LF pair.
- fname <ACCEPT> ; c-addr +n1 -- +n2
- ctok NEST
- ctok OVER
- ctok SWAP ; -- c-a c-a +n1
- ctok PACCEPT ; -- c-a +n2'
- ctok DUP ; -- c-a +n2 +n2
- compif accept9
- ctok TWO_DUP ; -- c-a +n2 c-a +n2
- ctok CHARS
- ctok PLUS ; -- c-a1 +n2 c-a2
- literal 2
- literal 0
- compdo accept4
- accept3:
- literal 1 ; -- c-a1 +n2 c-a2 1
- ctok CHARS
- ctok MINUS ; -- c-a1 +n2 c-a2'
- ctok DUP
- ctok C_FETCH ; -- c-a1 +n2 c-a2' char
- ctok DUP
- literal 0aH ; -- c-a1 +n2 c-a2' char char 0aH
- ctok EQUAL ; -- c-a1 +n2 c-a2' char flag
- ctok SWAP ; -- c-a1 +n2 c-a2' flag char
- literal 0dH ; -- c-a1 +n2 c-a2' flag char 0dH
- ctok EQUAL ; -- c-a1 +n2 c-a2' flag1 flag2
- ctok OR ; -- c-a1 +n2 c-a2' flag
- compif accept8
- ctok BL ; -- c-a1 +n2 c-a2' 020H
- ctok OVER ; -- c-a1 +n2 c-a2' 020H c-a2'
- ctok C_STORE ; -- c-a1 +n2 c-a2'
- accept8:
- comploop accept3
- accept4: ; -- c-a1 +n2 c-a2'
- ctok DROP ; -- c-a1 +n2
- accept9:
- ctok NIP ; -- +n2
- accept_done:
- ctok UNNEST
-
- znamemanque <(ACCEPT)> ; c-addr +n1 -- +n2
- fw_PACCEPT: ; implementation
- docode
- pop eax
- and eax,eax ; positive count?
- jnle paccept1 ; if yes, continue further on
- xor eax,eax ; make a zero
- mov [esp],eax ; +n2 = 0 on error
- paccept1:
- push eax ; preserve count
- lea eax,[dp+conMode] ; in order to preserve con mode
- INVOKE GetConsoleMode, [dp+stdIn], eax ; let's find out what it is
- and eax,eax ; success is "C" TRUE
- jne paccept2 ; if GetConsoleMode succeeds, continue
- pop eax ; discard count
- xor eax,eax ; make a zero
- mov [esp],eax ; n2 = 0 on error
- jmp doLastErr ; return to NEXT via doLastErr
- paccept2:
- INVOKE SetConsoleMode, [dp+stdIn], ENABLE_ECHO_INPUT OR ENABLE_LINE_INPUT OR ENABLE_PROCESSED_INPUT
- ; set echo, line input, processed handling
- and eax,eax ; success is "C" TRUE
- jne paccept3 ; if SetConsoleMode succeeds, continue
- pop eax ; discard count
- xor eax,eax ; make a zero
- mov [esp],eax ; n2 = 0 on error
- jmp doLastErr ; return to NEXT via doLastErr
- paccept3:
- pop eax ; count
- pop edx ; destination
- add edx,dp ; abs address of destination
- INVOKE ReadConsoleW, [dp+stdIn], edx, eax, OFFSET FLAT:numRead,0 ; get a line of input
- and eax,eax ; "C" TRUE is success
- jne paccept4 ; on success, continue elsewhere
- push eax
- jmp doLastErr ; failure, get error code
- paccept4:
- mov DWORD PTR lastError[dp],TRUE ; success, return TRUE, no Windows error code has all bits set
- mov eax,DWORD PTR numRead ; how many did we get?
- push eax ; this is: -- +n2
- mov eax,conMode[dp] ; get saved console mode
- INVOKE SetConsoleMode, [dp+stdIn], eax ; restore previous console mode, don't worry about err here
- next
-
- ;--( Data Space and the Dictionary )
-
- zname <UNFOUND> ; --
- ctok NEST ; Implementation
- literal -13
- ctok THROW
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 1
- db "'",0 ; -- xt | abort
- align 4 ; CORE
- fw_TICK:
- ctok NEST
- ctok BL
- ctok WORD
- ctok FIND
- ctok ZEROEQ
- compif tick1
- ctok UNFOUND
- tick1: ctok UNNEST
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell <3 or immedMask>
- db '[',0,"'",0,']',0 ; -- | abort
- align 4 ; CORE
- fw_BRACKETTICK:
- ctok NEST
- ctok STATEABORT
- ctok TICK
- ctok LITERAL
- ctok UNNEST
-
- fname <ALIGN> ; --
- ctok NEST ; CORE
- literal cell ; -- 4
- ctok HERE ; -- 4 addr
- literal cell-1 ; -- 4 addr 3
- ctok AND ; -- 4 xx
- ctok DUP ; -- 4 xx xx
- compif align1 ; -- 4 xx "extra bits" indicating cell alignment?
- ctok MINUS ; -- n address now aligned, but a cell short
- ctok ALLOT ; -- now it's ok
- ctok EXIT
- align1: ctok TWO_DROP ; 4 xx --
- ctok UNNEST
-
- fname <ALIGNED> ; addr -- a-addr
- ctok NEST ; CORE
- ctok DUP ; -- a a
- literal cell-1 ; -- a a n
- ctok AND ; -- a x
- ctok DUP ; -- a x x
- compif aligned1 ; -- a x "extra bits" indicating cell alignment?
- ctok MINUS ; -- a-a' address now aligned, but a cell short
- literal cell ; -- a-a' n
- ctok PLUS ; -- a-a
- ctok EXIT
- aligned1: ; -- a-a x no "extra bits"
- ctok DROP ; -- a-a
- ctok UNNEST
-
- fname <ALLOT> ; n --
- dd allot ; CORE
- allot: pop eax
- add datap[dp],eax
- next
-
- fnamemanque <CELL+> ; a-addr1 -- a-addr2
- fw_CELL_PLUS: ; CORE
- dd cell_plus
- cell_plus:
- add DWORD PTR [esp],cell
- next
-
- fname <CELLS> ; n1 -- n2
- ctok NEST ; CORE
- literal cell
- ctok STAR
- ctok UNNEST
-
- fnamemanque <FORTH-WORDLIST> ; -- wid
- fw_FWORDLIST: ; SEARCH
- ctok DOKWORDLIST
- dd flinkp ; pointer to data address of of last word added to list
- dd 0 ; token of next wordlist in link
-
- fnamemanque <INTERNALS-WORDLIST> ; -- wid
- fw_ZWORDLIST: ; Implementation
- ctok DOKWORDLIST
- dd zlinkp ; pointer to data address of of last word added to list
- ctok FWORDLIST ; token of next wordlist in link
-
- fnamemanque <NONSTANDARD-WORDLIST> ; -- wid
- fw_NWORDLIST: ; Implementation
- ctok DOKWORDLIST
- dd nlinkp ; pointer to data address of of last word added to list
- ctok ZWORDLIST ; token of next wordlist in link
-
- fnamemanque <SYSTEM-WORDLIST> ; -- wid
- fw_SWORDLIST: ; Implementation
- ctok DOKWORDLIST
- dd slinkp ; pointer to data address of of last word added to list
- ctok NWORDLIST ; token of next wordlist in link
-
- fname <FORTH> ; --
- ctok NEST ; SEARCH EXT
- ctok GET_ORDER
- ctok QDUP
- compif forth1
- ctok NIP
- ctok FWORDLIST
- ctok SWAP
- ctok SET_ORDER
- ctok EXIT
- forth1: ctok FWORDLIST
- literal 1
- ctok SET_ORDER
- ctok UNNEST
-
- fnamemanque <SET-CURRENT> ; wid --
- fw_SET_CURRENT: ; SEARCH
- docode
- pop DWORD PTR current[dp] ; store wid to the current compilation wordlist variable
- next
-
- fnamemanque <GET-CURRENT> ; -- wid
- fw_GET_CURRENT: ; SEARCH
- dd get_current
- get_current:
- push DWORD PTR current[dp]
- next
-
- fnamemanque <SET-ORDER> ; wid1 .. widn n --
- fw_SET_ORDER: ; SEARCH
- ctok NEST
- ctok DUP
- literal searchOrderSize
- ctok GREATER ; no bogus indices, please!
- literal -49 ; search order overflow THROW
- ctok AND
- ctok THROW
- ctok DUP
- ctok ZEROLT
- literal -50 ; search order underflow THROW
- ctok AND
- ctok THROW
- literal searchOrderSize
- literal 0
- compqdo set_order1
- set_order0: ; loop clearing search order
- ctok FALSE
- literal searchOrder
- ctok I
- ctok CELLS
- ctok PLUS
- ctok STORE
- comploop set_order0
- set_order1:
- literal 0
- compqdo set_order3 ; ?DO since 0 is a legit argument
- set_order2: ; loop filling cells, (if any
- literal searchOrder
- ctok I
- ctok CELLS
- ctok PLUS
- ctok STORE
- comploop set_order2
- set_order3:
- ctok UNNEST
-
- fname <WORDLIST> ; -- wid
- ctok NEST ; SEARCH
- literal unnamedHdr
- ctok ABSTODATA
- ctok COUNT
- ctok NAMEWORDLIST
- ctok UNNEST
-
- fname <MARKER> ; "<spaces>name" --
- ctok NEST ; CORE EXT
- literal wllink
- ctok FETCH ; -- xt ,wordlist link contains an xt
- literal 0
- literal 0 ; -- xt 0 0 ,mark end of wordlists
- literal 2
- ctok PICK ; -- xt 0 0 xt ,get a copy of wordlist link
- marker0:
- ctok DUP ; -- xt0 0 0 xt xt ,check for zero
- compif marker1
- ctok TOKENTODATA ; -- xt0 0 0 a-addr
- ctok CELL_PLUS ; -- xt0 0 0 a-addr' ,now we point to pointer to list pointer
- ctok DUP ; -- xt0 0 0 a-addr' a-addr'
- ctok FETCH ; -- xt0 0 0 a-addr' a-addr'' ,data address holds last word's link for this wid
- ctok DUP ; -- xt0 0 0 a-addr' a-addr'' a-addr''
- ctok FETCH ; -- xt0 0 0 a-addr' linkp ,pointer to last word in that wordlist
- ctok ROT ; -- xt0 0 0 a-addr'' linkp a-addr'
- ctok CELL_PLUS ; -- xt0 0 0 a-addr'' linkp a-addr''' move to back link to previous wordlist
- ctok FETCH ; -- xt0 0 0 a-addr'' linkp xt2
- compelse marker0 ; loop and keep piling them up
- marker1: ; we get here when we run out of wids
- ctok DROP ; -- xt0 0 0 a-addrn linkpn ... a-addrz linkpz
- ctok DP ; -- .. a-addrz linkpz a-addr
- ctok FETCH ; -- .. a-addrz linkpz abs-addr
- literal last
- ctok FETCH ; -- .. a-addrz linkpz abs-addr a-addr ,"last" pointer
- ctok ALIGN ; for good luck
- ctok CREATE ; now create this forgettable dictionary entry
- ctok DOLIT
- ctok DOMARKER ; runtime engine for MARKER
- ctok MAKEDOES ; "does" the new word to DOMARKER
- ctok COMMA ; save "last" pointer
- ctok COMMA ; save dictionary pointer
- marker2:
- ctok TWO_DUP ; -- .. a-addrz linkpz
- ctok COMMA ; a last-word pointer
- ctok COMMA ; a wid's data body address where it stores its last word pointer
- ctok D_ZEROEQ ; is this a zero-zero?
- ctok INVERT
- compif marker3 ; if not, we continue
- compelse marker2 ; this is the continuing
- marker3:
- ctok COMMA ; and there's the wordlist pointer
- ctok UNNEST
-
- zname <DOMARKER> ; data-address --
- ctok NEST
- ctok DUP ; -- a-addr a-addr
- literal datap ; -- a-addr1 a-addr1 a-addr2
- ctok STORE ; -- a-addr
- ctok DUP ; -- a-addr a-addr
- ctok FETCH ; -- a-addr linkp
- literal last ; -- a-addr1 linkp a-addr2 ,restore "last" pointer
- ctok STORE ; -- a-addr
- ctok CELL_PLUS ; -- a-addr' ,go to next cell
- ctok DUP ; -- a-addr a-addr
- ctok FETCH ; -- a-addr dp
- ctok DP ; -- a-addr1 dp a-addr2 ,restore dictionary pointer
- ctok STORE ; -- a-addr
- ctok CELL_PLUS ; -- a-addr'
- domarker0:
- ctok DUP ; -- a-addr a-addr ,here we go for the wordlists
- ctok TWO_FETCH ; -- a-addr wid-body last-word
- ctok TWO_DUP ; -- a-addr wid-body last-word wid last-word
- ctok OR ; -- a-addr wid-body last-word flag
- compif domarker1 ; we're done if it's zero-zero
- ctok SWAP ; -- a-addr last-word wid-body
- ctok STORE ; -- a-addr ,restore a wordlist's last pointer
- ctok CELL_PLUS ; -- ''
- ctok CELL_PLUS ; -- a-addr''' ,our next fetch will be two cells ahead
- compelse domarker0 ; and do it again
- domarker1: ; we're done restoring wids
- ctok TWO_DROP ; -- a-addr ,we didn't use the last (null) pair
- ctok CELL_PLUS ; -- a-addr'
- ctok CELL_PLUS ; -- a-addr' (past the last NULL wordlist pair we used to mark end)
- ctok FETCH ; -- wid , get the wordlist link
- literal wllink ; -- wid a-addr
- ctok STORE ; -- we're done
- ctok UNNEST
-
- nname <NAMEWORDLIST> ; c-addr u -- wid
- ctok NEST
- ctok HEADER ; make (possibly headerless) header
- ctok LINKIT ; ... and link it in current wordlist
- ctok DP
- ctok FETCH ; save dictionary pointer to convert to token for this wordlist
- ctok DOLIT
- ctok DOKWORDLIST ; embed wordlist engine
- ctok COMPCOMMA
- ctok HERE ; pointer to the link pointer for this wordlist
- ctok COMPCOMMA
- literal 1
- ctok CELLS
- ctok ALLOT ; allot storage for that link pointer
- literal wllink
- ctok FETCH
- ctok COMPCOMMA ; compile back pointer to previous wordlist
- ctok MAKETOKEN ; convert that dictionary pointer sitting on the stack to a user token
- ctok DUP ; save copy
- literal wllink
- ctok STORE ; store that token in the wordlist link pointer as last wordlist added
- ctok EXECUTE ; return own WID
- ctok UNNEST
-
- nname <WORDLISTS> ; --
- ctok NEST ; Not in Standard
- ctok CR
- literal wlHdr
- ctok ABSTODATA
- ctok COUNT
- ctok TYPE
- literal wllink
- wordlists1:
- ctok FETCH ; -- xt, token of wordlist
- ctok QDUP ; -- xt xt|-
- compif wordlists2 ; -- xt
- ctok TOKENTODATA ; -- a-addr
- ctok DATATOABS ; -- abs-addr, convert for printing wid as it is
- ctok CELL_PLUS ; -- abs-addr', the wid is the abs addr of the cell past cfa
- ctok DUP ; -- abs abs
- ctok DOT_WID ; -- abs
- ctok SPACE
- ctok CELL_PLUS ; -- abs-addr of wordlist link pointer
- ctok ABSTODATA ; -- a-addr, read for next go-round
- compelse wordlists1
- wordlists2: ; --
- ctok CR
- ctok UNNEST
-
- fname <WORDS> ; --
- ctok NEST ; TOOLKIT
- ctok CR
- literal searchOrder
- ctok FETCH ; -- wid
- ctok ABSTODATA ; -- addr of pointer to thread
- ctok FETCH ; -- addr of thread
- words1:
- ctok FETCH ; -- link-token
- ctok QDUP ; is it null
- compif words5 ; if null, we're done
- ctok DUP ; -- lt lt
- ctok DOT_WORD ; -- lt
- ctok TOKENTODATA ; -- a-addr
- ctok KEY_Q ; -- a-addr flag, has user punched for quick exit or pause?
- compif words1 ; -- a-addr, if no keypress, loop again
- words2: ; -- a-addr, here's where we get if there was a keypress
- ctok KEY ; -- a-addr char
- ctok BL ; -- a-addr c1 c2
- ctok EQUAL ; -- a-addr flag, was it a space bar?
- compif words4 ; -- a-addr, if not, it's a quit.
- words3: ; -- a-addr, it was a space bar
- ctok KEY ; -- a-addr char, we waited for user to punch again
- ctok BL ; -- a-addr c1 c2
- ctok NEQUAL ; -- a-addr flag, if it's a space bar, resume
- compif words1 ; -- a-addr, but if it's anything else, quit
- words4: ; -- a-addr, we fall thru here if key was NEQUAL to a space bar
- ctok DROP ; -- , discard address, quick exit
- words5:
- ctok CR ; -- , new line
- ctok UNNEST
-
- fnamemanque <GET-ORDER> ; ( -- wid1 .. widn n)
- fw_GET_ORDER: ; SEARCH
- ctok NEST
- literal 0 ; holder, -- 0
- literal searchOrderSize ; -- 0 n
- literal 0 ; -- 0 n 0
- compqdo get_order2
- get_order0: ; -- 0
- literal searchOrder ; -- 0 a-addr
- ctok I ; -- 0 a-addr n
- ctok CELLS ; -- 0 a-addr n'
- ctok PLUS ; -- 0 a-addr'
- ctok FETCH ; -- 0 wid
- ctok ZEROEQ ; -- 0 flag
- compif get_order1
- ctok LEAVE ; -- 0
- get_order1:
- ctok ONE_PLUS ; -- 0+1
- comploop get_order0
- get_order2:
- ctok DUP ; -- index index
- literal 0 ; -- index index 0
- compqdo get_order4
- get_order3: ; -- index
- ctok DUP ; -- index index
- ctok ONE_MINUS ; -- index index'
- ctok CELLS ; -- index n
- literal searchOrder ; -- index n a-addr
- ctok PLUS ; -- index a-addr'(last cell with a valid wid in it)
- ctok I
- ctok CELLS
- ctok MINUS ; -- index a-addr''
- ctok FETCH ; -- index wid
- ctok SWAP ; -- wid index
- comploop get_order3
- get_order4:
- ctok UNNEST
-
- fname <ORDER> ; --
- ctok NEST ; SEARCH EXT
- ctok CR
- literal orderMsg0
- ctok ABSTODATA
- literal orderMsg0Len
- ctok TYPE ; -- display text
- ctok GET_ORDER
- literal 0
- compqdo order1
- order0: ctok DOT_WID ; -- print each wid and its name
- comploop order0
- order1: ctok CR
- ctok CR
- literal orderMsg1
- ctok ABSTODATA
- literal orderMsg1Len
- ctok TYPE ; -- display text
- ctok GET_CURRENT
- ctok QDUP
- compif order2
- ctok DOT_WID ; -- print each wid
- order2: ctok CR
- ctok UNNEST
-
- nnamemanque <.NAME> ; c-addr --
- fw_DOT_NAME: ; Implementation
- ctok NEST
- ctok COUNT
- literal allNameMasks
- ctok INVERT
- ctok AND
- ctok TWO_DUP
- literal unnamedHdr
- ctok ABSTODATA
- ctok COUNT
- ctok COMPARE
- ctok ZERONE
- compif dot_name1
- ctok TYPE
- ctok SPACE
- compelse dot_name2
- dot_name1:
- ctok TWO_DROP
- dot_name2:
- ctok UNNEST
-
- nnamemanque <.WID> ; wid --
- fw_DOT_WID: ; Implementation
- ctok NEST
- ctok CR ; one per line
- ctok BASE ; get and save base
- ctok FETCH
- ctok TO_R ; -- wid R: -- base
- ctok HEX ; switch to hex
- ctok DUP ; -- wid wid R: -- base
- literal 8
- ctok U_DOT_R ; -- wid R: -- base
- ; print wid in hex, right justified
- literal widMsg ; -- wid abs-addr R: -- base
- ctok ABSTODATA ; data address
- ctok COUNT
- ctok TYPE ; display it
- ctok SPACE ; -- wid R: -- base
- ctok ABSTODATA ; -- a-addr R: -- base
- literal -1
- ctok CELLS
- ctok PLUS ; -- a-addr of code field R: -- base
- ctok EXETONAME ; convert to name
- ctok DOT_NAME ; print it if it's got one
- ctok R_FROM ; -- base R: --
- ctok BASE ; -- base a-addr R: --
- ctok STORE ; -- ,restore base
- ctok UNNEST
-
- znamemanque <.WORD> ; link-token --
- fw_DOT_WORD: ; Implementation
- ctok NEST
- ctok TOKENTODATA
- ctok LINKTONAME
- ctok DOT_NAME
- ctok UNNEST
-
- fname <ALSO> ; --
- ctok NEST ; SEARCH EXT
- ctok GET_ORDER
- ctok OVER
- ctok SWAP
- ctok ONE_PLUS
- ctok SET_ORDER
- ctok UNNEST
-
- fname <PREVIOUS> ; --
- ctok NEST ; SEARCH EXT
- ctok GET_ORDER
- ctok DUP
- literal 2
- ctok LESS
- literal -50
- ctok AND
- ctok THROW ; search order underflow THROW
- ctok NIP
- ctok ONE_MINUS
- ctok SET_ORDER
- ctok UNNEST
-
- fname <ONLY> ; --
- ctok NEST ; SEARCH EXT
- ctok FWORDLIST
- literal 1
- ctok SET_ORDER
- ctok UNNEST
-
- fname <DEFINITIONS> ; --
- ctok NEST ; SEARCH EXT
- literal searchOrder
- ctok FETCH
- ctok SET_CURRENT
- ctok UNNEST
-
- fnamemanque <SEARCH-WORDLIST> ; c-addr u wid -- 0 | xt 1 | xt -1)
- fw_SEARCH_WL: ; SEARCH
- ctok NEST
- ctok ABSTODATA ; -- a-addr, of pointer to data-address
- ctok FETCH ; -- a-addr, data location of last link
- ctok FETCH ; -- ltok, last link in the wordlist
- search_wl0:
- ctok DUP ; is link to zero (end of list)
- compif search_wl_fail ; No, it's a real link
- ctok TO_R ; save copy of ltoken
- ctok TWO_DUP ; -- c-a u c-a u R: -- ltoken
- ctok R_FETCH ; -- c-a u c-a u ltoken R: -- ltoken
- ctok TOKENTODATA ; -- c-a u c-a u a-a R: -- ltoken
- ctok LINKTONAME ; -- c-a1 u c-a1 u c-a2 R: -- ltoken
- ctok DUP
- ctok TO_R ; -- c-a1 u c-a1 u c-a2 R: -- ltoken name-address
- ctok COUNT ; -- c-a1 u1 c-a1 u1 c-a2 u2+mask
- literal allNameMasks ; unmask name count byte
- ctok INVERT
- ctok AND
- ctok COMPARE ; -- c-a1 u1 0|1|-1 R: -- ltoken name-address
- ctok ZEROEQ ; -- c-a1 u1 flag R: -- ltoken name-address
- compif search_wl4 ; Zero? We found it
- ctok TWO_DROP ; -- R: -- ltoken name-address
- ctok R_FROM ; -- name-address R: -- ltoken
- ctok C_FETCH ; -- count-word+mask R: -- ltoken
- literal immedMask
- ctok AND ; -- bit R: -- ltoken
- compif search_wl1
- literal 1 ; -- 1 R: -- ltoken
- compelse search_wl2
- search_wl1: ; -- -1 R: -- ltoken
- literal -1
- search_wl2:
- ctok R_FROM ; -- n ltoken
- ctok DUP ; -- n ltoken ltoken
- ctok TOKENTODATA ; -- n ltoken a-addr(link)
- ctok LINKTOEXE ; -- n ltoken a-addr'
- ctok DATATOABS ; -- n ltoken abs-addr
- ctok SWAP ; -- n a-addr' ltoken
- ctok USERTOKENQ ; -- n a-addr' flag
- compif search_wl3 ; -- is this in user dictionary?
- ctok ABSTOCODE ; yes, convert to code token
- ctok MAKETOKEN ; -- n xt
- search_wl3: ; -- no, abs address is valid xt for kernel words
- ctok SWAP ; -- xt 1|-1
- ctok EXIT
- search_wl4: ; didn't match, -- c-a1 u1 R: -- ltoken name-address
- ctok R_FROM
- ctok DROP ; -- c-a1 u1 R: -- ltoken
- ctok R_FROM ; -- c-a1 u1 ltoken R: --
- ctok TOKENTODATA ; -- c-a u a-addr
- ctok FETCH ; -- c-a u next-link-tok
- compelse search_wl0 ; try again
- search_wl_fail: ; ran out of links, -- c-a u ltoken
- ctok DROP
- ctok TWO_DROP ; --
- ctok FALSE ; -- 0
- ctok UNNEST
-
- fname <HERE> ; -- addr
- dd here ; execution engine
- here: push [dp+datap] ; CORE
- next
-
- ; Convert token such as link pointer or execution token to data-relative address
- zname <TOKENTODATA> ; linkt|xt -- a-addr
- ctok NEST ; Implementation
- ctok DUP
- ctok USERTOKENQ
- compif t_to_data1
- ctok DETOKEN
- ctok CODETODATA
- ctok EXIT
- t_to_data1:
- ctok ABSTODATA
- ctok UNNEST
-
- ; All these convert from one data-relative address to another. LINK is the link address. EXE is the address
- ; which is represented by the execution token for the word. NAME is the count word address at the head of
- ; the name field, not the FFFF word before it.
-
- zname <EXETOLINK> ; a-addr1 -- a-addr2
- ctok NEST ; Implementation
- ctok EXETONAME
- ctok NAMETOLINK
- ctok UNNEST
-
- zname <LINKTOEXE> ; a-addr1 -- a-addr2
- ctok NEST ; Implementation
- ctok LINKTONAME
- ctok NAMETOEXE
- ctok UNNEST
-
- zname <NAMETOLINK> ; c-addr -- a-addr
- ctok NEST ; Implementation
- literal 1
- ctok CHARS
- ctok MINUS ; back past the FFFF marker word
- literal 1
- ctok CELLS
- ctok MINUS ; back to head of link field
- ctok UNNEST
-
- zname <LINKTONAME> ; a-addr -- c-addr
- ctok NEST ; Implementation
- literal 1
- ctok CELLS
- ctok PLUS ; past link field
- literal 1
- ctok CHARS
- ctok PLUS ; past the FFFF marker word
- ctok UNNEST
-
- zname <NAMETOEXE> ; c-addr -- a-addr
- ctok NEST
- ctok COUNT
- literal allNameMasks
- ctok INVERT
- ctok AND ; mask out all "funny" bits in count word
- ctok CHARS
- ctok PLUS
- ctok ALIGNED
- ctok UNNEST
-
- zname <EXETONAME> ; a-addr -- c-addr
- ctok NEST
- exetoname1:
- literal 1
- ctok CHARS
- ctok MINUS
- ctok DUP
- ctok C_FETCH
- literal UniNotAChar
- ctok EQUAL
- compuntil exetoname1
- ctok CHAR_PLUS
- ctok UNNEST
-
- ;--( Interpreter )
-
- fname <BLK> ; -- a-addr
- ctok DOCONST ; CORE
- dd var_blk
-
-
- fname <FIND> ; ( c-addr -- c-addr 0 | xt 1 | xt -1 )
- ctok NEST ; CORE
- ctok DUP ; -- $addr
- ctok C_FETCH ; -- $addr u
- compif _4find ; IF the count is non-zero
- literal searchOrder ; -- $addr addr
- literal cell ; -- $addr addr n
- ctok MINUS ; back up to one cell before beginning of search order array
- ctok SWAP ; ptr-to-wid $addr
- ctok FALSE ; ptr-to-wid $addr 0(place holder for DROP of SEARCH-WORDLIST result in loop)
- ctok FALSE ; ptr-to-wid $addr 0(place holder for DROP of DUPed flag SEARCH-WORDLIST in loop)
- literal searchOrderSize ; number of vocabularies in search order
- literal 0
- compdo _3find ; loop until success or run out of search order
- _0find: ; -- ptr-to-wid $addr 0 0
- ctok TWO_DROP ; -- ptr-to-wid $addr
- literal cell ; -- ptr-to-wid $addr n
- ctok ROT ; -- $addr n ptr-to-wid
- ctok PLUS ; -- ptr-to-wid $addr
- ctok SWAP ; -- ptw $addr
- ctok OVER ; -- ptr-to-wid $addr ptr-to-wid
- ctok FETCH ; -- ptw $addr wid|0
- ctok QDUP ; we may have reached end of search order
- compif _1find ; -- ptw $addr wid ,valid vocabulary pointer
- ctok OVER ; -- ptw $addr wid $addr
- ctok COUNT ; -- ptw $addr wid c-addr u
- ctok ROT ; -- ptw $addr c-addr u wid
- ctok SEARCH_WL ; -- ptw $a1 [[ 0 ]|[ exetok [ -1|1 ]]]
- ctok DUP ; -- ptw $a1 [[ 0 0 ]|[ exetok [ -1|1 ] [-1|1]]]
- ctok ZEROEQ
- compif yfind
- ctok DUP ; -- ptw $a1 x1 x2
- yfind: compelse _2find ; NULL in CONTEXT at this entry
- _1find: ; -- ptw $addr ,invalid wid ptr, end of order
- ctok NIP ; -- $addr
- ctok FALSE ; -- $addr 0
- ctok UNLOOP ; -- $addr 0
- ctok EXIT ; -- c-addr 0
- _2find: ; -- ptw $addr x1 x2
- ctok DUP ; -- ptw $addr x1 x2 x2
- compif xfind ; -- ptw $addr x [-1|0|1]
- ctok LEAVE ; -- ptw $a1 x x
- xfind: comploop _0find
- _3find: ; -- ptw $a1 xt flag1
- ctok ROT
- ctok DROP ; -- ptw xt flag
- ctok ROT
- ctok DROP ; -- xt flag
- ctok EXIT ; -- xt flag
- _4find: ; -- $addr the string was null
- ctok TRUE
- literal endq ; var that indicates end of input
- ctok STORE
- ctok FALSE ; -- c-addr 0
- ctok UNNEST
-
- nnamemanque <?STACK> ; i*j -- i*j | -
- fw_QSTACK:
- ctok NEST ; implementation
- ctok SP0
- ctok FETCH ; original stack pointer
- ctok SP_FETCH ; current stack pointer
- literal cell
- ctok PLUS ; adjusted for presence of orig. stack ptr. on stack
- ctok U_LESS ; has stack underflowed?
- compif qstack1
- literal -4 ; Stack Underflow Throw
- ctok THROW
- qstack1:
- ctok UNNEST ; no, continue
-
- zname <INTERPRET> ; i*x -- j*x
- ctok NEST ; Not in Standard
- _0inter: ; Begin
- ctok QSTACK ; --
- ctok BL
- ctok WORD
- ctok FIND ; -- [ 'word 0 ] | [ cfa 1|-1 ]
- ctok QDUP ; -- [ 'word 0 ] | [ cfa 1|-1 1|-1]
- compif _1inter ; -- cfa 1|-1
- ctok STATE
- ctok FETCH ; -- cfa 1|-1 flag
- compif _9inter ; compiling
- ctok ZEROLT ; non-immediate?
- compif _8inter ; yes, compile it
- ctok COMPCOMMA ; --
- compelse _0inter ; --
- _8inter:
- ctok EXECUTE ; --
- compelse _0inter ; --
- _9inter:
- ctok DROP ; -- cfa ,interpreting
- ctok EXECUTE ; -- ,execute found word
- literal endq
- ctok FETCH ; -- t|f ,see if input stream exhausted
- compif _0inter ; -- loop if not exhausted
- ctok EXIT ; -- ,exhausted? exit INTERPRET
- _1inter:
- literal endq ; input stream exhausted?
- ctok FETCH ; -- c-addr flag
- compif _5inter ; if yes we're done, else we might be looking at a number
- ctok DROP ; discard c-addr
- ctok EXIT ; exit INTERPRET
- _5inter:
- ctok COUNT ; -- c-addr1 u1
- ctok NUMBER ; -- d flag
- ctok ZEROEQ ; -- d t|f
- compif _zinter ; wasn't a number in current base, fail
- ctok UNFOUND ; show offending lexical item with "?"
- _zinter:
- ctok DPL ; -- d a-addr check for double precision
- ctok FETCH ; -- d [ n | -1 ]
- ctok TRUE ; -- d [ n | -1 ] TRUE
- ctok EQUAL ; -- d t|f
- compif _6inter ; -- ud2
- ctok DROP ; -- u ,drop hi-order if not double precis
- ctok STATE ; -- u addr
- ctok FETCH ; -- u flag
- compif _2inter ; -- u
- ctok LITERAL ; --
- compelse _2inter ; -- u
- _6inter:
- ctok STATE ; -- ud2 addr
- ctok FETCH ; -- ud2 flag
- compif _2inter ; -- ud2
- ctok TWO_LITERAL ; --
- _2inter: ; Then
- literal endq
- ctok FETCH ; -- flag
- compuntil _0inter ; Until
- ctok UNNEST
-
- fname <EVALUATE> ; i*x c-addr u -- j*x
- ctok NEST
- ctok BLK ; Save input on return stack
- ctok FETCH
- ctok TO_R ; -- i*x c-addr u R: -- BLK
- ctok TIB
- ctok TO_R ; -- i*x c-addr u R: -- BLK TIB
- ctok NUMTIB
- ctok FETCH
- ctok TO_R ; -- i*x c-addr u R: -- BLK TIB #TIB
- ctok TO_IN
- ctok FETCH
- ctok TO_R ; -- i*x c-addr u R: -- BLK TIB #TIB >IN
- ctok SOURCE_ID
- ctok FETCH
- ctok TO_R ; -- i*x c-addr u R: -- BLK TIB #TIB >IN SID
- literal endq
- ctok FETCH
- ctok TO_R ; -- i*x c-addr u R: -- BLK TIB #TIB >IN SID endq
- ctok FALSE
- literal endq
- ctok STORE ; -- i*x c-addr u R: -- BLK TIB #TIB >IN SID endq
- ctok NUMTIB
- ctok STORE ; -- i*x c-addr R: -- BLK TIB #TIB >IN SID endq
- ctok TICK_TIB
- ctok STORE ; -- i*x R: -- BLK TIB #TIB >IN SID endq
- literal -1
- ctok SOURCE_ID
- ctok STORE ; -- i*x c-addr u R: -- BLK TIB #TIB >IN SOURCE-ID endq
- ctok FALSE
- ctok BLK
- ctok STORE ; -- i*x c-addr u R: -- BLK TIB #TIB >IN SOURCE-ID endq
- ctok FALSE
- ctok TO_IN
- ctok STORE ; -- i*x c-addr u R: -- BLK TIB #TIB >IN SOURCE-ID endq
- ctok INTERPRET ; -- j*x R: -- BLK TIB #TIB >IN SOURCE-ID endq
- ctok R_FROM ; Restore input spec
- literal endq
- ctok STORE ; -- j*x c-addr u R: -- BLK TIB #TIB >IN SOURCE-ID
- ctok R_FROM
- ctok SOURCE_ID
- ctok STORE ; -- j*x c-addr u R: -- BLK TIB #TIB >IN
- ctok R_FROM
- ctok TO_IN
- ctok STORE ; -- j*x c-addr u R: -- BLK TIB #TIB
- ctok R_FROM
- ctok NUMTIB
- ctok STORE ; -- j*x c-addr u R: -- BLK TIB
- ctok R_FROM
- ctok TICK_TIB
- ctok STORE ; -- j*x c-addr u R: -- BLK
- ctok R_FROM
- ctok BLK
- ctok STORE ; -- j*x R: --
- ctok UNNEST
-
- znamemanque <(PARSE)> ; char "ccc<char>" -- c-addr u
- fw_PPARSE:
- ctok NEST ; this one skips leading delims
- ctok SOURCE ; -- ch c-a u , get TIB or current BLOCK & char count
- ctok TO_IN ; -- ch c-a u a , get addr of current interp inset var
- ctok FETCH ; -- ch c-a u n , get current inset
- ctok SLSTRING ; -- ch c-a' u'
- ctok OVER ; -- ch c-a' u' c-a' Need a copy to increment >IN
- ctok TO_R ; -- ch c-a' u' R: -- c-a'
- ctok DUP ; -- ch c-a' u' u' R: -- c-a'
- ctok ZEROGT ; -- ch c-a' u' t|f R: -- c-a'
- compif _0parse ; -- ch c-a' u' R: -- c-a'
- literal 2 ; -- ch c-a' u' 2 R: -- c-a'
- ctok PICK ; -- ch c-a' u' ch' , copy of delim char R: -- c-a'
- ctok SKIP ; -- ch c-a'' u'' , skip leading delim R: -- c-a'
- _9parse:
- ctok OVER ; -- ch c-a'' u'' c-a'' R: -- c-a'
- ctok TO_R ; -- ch c-a'' u'' ,save adr of 1st char R: -- c-a' c-a''
- ctok ROT ; -- c-a' u'' ch R: -- c-a' c-a''
- ctok SCAN ; -- c-a''' u''' R: -- c-a' c-a''
- ctok DROP ; -- c-a''' R: -- c-a' c-a''
- ctok R_FROM ; -- c-a''' c-a'' R: -- c-a'
- ctok R_FROM ; -- c-a''' c-a'' c-a' R: --
- literal 2 ; -- c-a''' c-a'' c-a' 2
- ctok PICK ; -- c-a''' c-a'' c-a' c-a'''
- ctok SWAP ; -- c-a''' c-a'' c-a''' c-a'
- ctok MINUS ; -- c-a''' c-a'' n=bytes
- ctok TWO_SLASH ; -- c-a''' c-a'' n=chars
- ctok ONE_PLUS ; account for the character itself which was parsed to.
- ctok TO_IN ; -- c-a''' c-a'' n a
- ctok PL_STORE ; -- c-a''' c-a''
- ctok TUCK ; -- c-a'' c-a''' c-a''
- ctok MINUS ; -- c-addr1 bytes
- ctok TWO_SLASH ; -- c-addr1 u=chars
- compelse _1parse ; -- ch c-a u R: -- c-a
- _0parse:
- ctok R_FROM
- ctok DROP ; -- ch c-a u R: --
- ctok DROP ; -- ch c-a
- ctok NIP ; -- c-a
- literal 0 ; -- c-a 0
- _1parse:
- ctok UNNEST
-
- fname <PARSE> ; ( char "ccc<char>" -- c-addr u)
- ctok NEST ; CORE EXT, hits on leading delimiters
- ctok SOURCE ; -- ch c-a u , get TIB or current BLOCK & char count
- ctok TO_IN ; -- ch c-a u a , get addr of current interp inset var
- ctok FETCH ; -- ch c-a u n , get current inset
- ctok SLSTRING ; -- ch c-a' u'
- ctok OVER ; -- ch c-a' u' c-a' Need a copy to increment >IN
- ctok TO_R ; -- ch c-a' u' R: -- c-a'
- ctok DUP ; -- ch c-a' u' u' R: -- c-a'
- ctok ZEROGT ; -- ch c-a' u' t|f R: -- c-a'
- compif _0parse ; -- ch c-a' u' R: -- c-a'
- compelse _9parse
-
- zname <okPrompt> ; i*x -- i*x
- ctok NEST ; implementation
- ctok DOKDOTQUOTE
- dd okPrompt
- ctok DEPTH
- ctok DOT
- ctok UNNEST
-
- nnamemanque <..> ; i*x --
- fw_DOTDOT:
- ctok NEST
- ctok DEPTH
- literal 0
- compqdo dotdot2
- dotdot1:
- ctok U_DOT
- comploop dotdot1
- dotdot2:
- ctok UNNEST
-
- fname <QUIT> ; ( --) ( R: i*x --)
- ctok NEST ; CORE
- literal ticktib
- ctok TICK_TIB ; reset input buffer
- ctok STORE
- literal FALSE
- ctok BLK ; Not BLOCK input
- ctok STORE
- literal FALSE
- ctok SOURCE_ID ; Indicate keyboard input
- ctok STORE
- literal FALSE
- ctok NUMTIB ; indicate that input stream is empty
- ctok STORE
- literal FALSE
- ctok TO_IN ; indicate that input stream is unparsed
- ctok STORE
- literal FALSE
- ctok STATE ; set STATE to interpret
- ctok STORE
- literal FALSE
- literal inDefinition ; we're not in the middle of a : or :NONAME
- ctok STORE
- _1quit: ; this is a "begin"
- ctok CR ; ye olde CR each Forth QUIT
- literal rpzero ; zero the return stack
- ctok FETCH
- ctok RP_STORE ; init the RP stack
- ctok FIRSTCATCH ; set up initial catch frame
- literal FALSE
- literal endq
- ctok STORE ; reset end-of-input var
- ctok REFILL ; get a line of input
- compif _1quit ; loop back if no input line
- ctok INTERPRET ; execute it
- ctok STATE ; check STATE
- ctok FETCH
- ctok ZEROEQ
- compif _2quit
- ctok okPrompt ; say "ok " if interpreting
- _2quit: compelse _1quit ; and this is an "Again"
-
- fname <SOURCE> ; -- c-addr u
- ctok NEST ; CORE
- ctok BLK
- ctok FETCH
- ctok QDUP
- compif source1
- ctok BLOCK
- literal blockSize
- ctok EXIT
- source1:
- ctok TIB
- ctok NUMTIB
- ctok FETCH
- ctok UNNEST
-
- fnamemanque <SOURCE-ID> ; -- a-addr
- fw_SOURCE_ID:
- ctok DOCONST ; CORE
- dd var_srcid
-
- fname <TIB> ; -- c-addr
- ctok NEST ; CORE EXT
- ctok TICK_TIB
- ctok FETCH
- ctok UNNEST
-
- ; Can't use our name header macros with this one!
- linkme nlinkptr
- countcell 4
- db "'",0,'T',0,'I',0,'B',0 ; -- a-addr
- align 4 ; Not in Standard
- fw_TICK_TIB:
- ctok DOCONST
- dd var_tib
-
- fnamemanque <#TIB> ; -- c-addr
- fw_NUMTIB:
- ctok DOCONST ; CORE EXT
- dd var_numtib
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 3
- db '>',0,'I',0,'N',0 ; -- a-addr
- align 4 ; CORE
- fw_TO_IN:
- ctok DOCONST
- dd var_to_in
-
- fname <REFILL> ; -- flag
- ctok NEST ; CORE EXT
- ctok SOURCE_ID ; check source of input
- ctok FETCH
- literal -1
- ctok EQUAL ; if it's EVALUATE, exit FALSE
- compif refill1
- ctok FALSE
- ctok EXIT
- refill1:
- ctok BLK
- ctok FETCH ; -- u
- ctok QDUP ; -- u u | o
- compif refill2 ; we get input from the next BLOCK
- ctok ONE_PLUS ; -- u'
- ctok DUP ; -- u' u'
- ctok BLK ; -- u' u' a-addr
- ctok STORE ; -- u'
- ctok FALSE ; Reset interpreter values
- ctok TO_IN
- ctok STORE
- ctok FALSE
- literal endq
- ctok STORE
- ctok INVALIDBLOCK ; -- flag, TRUE if invalid block number
- ctok ZEROEQ ; -- flag, correct sense for REFILL's return
- ctok EXIT
- refill2: ; We get input from the terminal
- ctok FALSE
- ctok TO_IN
- ctok STORE ; >IN OFF
- ctok FALSE
- literal endq
- ctok STORE ; END? OFF
- ctok TIB
- literal tibsize
- ctok ACCEPT ; Get as many chars as console can return
- ctok NUMTIB ; and store to #TIB
- ctok STORE
- ctok TRUE
- ctok UNNEST
-
- fname <WORD> ; ( char "ccc<char>" -- c-addr)
- ctok NEST ; CORE
- ctok PPARSE ; -- c-addr u
- literal wordBuffer ; -- c-addr u dest
- ctok TWO_DUP ; -- c-addr u dest u dest
- ctok SWAP ; -- src u dest dest u
- ctok ONE_PLUS ; -- src u dest dest u' taking the count word into account
- ctok CHARS ; -- src u dest dest n
- ctok PLUS ; -- src u dest c-addr(past end-of-dest)
- ctok BL ; -- src u dest c-addr bl
- ctok SWAP ; -- src u dest bl c-addr
- ctok C_STORE ; -- src u dest pad string with a blank
- ctok PLACE ; -- install string
- literal wordBuffer ; -- c-addr return word buffer addr
- ctok UNNEST
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell <1 or immedMask>
- db '(',0
- align 4 ; "ccc<)>" --
- fw_PAREN: ; CORE
- ctok NEST
- charlit ')'
- ctok PARSE
- ctok TWO_DROP
- ctok UNNEST
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell <1 or immedMask>
- db '\',0
- align 4 ; "ccc<eol>" --
- fw_BSLASH:
- ctok NEST
- ctok BLK
- ctok FETCH ; -- n
- compif bslash2
- ctok TO_IN
- ctok FETCH ; -- n
- literal 64
- ctok MOD ; -- mod
- ctok QDUP
- compif bslash1 ; -- n
- literal 64
- ctok SWAP
- ctok MINUS ; -- diff
- ctok TO_IN
- ctok PL_STORE ; --
- bslash1:
- ctok EXIT ; --
- bslash2:
- ctok NUMTIB ; -- a-addr
- ctok FETCH ; -- n
- ctok TO_IN
- ctok STORE ; --
- ctok UNNEST
-
- ;--( Implementation Addressing Scheme )
- ; In this terminology, "Code" is the user dictionary offset from register CP,
- ; "Data" is the data space offset from register DP (the latter not to be confused with Forth variable DP).
- ; The system dictionary resides in absolute address space.
-
- ; Convert absolute address to reg DP relative offset.
- sname <ABSTODATA> ; abs-addr -- data-addr
- dd abstodata ; Implementation
- abstodata:
- sub DWORD PTR [esp],dp
- next
-
- ; Convert reg DP relative offset to absolute address.
- sname <DATATOABS> ; data-addr -- abs-addr
- dd datatoabs ; Implementation
- datatoabs:
- add DWORD PTR [esp],dp
- next
-
- ; Convert absolute address to reg CP relative offset.
- sname <ABSTOCODE> ; abs-addr -- code-addr
- dd abstocode ; Implementation
- abstocode:
- sub DWORD PTR [esp],cp
- next
-
- ; Convert reg CP relative offset to absolute address.
- sname <CODETOABS> ; code-addr -- abs-addr
- dd codetoabs ; Implementation
- codetoabs:
- add DWORD PTR [esp],cp
- next
-
- ; Convert reg CP relative code offset to reg DP relative data offset
- sname <CODETODATA> ; code-addr -- data-addr
- ctok NEST ; Implementation
- ctok CODETOABS
- ctok ABSTODATA
- ctok UNNEST
-
- ; Convert reg DP relative data offset to reg CP relative code offset
- sname <DATATOCODE> ; data-addr -- code-addr
- ctok NEST ; Implementation
- ctok DATATOABS
- ctok ABSTOCODE
- ctok UNNEST
-
- ; Convert an offset in the user dictionary to a user dict execution token
- zname <MAKETOKEN> ; code-offset -- user-xt
- ctok NEST ; Implementation detail
- literal userdictmask
- ctok OR
- ctok UNNEST
-
- ; Detect if a given token is from the user dictionary
- znamemanque <USERTOKEN?>
- fw_USERTOKENQ: ; xt -- flag
- ctok NEST
- literal userdictmask
- ctok AND
- ctok ZEROEQ
- ctok ZEROEQ
- ctok UNNEST
-
- ; Unmask a user dictionary token
- zname <DETOKEN> ; user-xt -- code-offset
- ctok NEST
- literal userdictmask
- ctok INVERT
- ctok AND
- ctok UNNEST
-
- ;--( Compiler )
- ; Any compiler word with "xt" in the stack args presumes that a valid form of xt is present on the stack in that position.
-
- zname <SAVEDEPTH> ; i*x -- i*x
- ctok NEST ; Implementation
- ctok SP_FETCH
- literal cstack
- ctok STORE
- ctok UNNEST
-
- zname <CHECKDEPTH> ; j*x -- j*x [ 0 | n if stack has changed ]
- ctok NEST ; Implementation
- ctok SP_FETCH
- literal cstack
- ctok FETCH
- ctok MINUS
- ctok UNNEST
-
- zname <HEADER> ; c-addr u --
- ctok NEST ; Implementation
- ctok DP
- ctok FETCH ; -- c-addr u code-offset
- ctok MAKETOKEN ; -- c-addr u valid-link-token
- literal last ; -- c-addr u valid-link-token a-addr
- ctok STORE ; -- c-addr u keep token for last link added to dictionary
- ctok GET_CURRENT ; -- c-addr u wid
- ctok ABSTODATA ; -- c-addr u a-addr-pointer
- ctok FETCH ; -- c-addr u a-addr-wordlist-data-body
- ctok FETCH ; -- c-addr u token
- ctok COMPCOMMA ; -- c-addr u compile back-link to previous definiton in wl
- ctok DUP ; -- c-addr u u
- literal 16
- ctok LSHIFT ; -- c-addr u u<<16 because we are going to store two words as a dword
- literal 0FFFFH ; -- c-addr u u 0ffff
- ctok OR ; -- c-addr u 0ffffuuuu
- ctok COMPCOMMA ; -- c-addr u
- ctok DP
- ctok FETCH ; -- c-addr u code-offset
- ctok CODETODATA ; -- c-addr u a-addr
- ctok SWAP ; -- c-addr a-addr u
- ctok CHARS ; -- c-addr a-addr uchars
- ctok DUP ; -- c-addr a-addr ubytes ubytes
- ctok TO_R ; -- c-addr a-addr ubytes R: -- ubytes
- ctok MOVE ; -- R: -- ubytes
- ctok R_FROM ; -- ubytes R: --
- ctok DP
- ctok FETCH ; -- ubytes code-offset
- ctok PLUS ; -- n
- ctok ALIGNED ; -- n'
- ctok DP ; -- n a-addr
- ctok STORE ; --
- ctok UNNEST
-
- zname <LINKIT> ; --
- ctok NEST ; Implementation
- literal last ; -- a-addr
- ctok FETCH ; -- ltok
- ctok GET_CURRENT ; -- ltok wid
- ctok ABSTODATA ; -- ltok a-addr-pointer-to-wordlist-databody
- ctok FETCH ; -- ltok a-addr-of-wordlist-databody
- ctok STORE ; --
- ctok UNNEST
-
- ; This one's why ";" doesn't reset the system variable "nonaming"
- fname <IMMEDIATE> ; --
- ctok NEST ; CORE
- literal nonaming
- ctok FETCH
- literal -32 ; zero-length string THROW
- ctok AND
- ctok THROW ; a :NONAME word can't be IMMEDIATE
- literal last
- ctok FETCH
- ctok TOKENTODATA
- ctok LINKTONAME
- ctok DUP
- ctok C_FETCH
- literal immedMask
- ctok OR
- ctok SWAP
- ctok C_STORE
- ctok UNNEST
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 1
- db ':',0
- align 4 ; "name" --
- fw_COLON: ; CORE
- ctok NEST
- literal inDefinition
- ctok FETCH
- compif colon1
- literal -29
- ctok THROW ; nested compilation
- colon1: ctok TRUE
- literal inDefinition ; we're in a : definition now, prevent nested compilation
- ctok STORE
- ctok BL
- ctok WORD
- ctok COUNT
- ctok QDUP
- ctok ZEROEQ
- compif colonnzero
- literal -16
- ctok THROW
- colonnzero:
- ctok FALSE
- literal nonaming
- ctok STORE ; this is not a :NONAME defintion
- ctok HEADER
- compelse noname1 ; continue on in :NONAME
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 7
- db ':',0,'N',0,'O',0,'N',0,'A',0,'M',0,'E',0
- align 4 ; -- | xt (when nonaming)
- fw_noname: ; CORE EXT
- ctok NEST
- ctok TRUE
- literal inDefinition
- ctok FETCH
- compif noname0
- literal -29
- ctok THROW ; nested compilation
- noname0:
- literal inDefinition ; we're in a : definition now, prevent nested compilation
- ctok STORE
- ctok TRUE
- literal nonaming
- ctok STORE ; this is a :NONAME defintion
- ctok DP
- ctok FETCH
- ctok MAKETOKEN
- literal last
- ctok STORE ; so semicolon knows what to put on the stack
- noname1: ; colon ":" jumps here
- ctok SAVEDEPTH ; save stack depth to be checked by ";"
- ctok DOLIT
- ctok NEST
- ctok COMPCOMMA
- ctok RBRACKET
- ctok UNNEST
-
- zname <STATEABORT> ; --
- ctok NEST ; Implementation
- ctok STATE
- ctok FETCH
- ctok ZEROEQ ; state zero? we're interpreting
- literal -14 ; Interpreting a compile-only word throw
- ctok AND
- ctok THROW
- ctok UNNEST
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell <immedMask or 1>
- db ';',0
- align 4 ; -- | xt (when nonaming)
- fw_SEMICOLON: ; CORE
- ctok NEST
- ctok STATEABORT
- ctok FALSE
- literal inDefinition ; we're now out of a : or :NONAME
- ctok STORE
- ctok DOLIT
- ctok UNNEST
- ctok COMPCOMMA
- ctok LBRACKET
- ctok CHECKDEPTH
- compif semi_done
- literal -52
- ctok THROW
- ctok EXIT
- semi_done:
- literal nonaming
- ctok FETCH
- compif semi_named
- literal last ; unnamed, get xt for last definition and leave on stack
- ctok FETCH
- ctok EXIT
- semi_named:
- ctok LINKIT ; named, link in to compilation wordlist
- ctok UNNEST
-
- fnamemanque <]> ; --
- fw_RBRACKET: ; CORE
- ctok NEST
- ctok TRUE
- ctok STATE
- ctok STORE
- ctok UNNEST
-
- finamemanque <[> ; --
- fw_LBRACKET: ; CORE
- ctok NEST
- ctok STATEABORT
- ctok FALSE
- ctok STATE
- ctok STORE
- ctok UNNEST
-
- fname <STATE> ; -- a-addr
- ctok DOCONST ; CORE
- dd var_state
-
- nname <DP> ; -- a-addr
- ctok DOCONST ; Not in Standard
- dd dictp
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 8
- db 'C',0,'O',0,'M',0,'P',0,'I',0,'L',0,'E',0,',',0
- align 4 ; xt --
- fw_COMPCOMMA: ; CORE EXT
- ctok NEST
- ctok DP ; -- xt dp
- ctok DUP ; -- xt dp dp
- ctok FETCH ; -- xt dp @dp
- ctok ALIGNED ; -- xt dp @dp'
- ctok ROT ; -- dp @dp' xt
- ctok OVER ; -- dp @dp' xt @dp'
- ctok CODETODATA ; -- dp @dp' xt a-addr
- ctok STORE ; -- dp @dp'
- ctok CELL_PLUS ; -- dp @dp''
- ctok SWAP ; -- @dp'' dp(a-addr)
- ctok STORE ; --
- ctok UNNEST
-
- finame <RECURSE> ; --
- ctok NEST ; CORE
- ctok STATEABORT
- literal last
- ctok FETCH
- ctok TOKENTODATA
- ctok LINKTOEXE
- ctok DATATOCODE
- ctok MAKETOKEN
- ctok COMPCOMMA
- ctok UNNEST
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell 5
- db '>',0,'B',0,'O',0,'D',0,'Y',0
- align 4 ; xt -- a-addr
- fw_TO_BODY: ; CORE
- ctok NEST
- ctok TOKENTODATA ; -- a-addr
- ctok DUP ; -- a-addr a-addr
- ctok FETCH ; -- a-addr xt2
- ctok DUP ; -- a-addr xt2 xt2
- ctok DOLIT
- ctok DOCONST ; -- a-addr xt2 xt2 xt3
- ctok EQUAL ; -- a-addr xt2 flag
- ctok SWAP ; -- a-addr flag xt2
- ctok DUP ; -- a-addr flag xt2 xt2
- ctok DOLIT
- ctok DODOES ; -- a-addr flag xt2 xt2 xt4
- ctok EQUAL ; -- a-addr flag1 xt2 flag2
- ctok SWAP ; -- a-addr flag1 flag2 xt2
- ctok DOLIT
- ctok DODEFER ; -- a-addr flag1 flag2 xt2 xt5
- ctok EQUAL ; -- a-addr flag1 flag2 flag3
- ctok OR ; -- a-addr flag1 flag4
- ctok OR ; -- a-addr flag
- ctok ZEROEQ ; -- a-addr ~flag
- compif to_body1
- literal -31
- ctok THROW
- to_body1:
- ctok CELL_PLUS ; -- a-addr'
- ctok FETCH ; -- a-addr''
- ctok UNNEST
-
- fname <CREATE> ; "name" --
- ctok NEST ; CORE
- ctok ALIGN
- ctok BL
- ctok WORD
- ctok COUNT
- ctok QDUP
- ctok ZEROEQ
- compif create1
- literal -16
- ctok THROW
- create1:
- ctok HEADER
- ctok DOLIT
- ctok DOCONST
- ctok COMPCOMMA
- ctok HERE
- ctok COMPCOMMA
- ctok LINKIT
- ctok UNNEST
-
- fname <VARIABLE> ; "name" --
- ctok NEST ; CORE
- ctok CREATE
- literal 1
- ctok CELLS
- ctok ALLOT
- ctok UNNEST
-
- fname <CONSTANT> ; x "name" --
- ctok NEST ; CORE
- ctok CREATE
- ctok DP
- ctok FETCH
- ctok CODETODATA
- literal 1
- ctok CELLS
- ctok MINUS
- ctok STORE
- ctok UNNEST
-
- zname <MAKEDOES> ; xt --
- ctok NEST ; Implementation
- ctok DOLIT
- ctok DODOES
- literal last ; Link token left by the execution of CREATE
- ctok FETCH
- ctok TOKENTODATA
- ctok LINKTOEXE ; Link token is now data address of execution vector
- ctok STORE ; Now execution vector of CREATEd word is overwritten with DODOES
- ctok COMPCOMMA ; compile the xt for the DOES> body
- ctok UNNEST
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell <5 or immedMask>
- db 'D',0,'O',0,'E',0,'S',0,'>',0
- align 4 ; --
- fw_DOES: ; CORE
- ctok NEST
- ctok DOLIT
- ctok DOLIT
- ctok COMPCOMMA ; we are laying down a literal
- ctok DP
- ctok FETCH
- literal 3
- ctok CELLS
- ctok PLUS ; the literal is the dict pointer plus the cells laid down by DOES> ..
- ctok COMPCOMMA ; .. up to the code laid down in the DOES> body.
- ctok DOLIT
- ctok MAKETOKEN
- ctok COMPCOMMA ; Then MAKETOKEN has to be executed on that literal at DOES> time
- ctok DOLIT
- ctok MAKEDOES ; Resultant xt is consumed by MAKEDOES
- ctok COMPCOMMA
- ctok DOLIT
- ctok EXIT
- ctok COMPCOMMA ; Then we EXIT the CREATE .. DOES> definition but continue to compile
- ctok UNNEST
-
- finame <LITERAL> ; x --
- ctok NEST ; CORE
- ctok DOLIT
- ctok DOLIT
- ctok COMPCOMMA
- ctok COMPCOMMA
- ctok UNNEST
-
- finamemanque <2LITERAL> ; x x --
- fw_TWO_LITERAL: ; DOUBLE
- ctok NEST
- ctok DOLIT
- ctok DODLIT
- ctok COMPCOMMA
- ctok COMPCOMMA
- ctok COMPCOMMA
- ctok UNNEST
-
- finame <POSTPONE> ; "name" --
- ctok NEST ; CORE
- ctok STATEABORT
- ctok BL
- ctok WORD
- ctok FIND
- ctok DUP
- ctok ZEROEQ
- compif postpone1
- ctok UNFOUND
- postpone1:
- ctok DOLIT ; first of all, compile this code here ..
- ctok STATEABORT ; ... since ..
- ctok COMPCOMMA ; ... the POSTPONEd construct should THROW -14 if encountered interpretively.
- ctok ZEROLT ; -1 is non-IMMEDIATE
- compif postpone2
- ctok LITERAL
- ctok DOLIT
- ctok COMPCOMMA
- ctok COMPCOMMA
- ctok EXIT
- postpone2: ; 1 is IMMEDIATE
- ctok COMPCOMMA
- ctok UNNEST
-
- ;--( Branches )
-
- zname <UNRESOLVED> ; --
- ctok NEST ; Implementation
- literal -22
- ctok THROW
-
- finame <IF> ; -- orig
- ctok NEST ; CORE
- ctok STATEABORT
- ctok DOLIT
- ctok DOIF ; -- xt
- ctok COMPCOMMA ; --
- ctok DP
- ctok FETCH ; -- orig
- ctok DOLIT
- ctok UNRESOLVED ; -- orig xt
- ctok COMPCOMMA ; -- orig
- ctok UNNEST
-
- finame <ELSE> ; orig1 -- orig2
- ctok NEST ; CORE
- ctok STATEABORT
- ctok DOLIT
- ctok DOELSE ; -- o1 xt
- ctok COMPCOMMA ; -- o1
- ctok DP
- ctok FETCH ; -- o1 o2
- ctok SWAP ; -- o2 o1
- ctok DOLIT
- ctok UNRESOLVED ; -- o2 o1 xt
- ctok COMPCOMMA ; -- o2 o1
- ctok DP
- ctok FETCH ; -- o2 o1 resolution
- ctok MAKETOKEN ; -- o2 o1 xt
- ctok SWAP ; -- o2 xt o1
- ctok CODETODATA ; -- o2 xt a-addr
- ctok STORE ; -- o2
- ctok UNNEST
-
- finame <THEN> ; orig --
- ctok NEST ; CORE
- ctok STATEABORT
- ctok DP
- ctok FETCH ; -- orig resolution
- ctok MAKETOKEN ; -- orig xt
- ctok SWAP ; -- xt orig
- ctok CODETODATA ; -- xt a-addr
- ctok STORE ; --
- ctok UNNEST
-
- finame <BEGIN> ; -- dest
- ctok NEST ; CORE
- ctok STATEABORT
- ctok DP
- ctok FETCH ; -- dest
- ctok UNNEST
-
- finame <UNTIL> ; dest --
- ctok NEST ; CORE
- ctok STATEABORT
- ctok DOLIT
- ctok DOUNTIL ; -- dest xt
- ctok COMPCOMMA ; -- dest
- ctok MAKETOKEN ; -- xt
- ctok COMPCOMMA ; --
- ctok UNNEST
-
- finame <WHILE> ; dest -- orig dest
- ctok NEST ; CORE
- ctok STATEABORT
- ctok DOLIT
- ctok DOIF ; -- dest xt
- ctok COMPCOMMA ; -- dest
- ctok DP
- ctok FETCH ; -- dest orig
- ctok SWAP ; -- orig dest
- ctok DOLIT
- ctok UNRESOLVED ; -- orig dest xt
- ctok COMPCOMMA ; -- orig dest
- ctok UNNEST
-
- finame <REPEAT> ; orig dest --
- ctok NEST ; CORE
- ctok STATEABORT
- ctok DOLIT
- ctok DOELSE ; -- o d xt
- ctok COMPCOMMA ; -- o d
- ctok MAKETOKEN ; -- o xt
- ctok COMPCOMMA ; -- o
- ctok DP
- ctok FETCH ; -- o resolution
- ctok MAKETOKEN ; -- o xt
- ctok SWAP ; -- xt orig
- ctok CODETODATA ; -- xt a-addr
- ctok STORE ; --
- ctok UNNEST
-
- finame <AGAIN> ; dest --
- ctok NEST ; CORE EXT
- ctok STATEABORT
- ctok DOLIT
- ctok DOELSE ; -- d xt
- ctok COMPCOMMA ; -- d
- ctok MAKETOKEN ; -- xt
- ctok COMPCOMMA ; --
- ctok UNNEST
-
- finame <DO> ; -- do-dest
- ctok NEST ; CORE
- ctok STATEABORT
- ctok DOLIT
- ctok DODO ; -- xt
- ctok COMPCOMMA ; --
- ctok DP
- ctok FETCH ; -- do-dest
- ctok DOLIT
- ctok UNRESOLVED ; -- do-dest xt
- ctok COMPCOMMA ; -- do-dest
- ctok UNNEST
-
- finamemanque <?DO> ; -- dest
- fw_QDO: ctok NEST ; CORE
- ctok STATEABORT
- ctok DOLIT
- ctok DOQDO ; -- xt
- ctok COMPCOMMA ; --
- ctok DP
- ctok FETCH ; -- do-dest
- ctok DOLIT
- ctok UNRESOLVED ; -- do-dest xt
- ctok COMPCOMMA ; -- do-dest
- ctok UNNEST
-
- finame <LOOP> ; dest --
- ctok NEST ; CORE
- ctok STATEABORT
- ctok DOLIT
- ctok DOLOOP ; -- dest xt
- ctok COMPCOMMA ; -- dest
- ctok DUP ; -- dest dest
- ctok CELL_PLUS ; -- dest dest' so that it points beyond UNRESOLVED
- ctok MAKETOKEN ; -- dest xt
- ctok COMPCOMMA ; -- dest
- ctok DP
- ctok FETCH ; -- dest resolution
- ctok MAKETOKEN ; -- dest xt
- ctok SWAP ; -- xt dest
- ctok CODETODATA ; -- xt a-addr
- ctok STORE ; --
- ctok UNNEST
-
- finamemanque <+LOOP> ; --
- fw_PLUSLOOP:
- ctok NEST ; CORE
- ctok STATEABORT
- ctok DOLIT
- ctok DOPLUSLOOP ; -- dest xt
- ctok COMPCOMMA ; -- dest
- ctok DUP ; -- dest dest
- ctok CELL_PLUS ; -- dest dest' so that it points beyond UNRESOLVED
- ctok MAKETOKEN ; -- dest xt
- ctok COMPCOMMA ; -- dest
- ctok DP
- ctok FETCH ; -- dest resolution
- ctok MAKETOKEN ; -- dest xt
- ctok SWAP ; -- xt dest
- ctok CODETODATA ; -- xt a-addr
- ctok STORE ; --
- ctok UNNEST
-
- fname <I> ; -- n|u
- docode ; CORE
- mov eax,[rp] ; Calculate current loop index
- add eax,cell[rp]
- push eax
- next
-
- fname <J> ; -- n|u
- docode ; CORE
- mov eax,(3*cell)[rp] ; Calculate next outermost loop index
- add eax,(4*cell)[rp]
- push eax
- next
-
- fname <LEAVE>
- docode ; -- R: loop-sys --
- poprp ; CORE
- poprp
- poprpto ip
- next
-
- fname <UNLOOP> ; -- R: loop-sys --
- docode ; CORE
- poprp
- poprp
- poprp
- next
-
- ;--( Exception Handling )
-
- fname <ABORT> ; --
- ctok NEST ; CORE
- ctok TRUE
- ctok THROW ; no unnest needed!
-
- ; Can't use our name header macros with this one!
- linkme flinkptr
- countcell <6 or immedMask>
- db 'A',0,'B',0,'O',0,'R',0,'T',0,'"',0 ; ccc<"> --
- align 4 ; CORE
- fw_ABORT_QUOTE:
- ctok NEST
- ctok STATEABORT
- ctok DOLIT
- ctok DOIF ; -- xt
- ctok COMPCOMMA ; --
- ctok DP
- ctok FETCH ; -- orig
- ctok DOLIT
- ctok UNRESOLVED ; -- orig xt
- ctok COMPCOMMA ; -- orig
- literal -2
- ctok LITERAL
- ctok DP
- ctok FETCH
- ctok S_QUOTE
- ctok CODETODATA
- ctok DOLIT
- ctok THROW
- ctok SWAP
- ctok STORE ; overwrite the S" execution engine
- ctok DP
- ctok FETCH ; -- orig resolution
- ctok MAKETOKEN ; -- orig xt
- ctok SWAP ; -- xt orig
- ctok CODETODATA ; -- xt a-addr
- ctok STORE ; --
- ctok UNNEST
-
- fname <CATCH> ; i*x xt -- j*x 0 | i*x n)
- dd catch ; EXCEPTION
- catch: pop wp ; execution token
- fetch edx,lastCatch ; save previous catch pointer
- pushrp edx ; (1)
- pushrp esp ; (2) save stack pointer
- fetch edx,var_tib ; save buffer address
- pushrp edx ; (3)
- fetch edx,var_numtib ; save number of chars in input buffer
- pushrp edx ; (4)
- fetch edx,var_to_in ; save index into input buffer
- pushrp edx ; (5)
- fetch edx,var_srcid ; save source id
- pushrp edx ; (6)
- fetch edx,var_blk ; save BLK
- pushrp edx ; (7)
- pushrp ip ; (8) save interpretive pointer
- store lastCatch,rp ; put pointer to this frame in lastCatch variable
- mov ecx,OFFSET FLAT:uncatch ; routine to recover
- mov ip,ecx
- innext ; eax (the wp) already has the token to execute
- align cell
- uncatch: ; we only end up here if no THROW intervenes
- docode ; as if it was a cell in a colon definition pointing to ...
- docode ; ... a definition which started here ...
- fetch rp,lastCatch ; restore return pointer from lastCatch, points to frame
- poprpto ip ; (8) restore IP that was stashed by CATCH
- poprp ; (7) discard BLK
- poprp ; (6) discard SOURCE-ID
- poprp ; (5) discard >IN
- poprp ; (4) discard #TIB
- poprp ; (3) discard 'TIB
- poprp ; (2) discard DSP
- poprpto eax ; (1) lastCatch
- store lastCatch,eax
- xor eax,eax
- push eax ; 0 return says all is well
- next
-
- fname <THROW> ; k*x n -- k*x | i*x n
- docode ; EXCEPTION
- pop edx ; check arg
- and edx,edx
- jne throw1 ; zero? continue harmlessly
- next
- throw1: ; arg was non-zero
- fetch rp,lastCatch ; set return stack back to where it was
- store lastCaught,ip ; save IP pointing to cell following the THROW
- poprpto ip ; (8) restore IP that was stashed by CATCH
- poprpto eax ; (7)
- store var_blk,eax ; restore BLK
- poprpto eax ; (6)
- store var_srcid,eax ; restore SOURCE-ID
- poprpto eax ; (5))
- store var_to_in,eax ; restore >IN
- poprpto eax ; (4)
- store var_numtib,eax ; restore #TIB
- poprpto eax ; (3)
- store var_tib,eax ; restore 'TIB
- poprpto esp ; (2) restore DSP
- poprpto eax ; (1)
- store lastCatch,eax ; restore lastCatch
- push edx ; the throw code
- next
-
- zname <FIRSTCATCH> ; -- R: -- catch-sys
- docode ; Implementation
- xor edx,edx
- pushrp edx ; there is no previous catch to push in this case
- pushrp esp ; save stack pointer
- fetch edx,var_tib ; save buffer address
- pushrp edx
- fetch edx,var_numtib ; save number of chars in input buffer
- pushrp edx
- fetch edx,var_to_in ; save number of chars in input buffer
- pushrp edx
- fetch edx,var_srcid ; save source id
- pushrp edx
- fetch edx,var_blk ; save BLK
- pushrp edx
- mov eax,OFFSET FLAT:fw_CATCHFIRSTCATCH+cell
- pushrp eax ; the CATCH of last resort!
- store lastCatch,rp ; put pointer to this frame in lastCatch variable
- next ; onwards!
-
- zname <CATCHFIRSTCATCH> ; --
- ctok NEST ; Implementation
- ctok DUP
- literal -2 ; The ABORT" throw
- ctok EQUAL
- compif catchfirst1
- literal lastCaught ; Get IP which is pointing to pointer to string
- ctok FETCH ; IP
- ctok TOKENTODATA
- ctok FETCH ; data address of counted string
- ctok COUNT
- ctok TYPE
- compelse catchabort ; fall thru into the tail of ABORT throw
- catchfirst1:
- ctok DUP
- literal -1 ; The ABORT throw
- ctok EQUAL
- compif catchfirst4
- catchabort:
- ctok SP0
- ctok FETCH
- ctok SP_STORE
- ctok FIRSTCATCH ; if we hit the LASTCATCH frame, SP=SP0, RP=RP0, etc, just rebuild LASTCATCH
- ctok QUIT ; just QUIT
- catchfirst4:
- ctok DUP
- literal -4
- ctok EQUAL
- compif catchfirst13
- ctok DOKDOTQUOTE ; stack underflow abort
- dd stackUnderMsg
- compelse catchabort ; exit via an ABORT
- catchfirst13:
- ctok DUP
- literal -13
- ctok EQUAL
- compif catchfirst14
- literal wordBuffer
- ctok COUNT
- ctok TYPE
- ctok SPACE
- charlit '?'
- ctok EMIT
- ctok SPACE
- ctok DOKDOTQUOTE ; undefined word abort
- dd undefinedMsg
- compelse catchabort ; exit via an ABORT
- catchfirst14:
- ctok DUP
- literal -14
- ctok EQUAL
- compif catchfirst16
- ctok DOKDOTQUOTE ; compile-only abort
- dd compOnlyMsg
- compelse catchabort ; exit via an ABORT
- catchfirst16:
- ctok DUP
- literal -16
- ctok EQUAL
- compif catchfirst22
- ctok DOKDOTQUOTE ; zero-length name string abort
- dd zeroStringMsg
- compelse catchabort ; exit via an ABORT
- catchfirst22:
- ctok DUP
- literal -22
- ctok EQUAL
- compif catchfirst29
- ctok DOKDOTQUOTE ; control structure abort
- dd conStructMsg
- compelse catchabort ; exit via an ABORT
- catchfirst29:
- ctok DUP
- literal -29
- ctok EQUAL
- compif catchfirst31
- ctok FALSE
- literal inDefinition ; reset internal var indicating : or :NONAME in progress
- ctok STORE
- ctok DOKDOTQUOTE ; >BODY on non-CREATE word
- dd compNestMsg
- compelse catchabort ; exit via an ABORT
- catchfirst31:
- ctok DUP
- literal -31
- ctok EQUAL
- compif catchfirst33
- ctok DOKDOTQUOTE ; >BODY on non-CREATE word
- dd toBodyMsg
- compelse catchabort ; exit via an ABORT
- catchfirst33:
- ctok DUP
- literal -33
- ctok EQUAL
- compif catchfirst34
- ctok DOKDOTQUOTE ; BLOCK read error
- dd blockReadMsg
- compelse catchabort ; exit via an ABORT
- catchfirst34:
- ctok DUP
- literal -34
- ctok EQUAL
- compif catchfirst35
- ctok DOKDOTQUOTE ; BLOCK write error
- dd blockWriteMsg
- compelse catchabort ; exit via an ABORT
- catchfirst35:
- ctok DUP
- literal -35
- ctok EQUAL
- compif catchfirst37
- ctok DOKDOTQUOTE ; BLOCK number error
- dd blockNumMsg
- compelse catchabort ; exit via an ABORT
- catchfirst37:
- ctok DUP
- literal -37
- ctok EQUAL
- compif catchfirst49
- ctok LastError
- ctok FETCH ; Error should be in LastError if we reach this point
- ctok DOKDOTQUOTE ; File I/O exception
- dd fileIOMsg ; this message needs a trailing space!
- ctok U_DOT ; Display
- compelse catchabort ; exit via an ABORT
- catchfirst49:
- ctok DUP
- literal -49 ; search order overflow THROW
- ctok EQUAL
- compif catchfirst50
- ctok DOKDOTQUOTE
- dd srchOverMsg
- compelse catchabort ; exit via an ABORT
- catchfirst50:
- ctok DUP
- literal -50 ; search order underflow THROW
- ctok EQUAL
- compif catchfirst52
- ctok DOKDOTQUOTE
- dd srchUnderMsg
- compelse catchabort ; exit via an ABORT
- catchfirst52:
- ctok DUP
- literal -52
- ctok EQUAL
- compif catchfirst56
- ctok DOKDOTQUOTE
- dd cStackMsg ; control flow stack changed
- compelse catchabort ; exit via ABORT
- catchfirst56:
- ctok DUP
- literal -56
- ctok EQUAL
- compif catchall
- ctok DROP ; drop the -56
- ctok FIRSTCATCH ; if we hit the LASTCATCH frame, SP=SP0, RP=RP0, etc, just rebuild LASTCATCH
- ctok QUIT ; just QUIT
- catchall: ; the catch-all case for THROWs outside those we have handled
- literal throwMsg
- ctok ABSTODATA
- literal throwMsgLen
- ctok TYPE
- ctok DOT
- charlit '@'
- ctok EMIT
- ctok SPACE
- literal lastCaught
- ctok FETCH
- literal cell
- ctok MINUS
- ctok DOT
- ctok FIRSTCATCH ; if we hit the LASTCATCH frame, SP=SP0, RP=RP0, etc, just rebuild LASTCATCH
- ctok QUIT
- ctok UNNEST
-
- ;--( Tools & Utilities )
-
- nname <NOOP> ; --
- docode ; Doesn't appear in Standard
- nop
- next
-
- zname <DUMPLINE> ; a-addr1 -- a-addr2
- ctok NEST
- ctok DUP
- ctok DUP ; -- a-addr1 a-addr1
- ctok FALSE
- ctok LSHARP ; -- a-addr1 ud
- literal 8
- ctok FALSE
- compdo dumpline2
- dumpline1:
- ctok SHARP ; -- a-addr1 ud'
- comploop dumpline1
- dumpline2:
- ctok SHARPR
- ctok TYPE ; -- a-addr1 print line address
- ctok SPACE
- literal 8
- literal 0
- compdo dumpline4
- dumpline3: ; -- addr addr
- ctok COUNT ; -- addr addr' char
- ctok FALSE
- ctok LSHARP
- ctok SHARP
- ctok SHARP
- ctok SHARP
- ctok SHARP
- ctok SHARPR
- ctok TYPE ; -- addr addr' print two bytes as a word
- ctok SPACE
- comploop dumpline3
- dumpline4:
- ctok DROP ; -- addr
- literal 8
- literal 0
- compdo dumpline6
- dumpline5:
- ctok COUNT
- literal 0FFh
- ctok AND
- ctok DUP
- literal 01fH ; -- addr' char char 01fh
- ctok GREATER
- compif dumplinenochar
- ctok EMIT
- compelse dumplinez
- dumplinenochar:
- ctok DROP
- charlit '.'
- ctok EMIT
- dumplinez:
- comploop dumpline5
- dumpline6:
- ctok UNNEST ; -- addr'
-
- fname <DUMP> ; addr u --
- ctok NEST ; TOOLKIT
- ctok BASE ; -- addr u a-addr
- ctok FETCH ; -- addr u n
- ctok TO_R ; -- addr u R: -- base
- ctok HEX
- ctok CR
- literal dumpHdr ; print a header here
- ctok ABSTODATA
- ctok COUNT
- ctok TYPE ; -- addr u R: -- base
- ctok CR
- ctok SWAP ; -- u addr
- ctok FALSE ; -- u addr 0
- literal 16 ; Now align the dump region
- ctok UMSLMOD ; -- u1 u2r addr/8
- ctok SWAP ; -- u addr/8 u2r
- ctok TO_R ; -- u addr/8 R: -- u2r
- literal 16
- ctok UMSTAR ; -- u addr' 0 R: -- u2r
- ctok DROP ; -- u addr' R: -- u2r
- ctok SWAP ; -- addr u R: -- u2r
- ctok FALSE ; -- addr u 0 R: -- u2r
- literal 16
- ctok UMSLMOD ; -- addr u1r u2q R: -- u2r
- ctok SWAP ; -- addr u2q u1r R: -- u2r
- ctok ZERONE ; -- addr u/16 [-1 | 0] R: -- u2r
- ctok NEGATE ; -- addr u/16 [1 | 0] R: -- u2r
- ctok PLUS ; -- addr u(number of iterations) R: -- u2r
- ctok R_FROM ; -- addr u/16 u2r R: --
- ctok ZERONE ; -- addr u/16 [1|0] [-1 | 0]
- ctok NEGATE ; -- addr u/16 [1|0] [1 | 0]
- ctok PLUS ; -- addr u(number of iterations) ; add line if bytes modded
- ctok FALSE ; -- addr u/16 0
- compdo dump3 ; dump that many lines
- dump1: ctok DUMPLINE ; -- addr'
- ctok CR ; -- addr'
- ctok KEY_Q ; -- addr' flag, has user punched for pause or quick quit?
- compif dumpcontinue ; -- addr', user hasn't punched for pause or quick quit
- ctok KEY ; -- addr' char
- ctok BL ; -- addr' c1 c2
- ctok EQUAL ; -- addr' flag, was it a space bar?
- compif dump2 ; -- addr', if not, it's a quit, hit a LEAVE below
- ctok KEY ; -- addr' char, space bar, we wait for user to punch again
- ctok BL ; -- addr' c1 c2
- ctok EQUAL ; -- addr' flag, if it's a space bar, resume
- compif dump2 ; -- addr', but if it's anything else, quit
- compelse dumpcontinue ; -- addr, twas a space bar, continue
- dump2:
- ctok LEAVE ; -- addr
- dumpcontinue:
- comploop dump1
- dump3: ; -- addr R: -- +n
- ctok DROP ; --
- ctok R_FROM ; -- +n R: --
- ctok BASE ; -- +n a-addr
- ctok STORE ; --
- ctok UNNEST
-
- fname <BYE> ; --
- dd byebye ; TOOLKIT EXT
- byebye: ; exit program
- fetch ebp,ntConEBP
- fetch esp,ntConESP
- fetch eax,memHandle
- INVOKE LocalFree, eax
- INVOKE WriteConsoleW, [dp+stdErr], OFFSET FLAT:byeMsg, byeMsgLen, OFFSET FLAT:numWritten,0
- pop edi
- pop esi
- pop ebx
- leave
- INVOKE ExitProcess, 0
-
- fnamemanque <AT-XY> ; u1 u2 --
- fw_AT_XY: ; FACILITY
- docode
- pop eax ; y
- pop edx ; x
- shl eax,16
- mov ax,dx ; compose COORD wherein Y is higher in mem than X
- INVOKE SetConsoleCursorPosition, DWORD PTR stdOut[dp], eax
- and eax,eax ; success is "C" TRUE
- ; je at_xy1 ; if failure, we'll do some more work
- mov DWORD PTR lastError[dp],-1 ; success, set lastErr
- next ; success, exit
- at_xy1: jmp doLastErr ; return to NEXT via doLastErr
-
- fname <PAGE> ; --
- docode ; FACILITY
- mov eax,20H ; character to fill with
- mov edx,32767 ; !!!***!!! HACK HACK HACK we have to calculate this correctly
- xor ecx,ecx ; Coord for fill, i.e., "0@0"
- INVOKE FillConsoleOutputCharacterW, DWORD PTR stdOut[dp], eax, edx, ecx, OFFSET FLAT:numWritten
- and eax,eax ; success is "C" TRUE
- ; je at_xy1 ; failure, exit re-using code above in AT-XY
- xor eax,eax ; make a "0@0" Coord for next call
- INVOKE SetConsoleCursorPosition, DWORD PTR stdOut[dp], eax
- and eax,eax ; success is "C" TRUE
- ; je at_xy1 ; failure, exit re-using code above in AT-XY
- mov DWORD PTR lastError[dp],-1 ; success, set lastErr
- next
-
- fnamemanque <ENVIRONMENT?> ; c-addr u -- false | i*x true
- fw_ENVQ: ; CORE
- ctok NEST
- ctok TWO_DROP
- ctok FALSE ; don't know nuttin'
- ctok UNNEST
-
- ;--( File Words )
-
- include jx4files.a ; jax4th.asm is just getting too big!
-
- ;--( Platform-Specific Stuff )
-
- ; Copy unicode string to asciiz string in special sys buffer, null terminates
- sname <ASCIIZ> ; c-addr u -- addr
- ctok NEST ; Not in Standard, used for syscalls that don't take unicode
- ctok TUCK ; -- u c-addr u
- ctok FALSE ; -- u c-addr u 0
- compqdo asciiz2
- asciiz1:
- ctok DUP ; -- u c-addr c-addr
- ctok C_FETCH ; -- u c-addr char
- literal asciizBuffer ; -- u c-addr char addr
- ctok I
- ctok PLUS ; -- u c-addr char addr'
- ctok B_STORE ; -- u c-addr
- ctok CHAR_PLUS ; -- u c-addr'
- comploop asciiz1
- asciiz2:
- ctok DROP ; -- u
- literal asciizBuffer ; -- u addr
- ctok PLUS ; -- addr' one past end of byte string
- ctok FALSE
- ctok SWAP ; -- 0 addr'
- ctok B_STORE ; --
- literal asciizBuffer ; -- addr buffer holding ascii byte string
- ctok UNNEST
-
- ; Copy ascii string to unicode string in special sys buffer, null terminates
- sname <UNICODE> ; b-addr u -- addr
- ctok NEST ; Not in Standard, used for syscalls that don't take unicode
- ctok TUCK ; -- u b-addr u
- ctok FALSE ; -- u b-addr u 0
- compqdo unicode2
- unicode1:
- ctok DUP ; -- u b-addr b-addr
- ctok B_FETCH ; -- u b-addr char
- literal asciizBuffer ; -- u b-addr char c-addr
- ctok I
- ctok CHARS
- ctok PLUS ; -- u c-addr char addr'
- ctok C_STORE ; -- u c-addr
- ctok ONE_PLUS ; -- u c-addr'
- comploop unicode1
- unicode2:
- ctok DROP ; -- u
- literal asciizBuffer ; -- u addr
- ctok CHARS
- ctok PLUS ; -- addr' one past end of byte string
- ctok FALSE
- ctok SWAP ; -- 0 addr'
- ctok C_STORE ; --
- literal asciizBuffer ; -- addr buffer holding ascii byte string
- ctok UNNEST
-
- sname <SYSCALL> ; abs-addr -- edx eax
- docode ; Call addr and return eax and edx
- pushrp ebx ; I'm suspicious this isn't loyally preserved
- pop eax
- call eax
- push edx
- push eax
- poprpto ebx ; restore
- next
-
- sname <GetProcAddress> ; [lpszProc | ordinal] hModule -- abs-addr | nil
- docode ; find a DLL function address from a null-terminated name string
- call GetProcAddress ; parameter if ordinal must have zero (0000h) in hi word
- push eax
- next
-
- sname <LoadLibraryEx> ; dwFlags 0 lpszLibFile -- hModule | 0
- docode
- call LoadLibraryExW
- push eax
- test eax,0
- je doLastErr ; if error, set LastError var
- next
-
- sname <FreeLibrary> ; hLibModule --
- docode
- call FreeLibrary
- push eax
- test eax,0
- je doLastErr ; if error, set LastError var
- next
-
- sname <ENABLE_LINE_INPUT> ; -- x
- ctok DOCONST ; Con Mode constant value
- dd ENABLE_LINE_INPUT
-
- sname <ENABLE_ECHO_INPUT> ; -- x
- ctok DOCONST ; Con Mode constant value
- dd ENABLE_ECHO_INPUT
-
- sname <ENABLE_PROCESSED_INPUT> ; -- x
- ctok DOCONST ; Con Mode constant value
- dd ENABLE_PROCESSED_INPUT
-
- sname <ENABLE_WINDOW_INPUT> ; -- x
- ctok DOCONST ; Con Mode constant value
- dd ENABLE_WINDOW_INPUT
-
- sname <ENABLE_MOUSE_INPUT> ; -- x
- ctok DOCONST ; Con Mode constant value
- dd ENABLE_MOUSE_INPUT
-
- sname <StdIn> ; -- a-addr
- ctok DOCONST ; Con stdin
- dd stdIn
-
- sname <StdOut> ; -- a-addr
- ctok DOCONST ; Con stdout
- dd stdOut
-
- sname <StdErr> ; -- a-addr
- ctok DOCONST ; Con stdErr
- dd stdErr
-
- sname <ConsoleMode> ; -- a-addr
- ctok DOCONST ; Address of Con Mode variable
- dd conMode ; Implementation
-
- sname <LastError> ; -- a-addr
- ctok DOCONST ; Address of Last Error variable
- dd lastError ; Implementation
-
- sname <GetConsoleMode> ; -- LastErr | TRUE
- docode ; Implementation
- lea eax,[dp+conMode]
- INVOKE GetConsoleMode, [dp+stdIn], eax
- jmp SHORT retLastErr ; returns to NEXT via doLastErr
-
- sname <SetConsoleMode> ; -- LastErr | TRUE
- docode ; Implementation
- mov eax,[dp+conMode]
- INVOKE SetConsoleMode, [dp+stdIn], eax
- jmp SHORT retLastErr ; returns to NEXT via doLastErr
-
- ; Set our local LastError variable either TRUE for success or to return from LastError, return same on stack
- retLastErr:
- and eax,eax ; "C" TRUE is success
- je rLE1 ; on failure, get error code
- mov DWORD PTR lastError[dp],TRUE ; success, return TRUE
- mov eax,TRUE
- push TRUE
- next ; No Windows error code has all bits set
- rLE1: INVOKE GetLastError
- mov lastError[dp],eax ; save error return
- push eax
- next
-
- ;--( Startup & Signoff )
-
- zname <LOGIN>
- docode
- INVOKE WriteConsoleW, [dp+stdErr], OFFSET FLAT:myMsg,myMsgLen, OFFSET FLAT:numWritten, 0
- next
-
- nname <ABOUT>
- docode
- INVOKE WriteConsoleW, [dp+stdErr], OFFSET FLAT:gnuMsg, gnuMsgLen, OFFSET FLAT:numWritten, 0
- next
-
- nname <COLD>
- ctok NEST
- cold: ctok GetConsoleMode ; set up our variable that tracks the console input mode
- ctok DROP ; discard return
- ctok DECIMAL ; set number conversion base to decimal, set early to aid debugging
- ctok FALSE
- ctok BLK ; input is not from a BLOCK file
- ctok STORE
- ctok FALSE
- ctok SOURCE_ID ; input is from keyboard
- ctok STORE
- literal ticktib
- ctok TICK_TIB ; set up pointer to terminal input buffer
- ctok STORE
- ctok FALSE
- ctok NUMTIB ; no chars in terminal input buffer
- ctok STORE
- ctok FALSE
- ctok TO_IN ; no index into zero chars
- ctok STORE
- ctok FALSE
- ctok STATE ; interpreting, not compiling
- ctok STORE
- ctok FALSE
- literal endq ; not end of input
- ctok STORE
- ctok EMPTYBUFFERS ; clear block buffer(s)
- ctok FALSE
- literal blockFile
- ctok STORE ; no active block file
- ctok FIRSTCATCH ; set up initial catch frame
- ctok INITDEFERS ; all the deferred words
- ctok ONLY ; set default search order
- ctok DEFINITIONS ; set default compilation order
- ctok SWORDLIST
- ctok NWORDLIST
- ctok FWORDLIST
- literal 3
- ctok SET_ORDER
- cold1: ctok LSHARP ; set up number conversion buffer
- ctok GETCOMMANDLINE ; -- c-addr u
- ctok NUMTIB
- ctok STORE
- ctok TICK_TIB
- ctok STORE
- ctok BL
- ctok WORD
- ctok DROP ; -- , eliminate filename from command line
- ctok INTERPRET ; -- interpret, ABORT will clean up
- ; ctok PAGE
- ctok LOGIN ; display signon message including copyright
- ctok ABOUT
- ctok okPrompt
- ctok QUIT
-
- zname <INITDEFERS> ; -- , init all deferred vectors
- ctok NEST
- ctok DOLIT
- ctok FILEPOSITIONW
- ctok DOLIT
- ctok FILEPOSITION
- ctok TO_BODY
- ctok STORE ; Init FILE-POSITION
- ctok DOLIT
- ctok FILESIZEW
- ctok DOLIT
- ctok FILESIZE
- ctok TO_BODY
- ctok STORE ; Init FILE-SIZE
- ctok DOLIT
- ctok READFILEW
- ctok DOLIT
- ctok READFILE
- ctok TO_BODY
- ctok STORE ; Init READ-FILE
- ctok DOLIT
- ctok REPOFILEW
- ctok DOLIT
- ctok REPOFILE
- ctok TO_BODY
- ctok STORE ; Init REPOSITION-FILE
- ctok DOLIT
- ctok RESIZEFILEW
- ctok DOLIT
- ctok RESIZEFILE
- ctok TO_BODY
- ctok STORE ; Init RESIZE-FILE
- ctok DOLIT
- ctok WRITEFILEW
- ctok DOLIT
- ctok WRITEFILE
- ctok TO_BODY
- ctok STORE ; Init WRITE-FILE
- ctok UNNEST
-
- ;--( Save and Restore Input )
-
- fnamemanque <SAVE-INPUT> ; -- xn .. x1 n
- fw_SAVEINP: ; CORE EXT
- ctok NEST
- ctok TIB
- ctok NUMTIB
- ctok FETCH
- ctok TO_IN
- ctok FETCH
- literal endq
- ctok FETCH
- ctok BLK
- ctok FETCH
- ctok SOURCE_ID
- ctok FETCH
- literal 6
- ctok UNNEST
-
- fnamemanque <RESTORE-INPUT> ; -- xn .. x1 n
- fw_RESTINP: ; CORE EXT
- ctok NEST
- ctok DROP
- ctok SOURCE_ID
- ctok STORE
- ctok BLK
- ctok STORE
- literal endq
- ctok STORE
- ctok TO_IN
- ctok STORE
- ctok NUMTIB
- ctok STORE
- ctok TICK_TIB
- ctok STORE
- ctok UNNEST
-
- ;--( Saving and Restoring Images )
-
- nnamemanque <SAVE-FORTH> ; -- 0|error
- fw_SAVEFORTH:
- docode
- store var_tib,ticktib ; loaded image comes back with normal inputbuff
- store var_numtib,0 ; loaded image comes back with no chars in buffer
- store var_to_in,0 ; no words parsed
- store endq,0 ; nuttin' happenin'
- store var_blk,0 ; no block
- store var_srcid,0 ; no file
- store lastError,0 ; no error
- store zeroBuffer,002E002Ah ; init file title string to "*.*\0"
- store (zeroBuffer+cell),0000002Ah
- mov eax,zeroBuffer ; data address of buffer
- add eax,dp ; convert to abs address
- mov edx,OFFSET FLAT:saveFile ; address of OPENFILENAME struct
- mov [edx].OPENFILENAME.lpstrFile,eax ; init w/ptr to string
- INVOKE GetSaveFileNameW,edx ; get string of file name to save
- and eax,eax
- je saveferr
- mov eax,zeroBuffer ; data address of buffer
- add eax,dp ; convert to abs address
- INVOKE CreateFileW, eax, GENERIC_WRITE, 0, OFFSET FLAT:secAttrib, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0
- cmp eax,INVALID_HANDLE_VALUE
- je saveferr1 ; if handle is invalid, branch away
- push eax ; save file handle
- INVOKE WriteFile, eax, cp, defDataSize+defDictSize, OFFSET FLAT:numRead, 0
- and eax,eax ; did we write ok?
- jne saveforth1 ; if TRUE, it's ok, branch onwards
- INVOKE GetLastError ; if FALSE, error, get it
- mov edx,eax ; save the error
- store lastError,eax ; keep copy in lastError
- pop eax ; get back file handle
- push edx ; here's the last error return to exit word with
- INVOKE CloseHandle,eax ; close the file handle
- next ; return that error code we left on stack
- saveforth1: ; we wrote ok
- pop eax ; get file handle back
- INVOKE CloseHandle,eax ; close the file handle
- saveforthdone:
- xor eax,eax ; make a zero, we don't care what CloseHandle did
- push eax ; return success
- next
- saveferr:
- store lastError, userErr ; an error code that no Windows API returns
- INVOKE CommDlgExtendedError ; get dialog error
- push eax ; push error ior
- ; but don't store in lastError, shows diff from GetLastError
- next
- saveferr1:
- INVOKE GetLastError ; if FALSE, error, get it
- store lastError,eax ; keep copy in lastError, this is a GetLastError err
- push eax ; push error ior
- next
-
- znamemanque <SAVE-CON> ; -- x1 .. xn
- fw_SAVECON: ; save console and other specs
- ctok NEST
- literal lastCatch ; holds catch frame pointer
- ctok FETCH
- literal lastCaught ; holds IP pointing to cell following THROW
- ctok FETCH
- literal conMode ; Holds Console Mode
- ctok FETCH
- literal ntConEBP ; holds value of EBP from startup
- ctok FETCH
- literal ntConESP ; holds value of ESP from startup
- ctok FETCH
- literal memHandle ; pointer to allocated memory block
- ctok FETCH
- literal stdIn ; Console handle
- ctok FETCH
- literal stdOut ; Console handle
- ctok FETCH
- literal stdErr ; Console handle
- ctok FETCH
- ctok SP0 ; initial SP
- ctok FETCH
- literal rpzero ; initial RP
- ctok FETCH
- ctok UNNEST
-
- znamemanque <RESTORE-CON> ; x1 .. xn --
- fw_RESTCON: ; Restore console and other specs
- ctok NEST
- literal rpzero ; initial RP
- ctok STORE
- ctok SP0 ; initial SP
- ctok STORE
- literal stdErr ; Console handle
- ctok STORE
- literal stdOut ; Console handle
- ctok STORE
- literal stdIn ; Console handle
- ctok STORE
- literal memHandle ; pointer to allocated memory block
- ctok STORE
- literal ntConESP ; holds value of ESP from startup
- ctok STORE
- literal ntConEBP ; holds value of EBP from startup
- ctok STORE
- literal conMode ; Holds Console Mode
- ctok STORE
- literal lastCaught ; holds IP pointing to cell following THROW
- ctok STORE
- literal lastCatch ; holds catch frame pointer
- ctok STORE
- ctok UNNEST
-
- snamemanque <RELOAD-FILE> ; file-id -- u ior
- fw_RELOADFILE:
- ctok NEST ; reloads an image from file-id
- ctok TO_R ; -- R: -- fid
- ctok SAVECON ; -- x1 .. xn R: -- fid
- ctok R_FROM ; -- x1 .. xn fid R: --
- literal 0
- ctok CODETODATA ; -- x1 .. xn fid a-addr, base of user image
- literal (defDataSize+defDictSize) ; -- x1 .. xn fid a-addr u, size of user image in bytes
- ctok ROT ; -- x1 .. xn c-addr u fid
- ctok READFILEA ; -- x1 .. xn u ior
- ctok TWO_TO_R ; -- x1 .. xn R: -- u ior
- ctok RESTCON ; -- R: -- u ior
- ctok TWO_R_FROM ; -- u ior R: --
- ctok UNNEST
-
- sname <RELOADED> ; c-addr u -- u ior1 ior2
- ctok NEST ; reload image from name file
- ctok RO ; -- c-addr u fam
- ctok OPENFILE ; -- fid ior
- compif reloaded1
- literal -37
- ctok THROW
- reloaded1: ; -- fid
- ctok DUP ; -- fid fid
- ctok RELOADFILE ; -- fid u ior
- ctok ROT ; -- u ior fid
- ctok CLOSEFILE ; -- u ior1 ior2
- ctok UNNEST
-
- sname <RELOAD> ; "ccc< >" --
- ctok NEST ; use on NT command line only, otherwise crap in TIB
- ctok BL
- ctok WORD
- ctok TO_R ; -- R: -- c-addr
- ctok SAVEINP ; -- n*x n
- ctok R_FROM ; -- n*x n c-addr
- ctok COUNT ; -- n*x n c-addr' u
- ctok RELOADED ; -- n*x n u ior1 ior2
- ctok TWO_DROP ; -- n*x n ior
- ctok DROP ; -- n*x n
- ctok RESTINP ; --
- ctok UNNEST
-
- sname <GETCOMMANDLINE> ; -- c-addr u
- docode
- INVOKE GetCommandLineW
- push eax ; push address of command line
- sub DWORD PTR [esp],dp ; convert to data-relative address
- mov ecx,eax
- .WHILE ( WORD PTR [eax] != 0 ) ; find null at end of string
- add eax,tchar
- .ENDW
- xor edx,edx
- sub eax,ecx
- mov ecx,2
- div ecx
- push eax
- next
-
- ;--( Bootup )
-
- boot: ; initialize system
- INVOKE LocalAlloc, LMEM_FIXED, defDataSize+defDictSize ; get mem for user dictionary & data space
- mov cp,eax ; return if non-null is user dictionary, must test here
- lea dp,[eax+defDictSize] ; data space
- store memHandle,eax ; save copy of mem handle for later free
- store ntConEBP,ebp ; preserve EBP
- store ntConESP,esp ; preserve ESP
- lea rp,[esp-dStackSize] ; set return stack pointer
- store rpzero,rp ; save initial return stack
- INVOKE GetStdHandle, STD_INPUT_HANDLE ; return is handle or INVALID_HANDLE
- store stdIn,eax ; store handle
- INVOKE GetStdHandle, STD_OUTPUT_HANDLE ; return is handle or INVALID_HANDLE
- store stdOut,eax ; store handle
- INVOKE GetStdHandle, STD_ERROR_HANDLE ; return is handle or INVALID_HANDLE
- store stdErr,eax ; store handle
-
- ; !!!***!!! for now, just fall thru here into bare_boot
-
- bare_boot: ; if we aren't loading a saved image
- store datap,varptr ; set HERE
- store dictp,0 ; offset end of dictionary
- store wllink,<OFFSET FLAT:fw_SWORDLIST> ; word list link
- mov DWORD PTR [dp+flinkp],flinkptr ; last link in FORTH-WORDLIST
- mov DWORD PTR [dp+zlinkp],zlinkptr ; last link in INTERNALS-WORDLIST
- mov DWORD PTR [dp+nlinkp],nlinkptr ; last link in NONSTANDARD-WORDLIST
- mov DWORD PTR [dp+slinkp],slinkptr ; last link in SYSTEM-WORDLIST
- mov ecx,searchOrderSize ; set up to clear search order
- xor eax,eax ; 0
- lea edx,searchOrder[dp] ; address of base of search order array
- bb1: mov [edx],eax ; erase a cell
- add edx,cell ; increment address
- loop bb1 ; loop till done
-
- dev_boot:
- mov WORD PTR lastReadConW,UniNotAChar
- mov ip,OFFSET FLAT:cold
- next
-
- _main ENDP
-
- _TEXT ENDS
-
- END
-