Files
linguist/samples/Assembly/forth.nasm
Lars Brinkhoff d673010420 Add .nasm extension for Assembly files.
Sample file by Chris Hinsley.
2015-02-12 08:24:44 +01:00

2842 lines
51 KiB
NASM

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; A Forth by Chris Hinsley
;; nasm -f macho forth.nasm
;; ld -o forth -e _main forth.o
;; ./forth
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%define VERSION_NUM 30
; various buffer area sizes
%define DATA_STACK_SIZE 1024
%define USER_DEFS_SIZE (64*1024)
%define NUM_HASH_CHAINS 64
%define MAX_LINE_SIZE 128
%define SYS_exit 1
%define SYS_read 3
%define SYS_write 4
%define SYS_open 5
%define SYS_close 6
%define SYS_unlink 10
%define SYS_mprotect 74
%define SYS_fsync 95
%define SYS_rename 128
%define SYS_stat 188
%define SYS_lseek 199
%define SYS_fstat 189
%define SYS_ftruncate 201
%define PROT_READ 0x01 ;pages can be read
%define PROT_WRITE 0x02 ;pages can be written
%define PROT_EXEC 0x04 ;pages can be executed
%define PROT_ALL (PROT_READ | PROT_WRITE | PROT_EXEC)
%define PAGE_SIZE 4096
;;;;;;;;;;;;;;;;;;;;;;;;;;
; some NASM codeing macros
;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro loopstart 0
%push loopstart
%$loop_start:
%endmacro
%macro break 0
jmp %$loop_exit
%endmacro
%macro breakif 1
j%+1 %$loop_exit
%endmacro
%macro loopend 0
jmp %$loop_start
%$loop_exit:
%pop
%endmacro
%macro repeat 0
%push repeat
%$loop_start:
%endmacro
%macro until 1
j%-1 %$loop_start
%$loop_exit:
%pop
%endmacro
%macro if 1
%push if
j%-1 %$ifnot
%endmacro
%macro else 0
%ifctx if
%repl else
jmp %$ifend
%$ifnot:
%else
%error "expected `if' before `else'"
%endif
%endmacro
%macro endif 0
%ifctx if
%$ifnot:
%pop
%elifctx else
%$ifend:
%pop
%else
%error "expected `if' or `else' before `endif'"
%endif
%endmacro
;;;;;;;;;;;;;;;;
; base VM macros
;;;;;;;;;;;;;;;;
; eip Forths IP
; esp Forths R
; ebp Forths S
; ebx Forths TOS
; push on to return stack
%macro PUSHRSP 1
push %1
%endm
; pop top of return stack
%macro POPRSP 1
pop %1
%endm
; save into return stack
%macro PUTRSP 2
%if (%2 = 0)
mov [esp], %1
%elif ((%2 >= -128) && (%2 < 128))
mov [byte esp + %2], %1
%else
mov [long esp + %2], %1
%endif
%endm
; load from return stack
%macro PICKRSP 2
%if (%2 = 0)
mov %1, [esp]
%elif ((%2 >= -128) && (%2 < 128))
mov %1, [byte esp + %2]
%else
mov %1, [long esp + %2]
%endif
%endm
; set return stack
%macro SETRSP 1
mov esp, %1
%endm
; get return stack
%macro GETRSP 1
mov %1, esp
%endm
; adjust return stack
%macro ADDRSP 1
%if ((%1 >= -128) && (%1 < 128))
add esp, byte %1
%else
add esp, %1
%endif
%endm
; push on to data stack
%macro PUSHDSP 1
sub ebp, byte 4
mov [ebp], %1
%endm
; pop top of data stack
%macro POPDSP 1
mov %1, [ebp]
add ebp, byte 4
%endm
; save into data stack
%macro PUTDSP 2
%if (%2 = 0)
mov [ebp], %1
%elif ((%2 >= -128) && (%2 < 128))
mov [byte ebp + %2], %1
%else
mov [long ebp + %2], %1
%endif
%endm
; load from data stack
%macro PICKDSP 2
%if (%2 = 0)
mov %1, [ebp]
%elif ((%2 >= -128) && (%2 < 128))
mov %1, [byte ebp + %2]
%else
mov %1, [long ebp + %2]
%endif
%endm
; set data stack
%macro SETDSP 1
mov ebp, %1
%endm
; get data stack
%macro GETDSP 1
mov %1, ebp
%endm
; adjust data stack
%macro ADDDSP 1
%if ((%1 >= -128) && (%1 < 128))
add ebp, byte %1
%else
add ebp, %1
%endif
%endm
; load value onto data stack
%macro LOADTOS 1
PUSHDSP ebx
mov ebx, %1
%endm
; move from data to return stack
%macro TORSP 0
PUSHRSP ebx
POPDSP ebx
%endm
; move from return to data stack
%macro FROMRSP 0
PUSHDSP ebx
POPRSP ebx
%endm
; copy from return to data stack
%macro FETCHRSP 0
PUSHDSP ebx
PICKRSP ebx, 0
%endm
; align reg
%define DP_ALIGN 3
%macro ALIGNREG 1
add %1, byte DP_ALIGN
and %1, byte ~DP_ALIGN
%endm
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; dictionary building macros
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; format of dictionary entry flag byte
%define F_IMMED 0x80
%define F_HIDDEN 0x20
%define F_LENMASK 0x1f
%define NULL 0
%define H_LLINK 0
%define H_HLINK 4
%define H_NSIZE 8
%define H_NAME 9
%define XT_BODY -12
%define XT_LENGTH -8
%define XT_COMPILE -4
%define XT_SIZE 12
%macro defword 4
%push newword
%strlen len %1
align 4
dic_%3:
dd NULL ; LATEST list link
dd NULL ; hash chain link
db len + %2 ; flags + length byte
db %1 ; the name
dd %3 ; body pointer
dd %$code_end - %3 ; code length
dd %4 ; compile action word
%3:
%endm ; assembler code follows
%macro defword_end 0
%$code_end:
%pop
%endm
%macro defvar 4
defword %1, %2, %3, WORD_INLINE_COMMA
LOADTOS var_%3
ret
defword_end
align 4
var_%3:
dd %4
%endm
%macro defvar2 5
defword %1, %2, %3, WORD_INLINE_COMMA
LOADTOS var_%3
ret
defword_end
align 4
var_%3:
dd %4
dd %5
%endm
%macro defconst 4
defword %1, %2, %3, WORD_INLINE_COMMA
LOADTOS %4
ret
defword_end
%endm
;;;;;;;;;;;;;;;;;;;;;;;;;;
; entry point
;;;;;;;;;;;;;;;;;;;;;;;;;;
SECTION .text
global _main
_main:
; use mprotect to allow read/write/execute of the data section
mov edx, forth_start
and edx, -PAGE_SIZE ;start address
mov ecx, forth_end
sub ecx, edx ;length
mov ebx, PROT_ALL ;flags
push ebx
push ecx
push edx
push 0 ;padding
mov eax, SYS_mprotect
int 0x80
add esp, 16
jmp forth_start
SECTION .data
forth_start:
; init data and return stacks, saving initial positions
; in Forth vars R0 and S0
cld
GETRSP [var_WORD_SZ]
SETDSP [var_WORD_SZ]
ADDRSP -DATA_STACK_SIZE
GETRSP [var_WORD_RZ]
; link built in dictionary
mov esi, dictionary_start
xor edi, edi
repeat
lodsd
mov [eax + H_LLINK], edi
mov edi, eax
push esi
mov cl, [eax + H_NSIZE]
and ecx, F_LENMASK
lea esi, [eax + H_NAME]
call strhashi
and ebx, NUM_HASH_CHAINS-1
mov esi, hash_buckets
mov eax, [esi + (ebx * 4)]
mov [esi + (ebx * 4)], edi
mov [edi + H_HLINK], eax
pop esi
cmp esi, dictionary_end
until z
mov [var_WORD_LATEST], edi
; run temp interpreter loop till we can get into the real QUIT word
call WORD_LBRAC ; interpret state
LOADTOS 666q ; octal !
TORSP
LOADTOS 0
TORSP
LOADTOS bootfile
TORSP
call WORD_SYS_OPEN
call WORD_SYSCALL
ADDRSP 12
TORSP ; ( fd ) of "forth.f"
loopstart
LOADTOS tib_buffer
LOADTOS MAX_LINE_SIZE
FETCHRSP ; ( c-addr len fd )
call WORD_READLINE ; ( num flag flag )
call WORD_DROP2
LOADTOS tib_buffer
call WORD_SWAP
call WORD_INHASH
call WORD_STORE2
LOADTOS 0
call WORD_TOIN
call WORD_STORE
call WORD_INTERPRET
loopend ; and loop till QUIT takes over
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; a few case insensative string operations
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
%macro to_lower 1
; lower case check
cmp %1, 'A'
if ge
cmp %1, 'Z'
if le
; make it lower case
add %1, byte 'a' - 'A'
endif
endif
%endm
strcpyi:
test ecx, ecx
if nz
strcpyi_l1:
lodsb
to_lower al
stosb
loop strcpyi_l1
endif
ret
strcmpi:
test ecx, ecx
if nz
strcmpi_l1:
lodsb
mov bl, [edi]
lea edi, [edi + 1]
to_lower al
to_lower bl
cmp bl, al
if z
loop strcmpi_l1
endif
endif
ret
;;;;;;;;;;;;;;;
; hash function
;;;;;;;;;;;;;;;
strhashi:
mov ebx, 5381
test ecx, ecx
if nz
mov edx, 33
strhashi_l1:
lodsb
movzx eax, al
to_lower eax
imul ebx, edx
add ebx, eax
loop strhashi_l1
endif
ret
;;;;;;;;;;;;;;;;;;;
; syscall functions
;;;;;;;;;;;;;;;;;;;
_syscall:
int 0x80
if c
neg eax
endif
ret
_lsyscall:
int 0x80
if c
not eax
not edx
add eax, 1
adc edx, 0
endif
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; built in variables
; STATE Is the interpreter executing code (0) or compiling a word (non-zero)?
; LATEST Points to the latest (most recently defined) word in the dictionary.
; DP Points to the next free byte of memory. When compiling, compiled words go here.
; S0 Stores the address of the top of the parameter stack.
; R0 The address of the top of the return stack.
; BASE The current base for printing and reading numbers.
; #IN The current input buffer descriptor.
; >IN The current input offset.
; SOURCEFD The current input source file descriptor.
; BLK The current block number.
; CHARBUF Single char buffer.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
defvar "state", 0, WORD_STATE, 0
defvar "dp", 0, WORD_DP, dictionary_start
defvar "latest", 0, WORD_LATEST, 0
defvar "s0", 0, WORD_SZ, 0
defvar "r0", 0, WORD_RZ, 0
defvar "base", 0, WORD_BASE, 10
defvar2 "#IN", 0, WORD_INHASH, 0, 0
defvar ">in", 0, WORD_TOIN, 0
defvar "sourcefd", 0, WORD_SOURCEFD, 0
defvar "blk", 0, WORD_BLK, 0
defvar "charbuf", 0, WORD_CHARBUF, 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; built in constants
; VERSION The current version of this FORTH.
; WORDBUF The address of the buffer WORD uses.
; LINESIZE The line buffer size.
; F_IMMED The IMMEDIATE flag's actual value.
; F_HIDDEN The HIDDEN flag's actual value.
; F_LENMASK The length mask in the flags/len byte.
; H_NSIZE The flags/len field offset.
; H_NAME The name field offset.
; XT_BODY The xt body pointer.
; XT_LENGTH The xt length field offset.
; XT_COMPILE The xt compile field offset.
; XT_SIZE The xt size offset.
; SYS_* The numeric codes of various syscalls.
; O_* Various sycall flags/modes.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
defconst "version", 0, WORD_VERSION, VERSION_NUM
defconst "wordbuf", 0, WORD_WORDBUF, word_buf
defconst "linesize", 0, WORD_LINESIZE, MAX_LINE_SIZE
defconst "f_immed", 0, WORD__F_IMMED, F_IMMED
defconst "f_hidden", 0, WORD__F_HIDDEN, F_HIDDEN
defconst "f_lenmask", 0, WORD__F_LENMASK, F_LENMASK
defconst "h_nsize", 0, WORD__H_NSIZE, H_NSIZE
defconst "h_name", 0, WORD__H_NAME, H_NAME
defconst "xt_body", 0, WORD__XT_BODY, XT_BODY
defconst "xt_length", 0, WORD__XT_LENGTH, XT_LENGTH
defconst "xt_compile", 0, WORD__XT_COMPILE, XT_COMPILE
defconst "xt_size", 0, WORD__XT_SIZE, XT_SIZE
defconst "sys_exit", 0, WORD_SYS_EXIT, SYS_exit
defconst "sys_open", 0, WORD_SYS_OPEN, SYS_open
defconst "sys_close", 0, WORD_SYS_CLOSE, SYS_close
defconst "sys_read", 0, WORD_SYS_READ, SYS_read
defconst "sys_write", 0, WORD_SYS_WRITE, SYS_write
defconst "sys_unlink", 0, WORD_SYS_UNLINK, SYS_unlink
defconst "sys_rename", 0, WORD_SYS_RENAME, SYS_rename
defconst "sys_ftruncate", 0, WORD_SYS_FTRUNCATE, SYS_ftruncate
defconst "sys_fsync", 0, WORD_SYS_FSYNC, SYS_fsync
defconst "sys_lseek", 0, WORD_SYS_LSEEK, SYS_lseek
defconst "sys_fstat", 0, WORD_SYS_FSTAT, SYS_fstat
defconst "sys_stat", 0, WORD_SYS_STAT, SYS_stat
defconst "o_rdonly", 0, WORD_O_RDONLY, 0x0
defconst "o_wronly", 0, WORD_O_WRONLY, 0x1
defconst "o_rdwr", 0, WORD_O_RDWR, 0x2
defconst "o_creat", 0, WORD_O_CREAT, 0x100
defconst "o_excl", 0, WORD_O_EXCL, 0x200
defconst "o_trunc", 0, WORD_O_TRUNC, 0x1000
defconst "o_append", 0, WORD_O_APPEND, 0x2000
defconst "o_nonblock", 0, WORD_O_NONBLOCK, 0x4000
;;;;;;;;;;;;;;;;;;;;;;;;;;;
; data stack ordering words
;;;;;;;;;;;;;;;;;;;;;;;;;;;
defword "dsp@", 0, WORD_DSPFETCH, WORD_INLINE_COMMA
PUSHDSP ebx
GETDSP ebx
ret
defword_end
defword "dsp!", 0, WORD_DSPSTORE, WORD_INLINE_COMMA
SETDSP ebx
POPDSP ebx
ret
defword_end
defword "drop", 0, WORD_DROP, WORD_INLINE_COMMA
POPDSP ebx
ret
defword_end
defword "swap", 0, WORD_SWAP, WORD_INLINE_COMMA
xchg ebx, [ebp]
ret
defword_end
defword "dup", 0, WORD_DUP, WORD_INLINE_COMMA
PUSHDSP ebx
ret
defword_end
defword "over", 0, WORD_OVER, WORD_INLINE_COMMA
PUSHDSP ebx
PICKDSP ebx, 4
ret
defword_end
defword "rot", 0, WORD_ROT, WORD_INLINE_COMMA
mov eax, ebx
PICKDSP ecx, 0
PICKDSP ebx, 4
PUTDSP eax, 0
PUTDSP ecx, 4
ret
defword_end
defword "-rot", 0, WORD_NROT, WORD_INLINE_COMMA
mov eax, ebx
PICKDSP ebx, 0
PICKDSP ecx, 4
PUTDSP ecx, 0
PUTDSP eax, 4
ret
defword_end
defword "2drop", 0, WORD_DROP2, WORD_INLINE_COMMA
PICKDSP ebx, 4
ADDDSP 8
ret
defword_end
defword "2dup", 0, WORD_DUP2, WORD_INLINE_COMMA
PICKDSP eax, 0
ADDDSP -8
PUTDSP eax, 0
PUTDSP ebx, 4
ret
defword_end
defword "2swap", 0, WORD_SWAP2, WORD_INLINE_COMMA
mov eax, ebx
PICKDSP ecx, 0
PICKDSP ebx, 4
PICKDSP edx, 8
PUTDSP edx, 0
PUTDSP eax, 4
PUTDSP ecx, 8
ret
defword_end
defword "2rot", 0, WORD_ROT2, WORD_INLINE_COMMA
mov eax, ebx
PICKDSP ecx, 16
PICKDSP ebx, 12
PICKDSP edx, 8
PICKDSP edi, 4
PICKDSP esi, 0
PUTDSP edx, 16
PUTDSP edi, 12
PUTDSP esi, 8
PUTDSP eax, 4
PUTDSP ecx, 0
ret
defword_end
defword "?dup", 0, WORD_QDUP, WORD_INLINE_COMMA
test ebx, ebx
if nz
PUSHDSP ebx
endif
ret
defword_end
defword "!?dup", 0, WORD_NQDUP, WORD_INLINE_COMMA
test ebx, ebx
if z
PUSHDSP ebx
endif
ret
defword_end
defword "nip", 0, WORD_NIP, WORD_INLINE_COMMA
ADDDSP 4
ret
defword_end
defword "tuck", 0, WORD_TUCK, WORD_INLINE_COMMA
PICKDSP eax, 0
PUTDSP ebx, 0
PUSHDSP eax
ret
defword_end
defword "pick", 0, WORD_PICK, WORD_INLINE_COMMA
mov ebx, [ebp + (ebx * 4)]
ret
defword_end
defword "2tuck", 0, WORD_TUCK2, WORD_INLINE_COMMA
PICKDSP eax, 0
PICKDSP ecx, 4
PICKDSP edx, 8
ADDDSP -8
PUTDSP eax, 0
PUTDSP ecx, 4
PUTDSP edx, 8
PUTDSP ebx, 12
PUTDSP eax, 16
ret
defword_end
defword "2nip", 0, WORD_NIP2, WORD_INLINE_COMMA
PICKDSP eax, 0
ADDDSP 8
PUTDSP eax, 0
ret
defword_end
defword "2over", 0, WORD_OVER2, WORD_INLINE_COMMA
ADDDSP -8
PUTDSP ebx, 4
PICKDSP ebx, 16
PUTDSP ebx, 0
PICKDSP ebx, 12
ret
defword_end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; return stack ordering words
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
defword ">r", 0, WORD_TOR, WORD_INLINE_COMMA
TORSP
ret
defword_end
defword "r>", 0, WORD_FROMR, WORD_INLINE_COMMA
FROMRSP
ret
defword_end
defword "2>r", 0, WORD_TOR2, WORD_INLINE_COMMA
ADDRSP -8
PICKDSP ecx, 0
PUTRSP ebx, 0
PUTRSP ecx, 4
PICKDSP ebx, 4
ADDDSP 8
ret
defword_end
defword "2r>", 0, WORD_FROMR2, WORD_INLINE_COMMA
ADDDSP -8
PUTDSP ebx, 4
PICKRSP ebx, 0
PICKRSP ecx, 4
PUTDSP ecx, 0
ADDRSP 8
ret
defword_end
defword "rsp@", 0, WORD_RSPFETCH, WORD_INLINE_COMMA
PUSHDSP ebx
GETRSP ebx
ret
defword_end
defword "r@", 0, WORD_RFETCH, WORD_INLINE_COMMA
PUSHDSP ebx
PICKRSP ebx, 0
ret
defword_end
defword "r!", 0, WORD_RSTORE, WORD_INLINE_COMMA
PUTRSP ebx, 0
POPDSP ebx
ret
defword_end
defword "2r@", 0, WORD_RFETCH2, WORD_INLINE_COMMA
ADDDSP -8
PUTDSP ebx, 4
PICKRSP ebx, 4
PICKRSP ecx, 0
PUTDSP ecx, 0
ret
defword_end
defword "rsp!", 0, WORD_RSPSTORE, WORD_INLINE_COMMA
SETRSP ebx
POPDSP ebx
ret
defword_end
defword "rdrop", 0, WORD_RDROP, WORD_INLINE_COMMA
ADDRSP 4
ret
defword_end
defword "2rdrop", 0, WORD_RDROP2, WORD_INLINE_COMMA
ADDRSP 8
ret
defword_end
defword "n>r", 0, WORD_NTOR, WORD_CALL_COMMA
PUSHDSP ebx
PICKRSP eax, 0
mov ecx, ebx
inc ecx
neg ebx
lea esp, [esp + (ebx * 4)]
mov esi, ebp
mov edi, esp
rep movsd
mov ebp, esi
POPDSP ebx
jmp eax
defword_end
defword "nr>", 0, WORD_NFROMR, WORD_CALL_COMMA
PUSHDSP ebx
POPRSP eax
PICKRSP ebx, 0
inc ebx
mov ecx, ebx
neg ebx
lea ebp, [ebp + (ebx * 4)]
mov esi, esp
mov edi, ebp
rep movsd
mov esp, esi
POPDSP ebx
jmp eax
defword_end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; memory fetch and store words
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
defword "!", 0, WORD_STORE, WORD_INLINE_COMMA
PICKDSP eax, 0
mov [ebx], eax
PICKDSP ebx, 4
ADDDSP 8
ret
defword_end
defword "@", 0, WORD_FETCH, WORD_INLINE_COMMA
mov ebx, [ebx]
ret
defword_end
defword "+!", 0, WORD_ADDSTORE, WORD_INLINE_COMMA
PICKDSP eax, 0
add [ebx], eax
PICKDSP ebx, 4
ADDDSP 8
ret
defword_end
defword "-!", 0, WORD_SUBSTORE, WORD_INLINE_COMMA
PICKDSP eax, 0
sub [ebx], eax
PICKDSP ebx, 4
ADDDSP 8
ret
defword_end
defword "c!", 0, WORD_STOREBYTE, WORD_INLINE_COMMA
PICKDSP eax, 0
mov [ebx], al
PICKDSP ebx, 4
ADDDSP 8
ret
defword_end
defword "c+!", 0, WORD_ADDBYTE, WORD_INLINE_COMMA
PICKDSP eax, 0
add [ebx], al
PICKDSP ebx, 4
ADDDSP 8
ret
defword_end
defword "c@", 0, WORD_FETCHBYTE, WORD_INLINE_COMMA
mov eax, ebx
xor ebx, ebx
mov bl, [eax]
ret
defword_end
defword "w!", 0, WORD_STORESHORT, WORD_INLINE_COMMA
PICKDSP eax, 0
mov [ebx], ax
PICKDSP ebx, 4
ADDDSP 8
ret
defword_end
defword "w@", 0, WORD_FETCHSHORT, WORD_INLINE_COMMA
mov eax, ebx
xor ebx, ebx
mov bx, [eax]
ret
defword_end
defword "2!", 0, WORD_STORE2, WORD_INLINE_COMMA
PICKDSP ecx, 4
PICKDSP edx, 0
mov [ebx + 4], ecx
mov [ebx], edx
PICKDSP ebx, 8
ADDDSP 12
ret
defword_end
defword "2@", 0, WORD_FETCH2, WORD_INLINE_COMMA
ADDDSP -4
mov ecx, [ebx +4]
mov ebx, [ebx]
PUTDSP ecx, 0
ret
defword_end
defword "blank", 0, WORD_BLANK, WORD_CALL_COMMA
mov ecx, ebx
PICKDSP ebx, 4
PICKDSP edi, 0
ADDDSP 8
mov eax, 0x20
rep stosb
ret
defword_end
defword "erase", 0, WORD_ERASE, WORD_CALL_COMMA
mov ecx, ebx
PICKDSP ebx, 4
PICKDSP edi, 0
ADDDSP 8
xor eax, eax
rep stosb
ret
defword_end
defword "fill", 0, WORD_FILL, WORD_CALL_COMMA
mov eax, ebx
PICKDSP ebx, 8
PICKDSP edi, 4
PICKDSP ecx, 0
ADDDSP 12
rep stosb
ret
defword_end
defword "cmove>", 0, WORD_CMOVEB, WORD_CALL_COMMA
mov ecx, ebx
PICKDSP ebx, 8
PICKDSP esi, 4
PICKDSP edi, 0
ADDDSP 12
lea esi, [esi + ecx - 1]
lea edi, [edi + ecx - 1]
std
rep movsb
cld
ret
defword_end
defword "cmove", 0, WORD_CMOVE, WORD_CALL_COMMA
mov ecx, ebx
PICKDSP ebx, 8
PICKDSP esi, 4
PICKDSP edi, 0
ADDDSP 12
rep movsb
ret
defword_end
defword "move", 0, WORD_MOVE, WORD_CALL_COMMA
mov ecx, ebx
PICKDSP ebx, 8
PICKDSP esi, 4
PICKDSP edi, 0
ADDDSP 12
cmp esi, edi
if a
rep movsb
else
lea esi, [esi + ecx -1]
lea edi, [edi + ecx -1]
std
rep movsb
cld
endif
ret
defword_end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; single precision alu words
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
defword "+", 0, WORD_ADD, WORD_INLINE_COMMA
add ebx, [ebp]
ADDDSP 4
ret
defword_end
defword "-", 0, WORD_SUB, WORD_INLINE_COMMA
mov eax, ebx
POPDSP ebx
sub ebx, eax
ret
defword_end
defword "*", 0, WORD_MULL, WORD_INLINE_COMMA
imul ebx, [ebp]
ADDDSP 4
ret
defword_end
defword "/", 0, WORD_DIV, WORD_INLINE_COMMA
POPDSP eax
cdq
idiv ebx
mov ebx, eax
ret
defword_end
defword "mod", 0, WORD_MOD, WORD_INLINE_COMMA
POPDSP eax
cdq
idiv ebx
mov ebx, edx
ret
defword_end
defword "1+", 0, WORD_INCR, WORD_INLINE_COMMA
add ebx, byte 1
ret
defword_end
defword "1-", 0, WORD_DECR, WORD_INLINE_COMMA
sub ebx, byte 1
ret
defword_end
defword "4+", 0, WORD_INCR4, WORD_INLINE_COMMA
add ebx, byte 4
ret
defword_end
defword "4-", 0, WORD_DECR4, WORD_INLINE_COMMA
sub ebx, byte 4
ret
defword_end
defword "2+", 0, WORD_INCR2, WORD_INLINE_COMMA
add ebx, byte 2
ret
defword_end
defword "2-", 0, WORD_DECR2, WORD_INLINE_COMMA
sub ebx, byte 2
ret
defword_end
defword "2*", 0, WORD_TWOMUL, WORD_INLINE_COMMA
shl ebx, byte 1
ret
defword_end
defword "2/", 0, WORD_TWODIV, WORD_INLINE_COMMA
sar ebx, byte 1
ret
defword_end
defword "abs", 0, WORD_ABS, WORD_INLINE_COMMA
mov eax, ebx
sar eax, byte 31
add ebx, eax
xor ebx, eax
ret
defword_end
defword "min", 0, WORD_MIN, WORD_INLINE_COMMA
POPDSP eax
cmp ebx, eax
if g
mov ebx, eax
endif
ret
defword_end
defword "max", 0, WORD_MAX, WORD_INLINE_COMMA
POPDSP eax
cmp ebx, eax
if l
mov ebx, eax
endif
ret
defword_end
defword "lshift", 0, WORD_LSHIFT, WORD_INLINE_COMMA
mov ecx, ebx
POPDSP ebx
shl ebx, cl
ret
defword_end
defword "rshift", 0, WORD_RSHIFT, WORD_INLINE_COMMA
mov ecx, ebx
POPDSP ebx
shr ebx, cl
ret
defword_end
defword "and", 0, WORD_AND, WORD_INLINE_COMMA
and ebx, [ebp]
ADDDSP 4
ret
defword_end
defword "or", 0, WORD_OR, WORD_INLINE_COMMA
or ebx, [ebp]
ADDDSP 4
ret
defword_end
defword "xor", 0, WORD_XOR, WORD_INLINE_COMMA
xor ebx, [ebp]
ADDDSP 4
ret
defword_end
defword "negate", 0, WORD_NEGATE, WORD_INLINE_COMMA
neg ebx
ret
defword_end
defword "invert", 0, WORD_INVERT, WORD_INLINE_COMMA
not ebx
ret
defword_end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; single precision comparision words
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
defword "=", 0, WORD_EQ, WORD_INLINE_COMMA
cmp [ebp], ebx
sete bl
ADDDSP 4
movzx ebx, bl
neg ebx
ret
defword_end
defword "<>", 0, WORD_NE, WORD_INLINE_COMMA
cmp [ebp], ebx
setne bl
ADDDSP 4
movzx ebx, bl
neg ebx
ret
defword_end
defword "<", 0, WORD_LT, WORD_INLINE_COMMA
cmp [ebp], ebx
setl bl
ADDDSP 4
movzx ebx, bl
neg ebx
ret
defword_end
defword ">", 0, WORD_GT, WORD_INLINE_COMMA
cmp [ebp], ebx
setg bl
ADDDSP 4
movzx ebx, bl
neg ebx
ret
defword_end
defword "u<", 0, WORD_ULT, WORD_INLINE_COMMA
cmp [ebp], ebx
setb bl
ADDDSP 4
movzx ebx, bl
neg ebx
ret
defword_end
defword "u>", 0, WORD_UGT, WORD_INLINE_COMMA
cmp [ebp], ebx
seta bl
ADDDSP 4
movzx ebx, bl
neg ebx
ret
defword_end
defword "u<=", 0, WORD_ULTEQ, WORD_INLINE_COMMA
cmp [ebp], ebx
setbe bl
ADDDSP 4
movzx ebx, bl
neg ebx
ret
defword_end
defword "u>=", 0, WORD_UGTEQ, WORD_INLINE_COMMA
cmp [ebp], ebx
setae bl
ADDDSP 4
movzx ebx, bl
neg ebx
ret
defword_end
defword "<=", 0, WORD_LTEQ, WORD_INLINE_COMMA
cmp [ebp], ebx
setle bl
ADDDSP 4
movzx ebx, bl
neg ebx
ret
defword_end
defword ">=", 0, WORD_GTEQ, WORD_INLINE_COMMA
cmp [ebp], ebx
setge bl
ADDDSP 4
movzx ebx, bl
neg ebx
ret
defword_end
defword "0=", 0, WORD_ZEQ, WORD_INLINE_COMMA
test ebx, ebx
setz bl
movzx ebx, bl
neg ebx
ret
defword_end
defword "0<>", 0, WORD_ZNE, WORD_INLINE_COMMA
test ebx, ebx
setnz bl
movzx ebx, bl
neg ebx
ret
defword_end
defword "0<", 0, WORD_ZLT, WORD_INLINE_COMMA
test ebx, ebx
setl bl
movzx ebx, bl
neg ebx
ret
defword_end
defword "0>", 0, WORD_ZGT, WORD_INLINE_COMMA
test ebx, ebx
setg bl
movzx ebx, bl
neg ebx
ret
defword_end
defword "0<=", 0, WORD_ZLTEQ, WORD_INLINE_COMMA
test ebx, ebx
setle bl
movzx ebx, bl
neg ebx
ret
defword_end
defword "0>=", 0, WORD_ZGTEQ, WORD_INLINE_COMMA
test ebx, ebx
setge bl
movzx ebx, bl
neg ebx
ret
defword_end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; double precision ALU words
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
defword "s>d", 0, WORD_STOD, WORD_INLINE_COMMA
mov eax, ebx
cdq
PUSHDSP eax
mov ebx, edx
ret
defword_end
defword "d>s", 0, WORD_DTOS, WORD_INLINE_COMMA
POPDSP ebx
ret
defword_end
defword "d+", 0, WORD_DPLUS, WORD_INLINE_COMMA
PICKDSP ecx, 8
PICKDSP edx, 4
PICKDSP eax, 0
add eax, ecx
adc ebx, edx
PUTDSP eax, 8
ADDDSP 8
ret
defword_end
defword "d-", 0, WORD_DMINUS, WORD_INLINE_COMMA
PICKDSP ecx, 8
PICKDSP edx, 4
PICKDSP eax, 0
sub ecx, eax
sbb edx, ebx
PUTDSP ecx, 8
mov ebx, edx
ADDDSP 8
ret
defword_end
defword "d2*", 0, WORD_D2STAR, WORD_INLINE_COMMA
PICKDSP eax, 0
shl eax, 1
rcl ebx, 1
PUTDSP eax, 0
ret
defword_end
defword "d2/", 0, WORD_D2SLASH, WORD_INLINE_COMMA
PICKDSP eax, 0
sar ebx, 1
rcr eax, 1
PUTDSP eax, 0
ret
defword_end
defword "*/", 0, WORD_MULDIV, WORD_INLINE_COMMA
PICKDSP edx, 4
PICKDSP eax, 0
imul edx
idiv ebx
mov ebx, eax
ADDDSP 8
ret
defword_end
defword "*/mod", 0, WORD_STARSMOD, WORD_INLINE_COMMA
PICKDSP edx, 4
PICKDSP eax, 0
imul edx
idiv ebx
PUTDSP edx, 4
ADDDSP 4
mov ebx, eax
ret
defword_end
defword "/mod", 0, WORD_DIVMOD, WORD_INLINE_COMMA
PICKDSP eax, 0
cdq
idiv ebx
PUTDSP edx, 0
mov ebx, eax
ret
defword_end
defword "dnegate", 0, WORD_DNEGATE, WORD_INLINE_COMMA
PICKDSP eax, 0
not eax
not ebx
add eax, 1
adc ebx, 0
PUTDSP eax, 0
ret
defword_end
defword "dabs", 0, WORD_DABS, WORD_INLINE_COMMA
test ebx, ebx
if l
PICKDSP eax, 0
not eax
not ebx
add eax, 1
adc ebx, 0
PUTDSP eax, 0
endif
ret
defword_end
defword "dmax", 0, WORD_DMAX, WORD_INLINE_COMMA
PICKDSP ecx, 8
PICKDSP edx, 4
PICKDSP eax, 0
ADDDSP 8
mov esi, ecx
mov edi, edx
sub esi, eax
sbb edi, ebx
if l
PUTDSP eax, 0
else
mov ebx, edx
endif
ret
defword_end
defword "dmin", 0, WORD_DMIN, WORD_INLINE_COMMA
PICKDSP ecx, 8
PICKDSP edx, 4
PICKDSP eax, 0
ADDDSP 8
mov esi, ecx
mov edi, edx
sub esi, eax
sbb edi, ebx
if ge
PUTDSP eax, 0
else
mov ebx, edx
endif
ret
defword_end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; double precision comparision words
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
defword "d0=", 0, WORD_DZEQ, WORD_INLINE_COMMA
or ebx, [ebp]
setz bl
ADDDSP 4
movzx ebx, bl
neg ebx
ret
defword_end
defword "d0<>", 0, WORD_DZNEQ, WORD_INLINE_COMMA
or ebx, [ebp]
setnz bl
ADDDSP 4
movzx ebx, bl
neg ebx
ret
defword_end
defword "d0<", 0, WORD_DZLT, WORD_INLINE_COMMA
test ebx, ebx
setl bl
ADDDSP 4
movzx ebx, bl
neg ebx
ret
defword_end
defword "d=", 0, WORD_DEQ, WORD_INLINE_COMMA
PICKDSP ecx, 8
PICKDSP eax, 4
sub ecx, [ebp]
sbb eax, ebx
setz bl
ADDDSP 12
movzx ebx, bl
neg ebx
ret
defword_end
defword "d<>", 0, WORD_DNEQ, WORD_INLINE_COMMA
PICKDSP ecx, 8
PICKDSP eax, 4
sub ecx, [ebp]
sbb eax, ebx
setnz bl
ADDDSP 12
movzx ebx, bl
neg ebx
ret
defword_end
defword "d<", 0, WORD_DLT, WORD_INLINE_COMMA
PICKDSP ecx, 8
PICKDSP eax, 4
sub ecx, [ebp]
sbb eax, ebx
setl bl
ADDDSP 12
movzx ebx, bl
neg ebx
ret
defword_end
defword "du<", 0, WORD_DULT, WORD_INLINE_COMMA
PICKDSP ecx, 8
PICKDSP eax, 4
sub ecx, [ebp]
sbb eax, ebx
setb bl
ADDDSP 12
movzx ebx, bl
neg ebx
ret
defword_end
;;;;;;;;;;;;;;;;;;;;;;;
; mixed precision words
;;;;;;;;;;;;;;;;;;;;;;;
defword "m+", 0, WORD_MPLUS, WORD_INLINE_COMMA
PICKDSP eax, 4
PICKDSP edx, 0
add eax, ebx
adc edx, 0
PUTDSP eax, 4
mov ebx, edx
ADDDSP 4
ret
defword_end
defword "m-", 0, WORD_MMINUS, WORD_INLINE_COMMA
PICKDSP eax, 4
PICKDSP edx, 0
sub eax, ebx
sbb edx, 0
PUTDSP eax, 4
mov ebx, edx
ADDDSP 4
ret
defword_end
defword "m*", 0, WORD_MULSTAR, WORD_INLINE_COMMA
PICKDSP eax, 0
imul ebx
PUTDSP eax, 0
mov ebx, edx
ret
defword_end
defword "m/", 0, WORD_MSLASH, WORD_INLINE_COMMA
PICKDSP eax, 4
PICKDSP edx, 0
idiv ebx
mov ebx, eax
ADDDSP 8
ret
defword_end
defword "um*", 0, WORD_UMULSTAR, WORD_INLINE_COMMA
PICKDSP eax, 0
mul ebx
PUTDSP eax, 0
mov ebx, edx
ret
defword_end
defword "um/mod", 0, WORD_UMDIVMOD, WORD_INLINE_COMMA
PICKDSP eax, 4
PICKDSP edx, 0
div ebx
PUTDSP edx, 4
mov ebx, eax
ADDDSP 4
ret
defword_end
defword "fm/mod", 0, WORD_FMDIVMOD, WORD_INLINE_COMMA
PICKDSP edx, 0
PICKDSP eax, 4
mov ecx, ebx
ADDDSP 4
xor ecx, edx
idiv ebx
test ecx, ecx
if s
test edx, edx
if nz
dec eax
add edx, ebx
endif
endif
PUTDSP edx, 0
mov ebx, eax
ret
defword_end
defword "sm/rem", 0, WORD_SMDIVREM, WORD_INLINE_COMMA
PICKDSP eax, 4
PICKDSP edx, 0
idiv ebx
PUTDSP edx, 4
mov ebx, eax
ADDDSP 4
ret
defword_end
defword "u/mod", 0, WORD_UDIVMOD, WORD_INLINE_COMMA
xor edx, edx
PICKDSP eax, 0
div ebx
PUTDSP edx, 0
mov ebx, eax
ret
defword_end
defword "dm*", 0, WORD_DMULSTAR, WORD_CALL_COMMA
call WORD_TUCK
call WORD_MULL
TORSP
call WORD_UMULSTAR
FROMRSP
call WORD_ADD
ret
defword_end
;;;;;;;;;;;;;;;;;;;;
; control flow words
;;;;;;;;;;;;;;;;;;;;
defword "branch", 0, WORD_BRANCH, WORD_INLINE_COMMA
i_jmp:
jmp strict near i_ret
ret
defword_end
defword "0branch", 0, WORD_ZBRANCH, WORD_INLINE_COMMA
mov eax, ebx
POPDSP ebx
test eax, eax
jz strict near i_jmp
ret
defword_end
defword "exit", 0, WORD_EXIT, WORD_EXIT_COMMA
i_ret:
ret
defword_end
defword "exit,", 0, WORD_EXIT_COMMA, WORD_CALL_COMMA
mov edi, [var_WORD_DP]
sub edi, 5
cmp edi, [lastcall] ; are we just after a call instruction ?
if z
mov al, [i_jmp]
mov [edi], al ; change it to a jmp
endif
mov edi, [var_WORD_DP]
mov al, [i_ret]
stosb
mov [var_WORD_DP], edi
POPDSP ebx
ret
defword_end
defword "execute", 0, WORD_EXECUTE, WORD_CALL_COMMA
mov eax, ebx ; Get xt into eax
POPDSP ebx ; After xt runs its ret will continue executing the current word.
jmp eax ; and jump to it.
defword_end
;;;;;;;;;;;;;;;;;;;;;;;;;;
; terminal input words
;;;;;;;;;;;;;;;;;;;;;;;;;;
defword "read-char", 0, WORD_READCHAR, WORD_CALL_COMMA
mov ecx, var_WORD_CHARBUF ; 2nd param: buffer
mov edx, 1 ; 3rd param: max length
push edx
push ecx
push ebx
mov eax, SYS_read ; syscall: read
call _syscall
add esp, 12
xor ebx, ebx
test eax, eax
if be
mov ebx, -1
endif
ret
defword_end
defword "read-line", 0, WORD_READLINE, WORD_CALL_COMMA
call WORD_NROT
call WORD_OVER
call WORD_ADD
call WORD_OVER ; ( fd start end cur )
readline_l1:
PICKDSP eax, 0
cmp ebx, eax
jz readline_l4
PUSHDSP ebx
PICKDSP ebx, 12
call WORD_READCHAR
test ebx, ebx
jz readline_l2
call WORD_DROP
call WORD_DROP2
call WORD_DROP2
LOADTOS 0
LOADTOS 0
LOADTOS -1
jmp readline_l5
readline_l2:
mov ebx, [var_WORD_CHARBUF]
cmp ebx, 10 ; LF
jz readline_l3
call WORD_OVER
call WORD_STOREBYTE
call WORD_INCR
jmp readline_l1
readline_l3:
call WORD_DROP
readline_l4:
call WORD_NIP
call WORD_SWAP
call WORD_SUB
call WORD_NIP
LOADTOS -1
LOADTOS 0
readline_l5:
ret
defword_end
defword "key", 0, WORD_KEY, WORD_CALL_COMMA
PUSHDSP ebx
xor ebx, ebx ; stdin
call WORD_READCHAR
mov ebx, [var_WORD_CHARBUF]
ret
defword_end
defword "accept", 0, WORD_ACCEPT, WORD_CALL_COMMA
call WORD_OVER
call WORD_ADD
call WORD_OVER ; ( start end cur )
accept_l1:
call WORD_KEY
cmp ebx, 127 ; BS
jz accept_l2
cmp ebx, 10 ; LF
jz accept_l3
call WORD_OVER ; ( start end cur key cur )
call WORD_STOREBYTE
call WORD_INCR ; ( start end cur' )
PICKDSP eax, 0
cmp ebx, eax
jz accept_l4
jmp accept_l1
accept_l2:
PICKDSP eax, 4 ; ( start end cur' )
cmp ebx, eax
jz accept_l1
call WORD_DECR
jmp accept_l1
accept_l3:
call WORD_DROP ; ( start end cur' )
accept_l4:
call WORD_NIP
call WORD_SWAP
call WORD_SUB
ret
defword_end
defword "tabs>spaces", 0, WORD_TABSTOSPACES, WORD_CALL_COMMA
mov ecx, ebx
POPDSP esi
test ecx, ecx
if nz
repeat
lodsb
cmp al, 9 ;TAB
if z
mov byte [esi - 1], ' '
endif
dec ecx
until z
endif
POPDSP ebx
ret
defword_end
;;;;;;;;;;;;;;;;;;;;;;;
; terminal output words
;;;;;;;;;;;;;;;;;;;;;;;
defword "type-fd", 0, WORD_TYPE_FD, WORD_CALL_COMMA
PICKDSP edx, 0 ; 3rd param: length of string
PICKDSP ecx, 4 ; 2nd param: address of string
ADDDSP 8 ; 1st param: FD in ebx
mov eax, SYS_write ; write syscall
push edx
push ecx
push ebx
call _syscall
add esp, 12
POPDSP ebx
ret
defword_end
defword "type", 0, WORD_TYPE, WORD_CALL_COMMA
LOADTOS 1 ; stdout
call WORD_TYPE_FD
ret
defword_end
defword "emit", 0, WORD_EMIT, WORD_CALL_COMMA
mov [emit_scratch], bl ; write needs the address of the byte to write
mov ebx, emit_scratch
LOADTOS 1
call WORD_TYPE
ret
defword_end
;;;;;;;;;;;;;;;;;;;
; system call words
;;;;;;;;;;;;;;;;;;;
defword "syscall", 0, WORD_SYSCALL, WORD_CALL_COMMA
pop eax
mov [syscallret], eax ; save return address
mov eax, ebx ; System call number (see <asm/unistd.h>)
call _syscall
mov ebx, eax ; Result (negative for -errno)
jmp [syscallret] ; return to caller
defword_end
defword "lsyscall", 0, WORD_LSYSCALL, WORD_CALL_COMMA
pop eax
mov [syscallret], eax ; save return address
mov eax, ebx ; System call number (see <asm/unistd.h>)
call _lsyscall
PUSHDSP eax
mov ebx, edx ; Result (negative for -errno)
jmp [syscallret] ; return to caller
defword_end
;;;;;;;;;;;;;;
; string words
;;;;;;;;;;;;;;
defword "count", 0, WORD_COUNT, WORD_CALL_COMMA
xor eax, eax
mov al, [ebx]
inc ebx
LOADTOS eax
ret
defword_end
defword "-trailing", 0, WORD_TRAILING, WORD_CALL_COMMA
test ebx, ebx
if nz
PICKDSP esi, 0
mov ecx, ebx
add esi, ebx
dec esi
std
trailing_l1:
lodsb
cmp al, ' '
if be
loop trailing_l1
endif
mov ebx, ecx
cld
endif
ret
defword_end
defword "/string", 0, WORD_SSTRING, WORD_CALL_COMMA
mov eax, ebx
POPDSP ebx
PICKDSP ecx, 0
sub ebx, eax
add ecx, eax
PUTDSP ecx, 0
ret
defword_end
defword "compare", 0, WORD_COMPARE, WORD_CALL_COMMA
PICKDSP esi, 8
PICKDSP edx, 4
PICKDSP edi, 0
ADDDSP 12
mov ecx, ebx
cmp edx, ebx
if be
mov ecx, edx
endif
test ecx, ecx ; ecx lowest length
jnz compare_l2
cmp edx, ebx
jz compare_l3 ; both are 0 length
jmp compare_l4 ; otherwise the longest wins
compare_l2:
cmpsb
jnz compare_l4 ; chars not same
loop compare_l2
cmp edx, ebx ; all chars same
jnz compare_l4 ; strings not same size
compare_l3:
xor ebx, ebx ; same
jmp compare_l7
compare_l4:
ja compare_l6
compare_l5:
mov ebx, -1
jmp compare_l7
compare_l6:
mov ebx, 1
compare_l7:
ret
defword_end
defword "icompare", 0, WORD_COMPAREI, WORD_CALL_COMMA
PICKDSP esi, 8
PICKDSP edx, 4
PICKDSP edi, 0
ADDDSP 12
mov ecx, ebx
cmp edx, ebx
if be
mov ecx, edx
endif
test ecx, ecx ; ecx lowest length
jnz comparei_l2
cmp edx, ebx
jz comparei_l3 ; both are 0 length
jmp comparei_l4 ; otherwise the longest wins
comparei_l2:
mov al, [esi]
mov ah, [edi]
to_lower al
to_lower ah
cmp ah, al
jnz comparei_l4 ; chars not same
inc edi
inc esi
loop comparei_l2
cmp edx, ebx ; all chars same
jnz comparei_l4 ; strings not same size
comparei_l3:
xor ebx, ebx ; same
jmp comparei_l7
comparei_l4:
ja comparei_l6
comparei_l5:
mov ebx, -1
jmp comparei_l7
comparei_l6:
mov ebx, 1
comparei_l7:
ret
defword_end
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; dictionary searching words
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
defword "find", 0, WORD_FIND, WORD_CALL_COMMA
call WORD_DUP
call WORD_COUNT
call WORD_FIND_DICT
test ebx, ebx
if nz
mov dl, [ebx + H_NSIZE]
call WORD_TCFA
LOADTOS 1
and edx, F_IMMED
if z
neg ebx
endif
call WORD_ROT
call WORD_DROP
endif
ret
defword_end
defword "(find)", 0, WORD_FIND_DICT, WORD_CALL_COMMA
mov ecx, ebx ; ecx = length
POPDSP edi ; edi = address
PUSHRSP ecx
mov esi, edi
call strhashi
and ebx, NUM_HASH_CHAINS-1
mov esi, hash_buckets
mov edx, [esi + (ebx * 4)]
POPRSP ecx ; edx can now scan back through this hash chain
findd_l1:
test edx, edx ; NULL pointer? (end of the linked list)
je findd_l4
xor eax, eax
mov al, [edx + H_NSIZE] ; al = flags+length field
and al, (F_HIDDEN|F_LENMASK) ; al = name length
cmp al, cl ; Length is the same?
jne findd_l2
PUSHRSP ecx ; Save the length
PUSHRSP edi ; Save the address (repe cmpsb will move this pointer)
lea esi, [edx + H_NAME] ; Dictionary string we are checking against.
call strcmpi
POPRSP edi
POPRSP ecx
jne findd_l2 ; Not the same.
mov ebx, edx
ret
findd_l2:
mov edx, [edx + H_HLINK] ; Move back through the link field to the previous word
jmp findd_l1 ; .. and loop.
findd_l4:
xor ebx, ebx ; Return zero to indicate not found.
ret
defword_end
defword ">cfa", 0, WORD_TCFA, WORD_CALL_COMMA
add ebx, H_NSIZE
mov al, [ebx] ; Load flags+len into al.
inc ebx ; skip flags+len byte.
and eax, F_LENMASK ; Just the length, not the flags.
add ebx, eax ; skip the name
add ebx, XT_SIZE ; skip to the xt
ret
defword_end
defword "(bucket)", 0, WORD_BUCKET, WORD_CALL_COMMA
mov ecx, ebx ; ecx = length
POPDSP ebx ; ebx = address of name
PUSHRSP esi
mov esi, ebx
call strhashi
and ebx, NUM_HASH_CHAINS-1
mov esi, hash_buckets
lea ebx, [esi + (ebx * 4)]
POPRSP esi
ret
defword_end
defword "unused", 0, WORD_UNUSED, WORD_CALL_COMMA
LOADTOS forth_end
LOADTOS [var_WORD_DP]
call WORD_SUB
ret
defword_end
;;;;;;;;;;;;;;;;;;;;;;;;;;;
; dictionary building words
;;;;;;;;;;;;;;;;;;;;;;;;;;;
defword "align", 0, WORD_ALIGNDP, WORD_CALL_COMMA
mov eax, [var_WORD_DP]
ALIGNREG eax
mov [var_WORD_DP], eax
ret
defword_end
defword "header,", 0, WORD_HEADER_COMMA, WORD_CALL_COMMA
mov ecx, ebx ; ecx = length
POPDSP ebx ; ebx = address of name
call WORD_ALIGNDP ; align header
mov edi, [var_WORD_DP] ; edi is the address of the header
mov eax, [var_WORD_LATEST] ; Get link pointer
mov [edi + H_LLINK], eax ; and store it in the header.
mov [var_WORD_LATEST], edi
PUSHRSP ebx ; hash chain
PUSHRSP ecx
mov esi, ebx
call strhashi
and ebx, NUM_HASH_CHAINS-1
mov esi, hash_buckets
mov eax, [esi + (ebx * 4)]
mov [esi + (ebx * 4)], edi
mov [edi + H_HLINK], eax ; and store it in the header.
POPRSP ecx
POPRSP esi
mov [edi + H_NSIZE], cl ; Store the length/flags byte.
add edi, H_NAME
call strcpyi
mov ecx, XT_SIZE
xor eax, eax
rep stosb ; clear the gap till the xt
mov [var_WORD_DP], edi
mov long [edi + XT_COMPILE], WORD_CALL_COMMA ;compile action
POPDSP ebx
ret
defword_end
defword "lit,", 0, WORD_LIT_COMMA, WORD_CALL_COMMA
mov esi, litc_l1
mov edi, [var_WORD_DP]
mov ecx, litc_l2 - litc_l1 - 4
rep movsb
mov [var_WORD_DP], edi
ret
defword_end
litc_l1:
LOADTOS 0xBAADF00D
litc_l2:
defword "slits", 0, WORD_SLITS, WORD_CALL_COMMA
PUSHDSP ebx
POPRSP esi
xor eax, eax
lodsb ; get the length of the string
PUSHDSP esi ; push the address of the start of the string
mov ebx, eax ; push length on the stack
add esi, eax ; skip past the string
jmp esi
defword_end
defword "clits", 0, WORD_CLITS, WORD_CALL_COMMA
FROMRSP
xor eax, eax
mov al, [ebx]
lea eax, [ebx + eax + 1]
jmp eax
defword_end
defword ",", 0, WORD_COMMA, WORD_CALL_COMMA
mov edi, [var_WORD_DP] ; DP
mov eax, ebx
stosd ; Store it.
mov [var_WORD_DP], edi ; Update DP (incremented)
POPDSP ebx
ret
defword_end
defword "c,", 0, WORD_CHAR_COMMA, WORD_CALL_COMMA
mov eax, ebx
mov edi, [var_WORD_DP] ; DP
stosb ; Store it.
mov [var_WORD_DP], edi ; Update DP (incremented)
POPDSP ebx
ret
defword_end
defword ":", 0, WORD_COLON, WORD_CALL_COMMA
call WORD_PARSENAME
call WORD_HEADER_COMMA ; Create the dictionary entry / header
mov eax, [var_WORD_DP]
mov [eax + XT_BODY], eax
call WORD_LATEST
call WORD_FETCH
call WORD_HIDDEN ; Make the word hidden
call WORD_RBRAC ; Go into compile mode.
ret
defword_end
defword "create", 0, WORD_CREATE, WORD_CALL_COMMA
call WORD_PARSENAME
call WORD_HEADER_COMMA
mov esi, create_l1
mov edi, [var_WORD_DP]
PUSHRSP edi
mov ecx, create_l4 - create_l1
rep movsb
mov [var_WORD_DP], edi
mov edx, edi
call WORD_ALIGNDP
POPRSP eax
mov edi, [var_WORD_DP]
sub edx, eax
mov [eax + create_l2 - create_l1 - 4], edi
mov [eax + XT_BODY], edi
mov [eax + XT_LENGTH], edx
ret
defword_end
create_l1:
LOADTOS 0xBAADF00D
create_l2:
call strict near create_l3
create_l3:
ret
create_l4:
defword "dodoes", 0, WORD_DODOES, WORD_CALL_COMMA
call WORD_LATEST
call WORD_FETCH
call WORD_TCFA
add ebx, create_l3 - create_l1 - 4
POPDSP eax
sub eax, ebx
sub eax, 4
mov [ebx], eax
POPDSP ebx
ret
defword_end
defword "does>", F_IMMED, WORD_DOES, WORD_CALL_COMMA
call WORD_LIT_COMMA
LOADTOS [var_WORD_DP]
add ebx, 10
call WORD_COMMA
LOADTOS WORD_DODOES
call WORD_COMPILE_COMMA
LOADTOS 0
mov bl, [does_l1]
call WORD_CHAR_COMMA
does_l1:
ret
defword_end
defword "postpone", F_IMMED, WORD_POSTPONE, WORD_CALL_COMMA
call WORD_PARSENAME
call WORD_FIND_DICT
mov dl, [ebx + H_NSIZE]
call WORD_TCFA
and edx, F_IMMED
if z
call WORD_LIT_COMMA
call WORD_COMMA
LOADTOS WORD_COMPILE_COMMA
endif
jmp WORD_COMPILE_COMMA
ret
defword_end
defword "call,", 0, WORD_CALL_COMMA, WORD_CALL_COMMA
mov edi, [var_WORD_DP]
mov [lastcall], edi ; record last location of last call
mov esi, i_call
movsb
mov eax, ebx
sub eax, 4
sub eax, edi
stosd
mov [var_WORD_DP], edi
POPDSP ebx
ret
defword_end
defword "inline,", 0, WORD_INLINE_COMMA, WORD_CALL_COMMA
mov ecx, [ebx + XT_LENGTH]
dec ecx ; actual code length minus ret
mov esi, ebx
mov edi, [var_WORD_DP]
rep movsb ; inline copy the code
mov [var_WORD_DP], edi ; update DP
POPDSP ebx
ret
defword_end
defword "compile,", 0, WORD_COMPILE_COMMA, WORD_INLINE_COMMA
call [ebx + XT_COMPILE]
ret
defword_end
defword ";", F_IMMED, WORD_SEMICOLON, WORD_CALL_COMMA
LOADTOS WORD_EXIT
i_call:
call strict near WORD_COMPILE_COMMA
call WORD_LATEST
call WORD_FETCH
call WORD_HIDDEN ; toggle hidden flag -- unhide the word (see below for definition).
call WORD_LBRAC ; go back to IMMEDIATE mode.
mov edx, ebx
mov ebx, [var_WORD_LATEST]
call WORD_TCFA
mov ecx, [var_WORD_DP]
sub ecx, ebx
mov [ebx + XT_LENGTH], ecx ; set code size of word
mov ebx, edx
ret
defword_end
defword "immediate", 0, WORD_IMMEDIATE, WORD_CALL_COMMA
mov edi, [var_WORD_LATEST] ; LATEST word.
add edi, H_NSIZE ; Point to name/flags byte.
xor byte [edi], F_IMMED ; Toggle the IMMED bit.
ret
defword_end
defword "hidden", 0, WORD_HIDDEN, WORD_CALL_COMMA
add ebx, H_NSIZE ; Point to name/flags byte.
xor byte [ebx], F_HIDDEN ; Toggle the HIDDEN bit.
POPDSP ebx
ret
defword_end
defword "[", F_IMMED, WORD_LBRAC, WORD_CALL_COMMA
mov long [var_WORD_STATE], 0 ; Set STATE to 0.
ret
defword_end
defword "]", 0, WORD_RBRAC, WORD_CALL_COMMA
mov long [var_WORD_STATE], 1 ; Set STATE to 1.
ret
defword_end
;;;;;;;;;;;;;;;;;;;;;
; source buffer words
;;;;;;;;;;;;;;;;;;;;;
defword "source", 0, WORD_SOURCE, WORD_CALL_COMMA
call WORD_INHASH
call WORD_FETCH2
ret
defword_end
defword "refill", 0, WORD_REFILL, WORD_CALL_COMMA
LOADTOS tib_buffer
call WORD_LINESIZE ; ( tib len )
call WORD_OVER
call WORD_SWAP ; ( tib tib len )
call WORD_ACCEPT ; read line into TIB
call WORD_DUP2
call WORD_TABSTOSPACES
call WORD_INHASH
call WORD_STORE2 ; set as current WORD_SOURCE
LOADTOS 0
call WORD_TOIN
call WORD_STORE ; set to start of buffer
LOADTOS -1
ret
defword_end
defword "isspace?", 0, WORD_ISSPACE, WORD_CALL_COMMA
LOADTOS ' '
call WORD_ULTEQ
ret
defword_end
defword "isnotspace?", 0, WORD_ISNOTSPACE, WORD_CALL_COMMA
call WORD_ISSPACE
call WORD_ZEQ
ret
defword_end
defword "xt-skip", 0, WORD_XTSKIP, WORD_CALL_COMMA
TORSP
xtskip_l1:
test ebx, ebx
jz xtskip_l3
call WORD_OVER
call WORD_FETCHBYTE
FETCHRSP
call WORD_EXECUTE
test ebx, ebx
jz xtskip_l2
mov ebx, 1
call WORD_SSTRING
jmp xtskip_l1
xtskip_l2:
call WORD_DROP
xtskip_l3:
ADDRSP 4
ret
defword_end
;;;;;;;;;;;;;;;;;;;;;;
; input parseing words
;;;;;;;;;;;;;;;;;;;;;;
defword "parse-name", 0, WORD_PARSENAME, WORD_CALL_COMMA
call WORD_SOURCE
call WORD_TOIN
call WORD_FETCH
call WORD_SSTRING
LOADTOS WORD_ISSPACE
call WORD_XTSKIP
call WORD_OVER
TORSP
LOADTOS WORD_ISNOTSPACE
call WORD_XTSKIP
call WORD_DUP2
LOADTOS 1
call WORD_MIN
call WORD_ADD
call WORD_SOURCE
call WORD_DROP
call WORD_SUB
call WORD_TOIN
call WORD_STORE
call WORD_DROP
FROMRSP
call WORD_TUCK
call WORD_SUB
; code to print out "P <word> CR"
;LOADTOS 80
;call WORD_EMIT
;LOADTOS 32
;call WORD_EMIT
;call WORD_DUP2
;call WORD_TYPE
;LOADTOS 10
;call WORD_EMIT
ret
defword_end
defword "word-name", 0, WORD_WORDNAME, WORD_CALL_COMMA
call WORD_PARSENAME ; ( start len )
LOADTOS word_buf ; ( string size buf )
call WORD_DUP2 ; ( string size buf size buf )
call WORD_STOREBYTE ; ( string size buf )
call WORD_INCR ; ( string size buf+1 )
call WORD_SWAP ; ( string buf+1 size )
call WORD_CMOVE
LOADTOS word_buf ; ( cstring )
; debug code to print out "N <word> CR"
;LOADTOS 78
;call WORD_EMIT
;LOADTOS 32
;call WORD_EMIT
;call WORD_DUP2
;call WORD_TYPE
;LOADTOS 10
;call WORD_EMIT
ret
defword_end
defword "interp-name", 0, WORD_INTERPNAME, WORD_CALL_COMMA
call WORD_PARSENAME ; ( start len )
LOADTOS intep_name_buf ; ( string size buf )
call WORD_DUP2 ; ( string size buf size buf )
call WORD_STOREBYTE ; ( string size buf )
call WORD_INCR ; ( string size buf+1 )
call WORD_SWAP ; ( string buf+1 size )
call WORD_CMOVE
LOADTOS intep_name_buf ;( cstring )
ret
defword_end
defword "interpret", 0, WORD_INTERPRET, WORD_CALL_COMMA
loopstart
call WORD_INTERPNAME
mov al, [ebx]
test al, al
breakif z
; debug code to print out "I <word> CR"
;LOADTOS 73
;call WORD_EMIT
;LOADTOS 32
;call WORD_EMIT
;call WORD_DUP
;call WORD_COUNT
;call WORD_TYPE
;LOADTOS 10
;call WORD_EMIT
call WORD_INTERP
loopend
call WORD_DROP
ret
defword_end
defword "interp", 0, WORD_INTERP, WORD_CALL_COMMA
call WORD_FIND ; ( cstring 0 | xt 1 | xt | -1 )
mov eax, ebx
POPDSP ebx
test eax, eax
jz tryasnumber
jle nonimediate
executeword:
mov eax, ebx
POPDSP ebx
jmp eax
nonimediate:
mov eax, [var_WORD_STATE]
test eax, eax ; are we in imedeate mode ?
jz executeword
jmp WORD_COMPILE_COMMA ; compile xt
tryasnumber:
call WORD_COUNT ; ( adr len )
LOADTOS 0
LOADTOS 0
call WORD_SWAP2 ; ( 0d addr len )
call WORD_TOSNUMBER ; ( d addr len )
test ebx, ebx
jnz parseproblem
call WORD_DROP2
call WORD_DROP ; ( num )
mov eax, [var_WORD_STATE]
test eax, eax
if nz
call WORD_LIT_COMMA ; compile LIT
call WORD_COMMA ; compile value
endif
ret
parseproblem:
LOADTOS errmsg
LOADTOS errmsgend - errmsg
LOADTOS 2
call WORD_TYPE_FD
LOADTOS errmsgnl
LOADTOS 1
LOADTOS 2
call WORD_TYPE_FD
LOADTOS tib_buffer
LOADTOS [var_WORD_TOIN]
LOADTOS 2
call WORD_TYPE_FD
LOADTOS errmsgnl
LOADTOS 1
LOADTOS 2
call WORD_TYPE_FD
call WORD_DROP2
call WORD_DROP2
ret
defword_end
defword ">number", 0, WORD_TONUMBER, WORD_CALL_COMMA
call WORD_OVER
call WORD_ADD
call WORD_SWAP ; ( ud end cur )
tonumber_l1:
PICKDSP eax, 0
cmp ebx, eax
jz near tonumber_l4
call WORD_DUP
call WORD_FETCHBYTE ; ( ud end cur char )
to_lower ebx
sub ebx, byte '0'
jb tonumber_l3 ; < '0'?
cmp ebx, byte 10
jb tonumber_l2 ; <= '9' ?
sub ebx, byte 'a' - '0'
jb tonumber_l3 ; < 'a' ?
add ebx, byte 10
tonumber_l2:
cmp ebx, [var_WORD_BASE]
jge tonumber_l3 ; >= WORD_BASE ?
TORSP
call WORD_SWAP2 ; ( end cur ud )
LOADTOS [var_WORD_BASE]
call WORD_DMULSTAR
FROMRSP
call WORD_MPLUS ; ( end cur ud' )
call WORD_SWAP2
call WORD_INCR ; ( ud' end cur' )
jmp tonumber_l1
tonumber_l3:
call WORD_DROP
tonumber_l4:
call WORD_SWAP
call WORD_OVER
call WORD_SUB ; ( ud' c-addr u2 )
ret
defword_end
defword ">snumber", 0, WORD_TOSNUMBER, WORD_CALL_COMMA
test ebx, ebx
if nz
PICKDSP eax, 0
mov cl, [eax]
cmp cl, '-'
jnz WORD_TONUMBER ; not '-'
inc eax
PUTDSP eax, 0
dec ebx
call WORD_TONUMBER
call WORD_SWAP2
call WORD_DNEGATE
call WORD_SWAP2
endif
ret
defword_end
;;;;;;;;;;;
; tick word
;;;;;;;;;;;
defword "ticks", 0, WORD_TICKS, WORD_CALL_COMMA
sub ebp, byte 8
rdtsc
mov [byte ebp -4], ebx
mov [ebp], eax
mov ebx, edx
ret
defword_end
;;;;;;;;;;;
; test word
;;;;;;;;;;;
defword "test", 0, WORD_TEST, WORD_CALL_COMMA
ret
defword_end
;;;;;;;;;;;;;;;;;
; read/write data
;;;;;;;;;;;;;;;;;
align 4
syscallret:
; return address saved by syscall
dd 0
lastcall:
; last call layed down by compiler
dd 0
tib_buffer:
; keyboard input buffer
times MAX_LINE_SIZE db 0
word_buf:
; static buffer where WORD returns. Subsequent calls
; overwrite this buffer.
times MAX_LINE_SIZE db 0
intep_name_buf:
; static buffer where INTERPNAME returns. Subsequent calls
; overwrite this buffer.
times MAX_LINE_SIZE db 0
emit_scratch:
; scratch used by EMIT
db 0
errmsg:
db "PARSE ERROR:"
errmsgend:
errmsgnl:
db 10
bootfile:
db "forth.f"
db 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; dictionary hash table (64)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 4
hash_buckets:
dd 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
dd 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
dd 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
dd 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; addresses of all built in dictionary words.
; this ends up as part of the user space after booting !
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 4
dictionary_start:
dd dic_WORD_ABS
dd dic_WORD_ACCEPT
dd dic_WORD_ADD
dd dic_WORD_ADDBYTE
dd dic_WORD_ADDSTORE
dd dic_WORD_ALIGNDP
dd dic_WORD_AND
dd dic_WORD_BASE
dd dic_WORD_BLANK
dd dic_WORD_BLK
dd dic_WORD_BRANCH
dd dic_WORD_BUCKET
dd dic_WORD_CALL_COMMA
dd dic_WORD_CHARBUF
dd dic_WORD_CHAR_COMMA
dd dic_WORD_CLITS
dd dic_WORD_CMOVE
dd dic_WORD_CMOVEB
dd dic_WORD_COLON
dd dic_WORD_COMMA
dd dic_WORD_COMPARE
dd dic_WORD_COMPAREI
dd dic_WORD_COMPILE_COMMA
dd dic_WORD_COUNT
dd dic_WORD_CREATE
dd dic_WORD_D2SLASH
dd dic_WORD_D2STAR
dd dic_WORD_DABS
dd dic_WORD_DECR
dd dic_WORD_DECR2
dd dic_WORD_DECR4
dd dic_WORD_DEQ
dd dic_WORD_DIV
dd dic_WORD_DIVMOD
dd dic_WORD_DLT
dd dic_WORD_DMAX
dd dic_WORD_DMIN
dd dic_WORD_DMINUS
dd dic_WORD_DMULSTAR
dd dic_WORD_DNEGATE
dd dic_WORD_DNEQ
dd dic_WORD_DODOES
dd dic_WORD_DOES
dd dic_WORD_DP
dd dic_WORD_DPLUS
dd dic_WORD_DROP
dd dic_WORD_DROP2
dd dic_WORD_DSPFETCH
dd dic_WORD_DSPSTORE
dd dic_WORD_DTOS
dd dic_WORD_DULT
dd dic_WORD_DUP
dd dic_WORD_DUP2
dd dic_WORD_DZEQ
dd dic_WORD_DZLT
dd dic_WORD_DZNEQ
dd dic_WORD_EMIT
dd dic_WORD_EQ
dd dic_WORD_ERASE
dd dic_WORD_EXECUTE
dd dic_WORD_EXIT
dd dic_WORD_FETCH
dd dic_WORD_FETCH2
dd dic_WORD_FETCHBYTE
dd dic_WORD_FETCHSHORT
dd dic_WORD_FILL
dd dic_WORD_FIND
dd dic_WORD_FIND_DICT
dd dic_WORD_FMDIVMOD
dd dic_WORD_FROMR
dd dic_WORD_FROMR2
dd dic_WORD_GT
dd dic_WORD_GTEQ
dd dic_WORD_HEADER_COMMA
dd dic_WORD_HIDDEN
dd dic_WORD_IMMEDIATE
dd dic_WORD_INCR
dd dic_WORD_INCR2
dd dic_WORD_INCR4
dd dic_WORD_INHASH
dd dic_WORD_INLINE_COMMA
dd dic_WORD_INTERP
dd dic_WORD_INTERPNAME
dd dic_WORD_INTERPRET
dd dic_WORD_INVERT
dd dic_WORD_ISNOTSPACE
dd dic_WORD_ISSPACE
dd dic_WORD_KEY
dd dic_WORD_LATEST
dd dic_WORD_LBRAC
dd dic_WORD_LINESIZE
dd dic_WORD_LIT_COMMA
dd dic_WORD_LSHIFT
dd dic_WORD_LSYSCALL
dd dic_WORD_LT
dd dic_WORD_LTEQ
dd dic_WORD_MAX
dd dic_WORD_MIN
dd dic_WORD_MMINUS
dd dic_WORD_MOD
dd dic_WORD_MOVE
dd dic_WORD_MPLUS
dd dic_WORD_MSLASH
dd dic_WORD_MULDIV
dd dic_WORD_MULL
dd dic_WORD_MULSTAR
dd dic_WORD_NE
dd dic_WORD_NEGATE
dd dic_WORD_NFROMR
dd dic_WORD_NIP
dd dic_WORD_NIP2
dd dic_WORD_NQDUP
dd dic_WORD_NROT
dd dic_WORD_NTOR
dd dic_WORD_OR
dd dic_WORD_OVER
dd dic_WORD_OVER2
dd dic_WORD_O_APPEND
dd dic_WORD_O_CREAT
dd dic_WORD_O_EXCL
dd dic_WORD_O_NONBLOCK
dd dic_WORD_O_RDONLY
dd dic_WORD_O_RDWR
dd dic_WORD_O_TRUNC
dd dic_WORD_O_WRONLY
dd dic_WORD_PARSENAME
dd dic_WORD_PICK
dd dic_WORD_POSTPONE
dd dic_WORD_QDUP
dd dic_WORD_RBRAC
dd dic_WORD_RDROP
dd dic_WORD_RDROP2
dd dic_WORD_READCHAR
dd dic_WORD_READLINE
dd dic_WORD_REFILL
dd dic_WORD_RFETCH
dd dic_WORD_RFETCH2
dd dic_WORD_ROT
dd dic_WORD_ROT2
dd dic_WORD_RSHIFT
dd dic_WORD_RSPFETCH
dd dic_WORD_RSPSTORE
dd dic_WORD_RSTORE
dd dic_WORD_RZ
dd dic_WORD_SEMICOLON
dd dic_WORD_SLITS
dd dic_WORD_SMDIVREM
dd dic_WORD_SOURCE
dd dic_WORD_SOURCEFD
dd dic_WORD_SSTRING
dd dic_WORD_STARSMOD
dd dic_WORD_STATE
dd dic_WORD_STOD
dd dic_WORD_STORE
dd dic_WORD_STORE2
dd dic_WORD_STOREBYTE
dd dic_WORD_STORESHORT
dd dic_WORD_SUB
dd dic_WORD_SUBSTORE
dd dic_WORD_SWAP
dd dic_WORD_SWAP2
dd dic_WORD_SYSCALL
dd dic_WORD_SYS_CLOSE
dd dic_WORD_SYS_EXIT
dd dic_WORD_SYS_FSTAT
dd dic_WORD_SYS_FSYNC
dd dic_WORD_SYS_FTRUNCATE
dd dic_WORD_SYS_LSEEK
dd dic_WORD_SYS_OPEN
dd dic_WORD_SYS_READ
dd dic_WORD_SYS_RENAME
dd dic_WORD_SYS_STAT
dd dic_WORD_SYS_UNLINK
dd dic_WORD_SYS_WRITE
dd dic_WORD_SZ
dd dic_WORD_TABSTOSPACES
dd dic_WORD_TCFA
dd dic_WORD_TICKS
dd dic_WORD_TOIN
dd dic_WORD_TONUMBER
dd dic_WORD_TOR
dd dic_WORD_TOR2
dd dic_WORD_TOSNUMBER
dd dic_WORD_TRAILING
dd dic_WORD_TUCK
dd dic_WORD_TUCK2
dd dic_WORD_TWODIV
dd dic_WORD_TWOMUL
dd dic_WORD_TYPE
dd dic_WORD_TYPE_FD
dd dic_WORD_UDIVMOD
dd dic_WORD_UGT
dd dic_WORD_UGTEQ
dd dic_WORD_ULT
dd dic_WORD_ULTEQ
dd dic_WORD_UMDIVMOD
dd dic_WORD_UMULSTAR
dd dic_WORD_UNUSED
dd dic_WORD_VERSION
dd dic_WORD_WORDBUF
dd dic_WORD_WORDNAME
dd dic_WORD_XOR
dd dic_WORD_XTSKIP
dd dic_WORD_ZBRANCH
dd dic_WORD_ZEQ
dd dic_WORD_ZGT
dd dic_WORD_ZGTEQ
dd dic_WORD_ZLT
dd dic_WORD_ZLTEQ
dd dic_WORD_ZNE
dd dic_WORD__F_HIDDEN
dd dic_WORD__F_IMMED
dd dic_WORD__F_LENMASK
dd dic_WORD__H_NAME
dd dic_WORD__H_NSIZE
dd dic_WORD__XT_BODY
dd dic_WORD__XT_COMPILE
dd dic_WORD__XT_LENGTH
dd dic_WORD__XT_SIZE
dd dic_WORD_TEST
dictionary_end:
;;;;;;;;;;;;;;;;;;;;;;;;;;
; room for user dictionary
;;;;;;;;;;;;;;;;;;;;;;;;;;
times USER_DEFS_SIZE db 0
forth_end: