code: 9ferno

ref: b548687a8ed1d0a159c9d3f3f921d93bbb56908e
dir: /os/pc64/words-nasm.s/

View raw version
CENTRY "false" C_false 5
dd M_literal
dd 0
dd M_exitcolon
CENTRY "true" C_true 4
dd M_literal
dd -1
dd M_exitcolon
CENTRY "bl" C_bl 2
dd M_literal
dd 32
dd M_exitcolon
CENTRY "on" C_on 2		; ( a --  ) (G stores -1 at a )
dd M_literal
dd -1
dd M_xswap
dd M_store
dd M_exitcolon
CENTRY "off" C_off 3		; ( a --  ) (G stores 0 at a )
dd M_literal
dd 0
dd M_xswap
dd M_store
dd M_exitcolon
CENTRY ">body" C_tobody 5
dd M_literal
dd 8
dd M_plus
dd M_exitcolon
CENTRY "aligned" C_aligned 7	; align a number to a multiple of 8
dd M_literal
dd 7
dd M_plus
dd M_literal
dd -8
dd M_binand
dd M_exitcolon
CENTRY "cells" C_cells 5
dd M_literal
dd 3			; (index << 2) -> (index << 3) for amd64
dd M_lshift
dd M_exitcolon
CENTRY "cells+" C_cells_plus 6 ; ( n1 n2 -- n1+(n2*cellsize) )
dd C_cells
dd M_plus
dd M_exitcolon
CENTRY "cell+" C_cell_plus 5
dd M_literal
dd 1
dd C_cells_plus
dd M_exitcolon

CENTRY "depth" C_depth 5
dd MV_S0
dd M_stackptr
dd M_minus
dd M_literal
dd 3
dd M_rshift
dd M_literal
dd 1
dd M_minus
dd M_exitcolon
CENTRY "nip" C_nip 3 ; ( n1 n2 -- n2 )
dd M_xswap
dd M_drop
dd M_exitcolon
CENTRY "rot" C_rot 3 ; ( n1 n2 n3 -- n2 n3 n1 )
dd M_rpush
dd M_xswap
dd M_rpop
dd M_xswap
dd M_exitcolon
CENTRY "2drop" C_2drop 5
dd M_drop
dd M_drop
dd M_exitcolon
CENTRY "2dup" C_2dup 4
dd M_over
dd M_over
dd M_exitcolon
CENTRY "2nip" C_2nip 4
dd C_nip
dd C_nip
dd M_exitcolon
CENTRY "2swap" C_2swap 5
dd C_rot
dd M_rpush
dd C_rot
dd M_rpop
dd M_exitcolon
CENTRY "?dup" C_qdup 4 ; if (n != 0) ( n -- n n) else ( n -- n )
dd M_dup	; ( n -- n n )
dd M_dup	; ( n n -- n n n )
dd M_literal
dd 0		; ( n n n -- n n n 0 )
dd M_equal	; ( n n n 0 -- n n f )
dd M_cjump	; ( n n f -- n n )
dd L_qdup	; when n != 0, go to L20
dd M_drop	; when n == 0 ( n n -- n)
L_qdup:		; when n != 0 ( n n )
dd M_exitcolon

CENTRY "pick" C_pick 4
dd C_qdup
dd M_cjump
dd L_pick
dd M_literal
dd 1
dd M_plus
dd C_cells
dd M_stackptr
dd M_plus
dd M_fetch
dd M_jump
dd L_pick_1
L_pick:
dd M_dup
L_pick_1:
dd M_exitcolon

CENTRY "tuck" C_tuck 4 ; ( n1 n2 -- n2 n1 n2 )
dd M_dup
dd M_rpush
dd M_xswap
dd M_rpop
dd M_exitcolon
CENTRY "/" C_divides 1
dd M_slashmod
dd C_nip
dd M_exitcolon

CENTRY "+!" C_plusstore 2 ; ( n 'a -- ) a@ = a@+n
dd M_dup
dd M_fetch
dd C_rot
dd M_plus
dd M_xswap
dd M_store
dd M_exitcolon

CENTRY "invert" C_invert 6
dd M_literal
dd -1
dd M_binxor
dd M_exitcolon
CENTRY "mod" C_mod 3
dd M_slashmod
dd M_drop
dd M_exitcolon
CENTRY "1+" C_1plus 2
dd M_literal
dd 1
dd M_plus
dd M_exitcolon
CENTRY "1-" C_1minus 2
dd M_literal
dd 1
dd M_minus
dd M_exitcolon
CENTRY "negate" C_negate 6
dd M_literal
dd 0
dd M_xswap
dd M_minus
dd M_exitcolon
CENTRY "2*" C_2multiplies 2
dd M_literal
dd 1
dd M_lshift
dd M_exitcolon
CENTRY "2/" C_2divides 2
dd M_literal
dd 1
dd M_rshifta
dd M_exitcolon
CENTRY "0=" C_0eq 2
dd M_literal
dd 0
dd M_equal
dd M_exitcolon
CENTRY "0<" C_0lt 2
dd M_literal
dd 0
dd M_less
dd M_exitcolon
CENTRY "0>" C_0gt 2
dd M_literal
dd 0
dd M_greater
dd M_exitcolon
CENTRY "<>" C_neq 2
dd M_equal
dd C_invert
dd M_exitcolon
CENTRY "0<>" C_0neq 3
dd M_literal
dd 0
dd C_neq
dd M_exitcolon

CENTRY "max" C_max 3
dd C_2dup
dd M_greater
dd M_cjump
dd L_max
dd M_drop
dd M_jump
dd L_max_1
L_max:
dd C_nip
L_max_1:
dd M_exitcolon

CENTRY "min" C_min 3
dd C_2dup
dd M_less
dd M_cjump
dd L_min
dd M_drop
dd M_jump
dd L_min_1
L_min:
dd C_nip
L_min_1:
dd M_exitcolon

CENTRY "signum" C_signum 6
dd M_dup
dd C_0gt
dd M_cjump
dd L_signum
dd M_drop
dd M_literal
dd 1
dd M_jump
dd L_signum_1
L_signum:
dd C_0lt
dd M_cjump
dd L_signum_2
dd M_literal
dd -1
dd M_jump
dd L_signum_3
L_signum_2:
dd M_literal
dd 0
L_signum_3:
L_signum_1:
dd M_exitcolon

CENTRY "within" C_within 6
dd M_rpush
dd M_over
dd M_greater
dd C_0eq
dd M_xswap
dd M_rpop
dd M_greater
dd C_0eq
dd M_binand
dd M_exitcolon
CENTRY "abs" C_abs 3
dd M_dup
dd C_0lt
dd M_cjump
dd L_abs
dd C_negate
L_abs:
dd M_exitcolon

CENTRY "emit" C_emit 4	; ( character -- )
dd MV_Iobuf		; variable iobuf address
dd M_cstore	; variable iobuf has character
dd MV_Outfd
dd M_fetch		; outfd
dd MV_Iobuf		; variable iobuf address
dd M_literal
dd 1			; ( outfd iobuf 1 )
dd M_syswrite	; ( 1 iobuf outfd --  )
dd M_drop		; drop the return value of write
dd M_exitcolon

CENTRY "type" C_type 4	; ( addr n -- )
dd M_rpush		; ( addr ) (R n )
dd M_rpush		; ( ) (R n addr )
dd MV_Outfd
dd M_fetch		; ( outfd )
dd M_rpop		; ( outfd addr ) (R n )
dd M_rpop		; ( outfd addr n ) (R )
dd M_syswrite	; ( 1 addr n --  )
dd M_drop		; drop the return value of write
dd M_exitcolon

CENTRY "cr" C_cr 2
dd M_literal
dd 10			; ascii value of carriage return
dd C_emit			; emit
dd M_exitcolon

CENTRY "space" C_space 5
dd C_bl
dd C_emit
dd M_exitcolon

CENTRY "emits" C_emits 5
L_emits:
dd C_qdup
dd M_cjump
dd L_emits_1
dd M_over
dd C_emit
dd C_1minus
dd M_jump
dd L_emits
L_emits_1:
dd M_drop
dd M_exitcolon

CENTRY "spaces" C_spaces 6
dd C_bl
dd M_xswap
dd C_emits
dd M_exitcolon

CENTRY "count" C_count 5 ; ( 'counted-string -- 'text count ) a = address of counted string ( a - a+1 a[0])
dd C_1plus
dd M_dup
dd C_1minus
dd M_cfetch
dd M_exitcolon

dd C_2dup ; debug show the word name to search
dd C_type
dd C_space

dd M_rpush ; debug show the dictionary entry
dd M_rpush
dd C_2dup
dd C_type
dd M_rpop
dd M_rpop
dd C_cr

CENTRY "compare" C_compare 7 ; ( a1 n1 a2 n2 -- f ) a1 = dictionary entry a2 = word name to search
dd C_rot	; ( a1 n1 a2 n2 -- a1 a2 n2 n1 )
dd C_2dup	; ( -- a1 a2 n2 n1 n2 n1 )
dd M_rpush	; ( -- a1 a2 n2 n1 n2 ) (R n1 -- )
dd M_rpush	; ( -- a1 a2 n2 n1 ) (R n1 n2 -- )
dd C_min	; ( -- a1 a2 nmin ) (R n1 n2 -- )
dd M_literal
dd 0		; ( -- a1 a2 nmin 0 ) (R n1 n2 -- )
dd M_doinit	; ( -- a1 a2 ) (R n1 n2 0 nmin -- )
L_compare:
dd M_over
dd M_i
dd M_plus
dd M_cfetch
dd M_over
dd M_i
dd M_plus
dd M_cfetch
dd M_minus
dd C_signum
dd C_qdup
dd M_cjump
dd L_compare_1		; matches
dd C_2nip	; does not match ( a1 a2 f -- f ) (R n1 n2 0 nmin -- )
dd M_unloop	; ( f -- f ) (R n1 n2 0 nmin -- n1 n2)
dd M_unloop	; ( f -- f ) (R n1 n2 -- )
dd M_exitcolon
L_compare_1:
dd M_doloop
dd L_compare
dd C_2drop	; ( a1 a2 -- ) (R n1 n2 -- )
dd M_rpop
dd M_rpop	; ( n2 n1 -- ) (R -- )
dd M_minus	; ( -- n1-n2 )
dd C_signum
dd M_exitcolon

CENTRY "erase" C_erase 5	; ( a n -- ) put 0 at a for n characters
dd M_literal
dd 0
dd M_doinit
L_erase_loop:
dd M_literal
dd 0
dd M_over
dd M_cstore
dd C_1plus
dd M_doloop
dd L_erase_loop
dd M_drop
dd M_exitcolon

CENTRY "fill" C_fill 4	; ( a n c -- ) fill c at a for n characters
dd M_xswap
dd M_literal
dd 0
dd M_doinit
L_fill_loop:
dd C_2dup
dd M_xswap
dd M_i
dd M_plus
dd M_cstore
dd M_doloop
dd L_fill_loop
dd C_2drop
dd M_exitcolon

CENTRY "blank" C_blank 5
dd C_bl
dd C_fill
dd M_exitcolon

CENTRY "search" C_search 6
dd MV_Searchlen
dd M_store
dd M_xswap
dd M_dup
dd M_rpush
dd MV_Searchlen
dd M_fetch
dd M_minus
dd C_1plus
dd M_literal
dd 0
dd M_doinit
L_search:
dd M_over
dd M_i
dd M_plus
dd M_over
dd MV_Searchlen
dd M_fetch
dd M_xswap
dd MV_Searchlen
dd M_fetch
dd C_compare
dd C_0eq
dd M_cjump
dd L_search_1
dd M_drop
dd M_i
dd M_plus
dd M_i
dd M_unloop
dd M_rpop
dd M_xswap
dd M_minus
dd C_true
dd M_exitcolon
L_search_1:
dd M_doloop
dd L_search
dd M_drop
dd M_rpop
dd C_false
dd M_exitcolon

CENTRY "here" C_here 4
dd MV_Here		; the address on the top of stack is 0x583288, which is correct
dd M_fetch
dd M_exitcolon

CENTRY "there" C_there 5	; variable here
dd MV_There
dd M_fetch
dd M_exitcolon

CENTRY "," C_comma 1
dd C_here
dd M_store
dd M_literal
dd 8
dd MV_Here
dd C_plusstore
dd M_exitcolon

CENTRY "c," C_c 2
dd C_here
dd M_cstore
dd M_literal
dd 1
dd MV_Here
dd C_plusstore
dd M_exitcolon

CENTRY "allot" C_allot 5 ; ( n -- ) here = here+n
dd MV_Here
dd C_plusstore
dd M_exitcolon

CENTRY "vallot" C_vallot 6 ; allot on the variable space ( n -- ) there = there+n
dd MV_There
dd C_plusstore
dd M_exitcolon

CENTRY "pad" C_pad 3
dd C_here
dd M_literal
dd 256
dd M_plus
dd M_exitcolon
CENTRY "align" C_align 5	; ( -- ) align here to a cell boundary
dd C_here		; Dp @
dd C_aligned	; here is aligned to a multiple of 8
dd MV_Here			; store the aligned here at Dp
dd M_store		; Dp contains aligned_here
dd M_exitcolon
CENTRY "unused" C_unused 6
dd MV_Here
dd M_fetch
dd C_here
dd M_minus
dd M_exitcolon

CENTRY "<#" C_fromhash 2
dd C_pad
dd M_literal
dd 1024
dd M_plus
dd MV_toNum
dd M_store
dd M_exitcolon

CENTRY "#" C_hash 1
dd MV_Base
dd M_fetch
dd M_uslashmod
dd M_xswap
dd M_dup
dd M_literal
dd 9
dd M_greater
dd M_cjump
dd L_hash
dd M_literal
dd 97
dd M_plus
dd M_literal
dd 10
dd M_minus
dd M_jump
dd L_hash_1
L_hash:
dd M_literal
dd 48
dd M_plus
L_hash_1:
dd MV_toNum
dd M_fetch
dd C_1minus
dd M_dup
dd MV_toNum
dd M_store
dd M_cstore
dd M_exitcolon

CENTRY "#s" C_hashs 2
L_hashs:
dd C_hash
dd M_dup
dd M_cjump
dd L_hashs_1
dd M_jump
dd L_hashs
L_hashs_1:
dd M_exitcolon

CENTRY "#>" C_hashfrom 2
dd M_drop
dd MV_toNum
dd M_fetch
dd M_dup
dd C_pad
dd M_literal
dd 1024
dd M_plus
dd M_xswap
dd M_minus
dd M_exitcolon

CENTRY "hold" C_hold 4
dd MV_toNum
dd M_fetch
dd C_1minus
dd M_dup
dd M_rpush
dd M_cstore
dd M_rpop
dd MV_toNum
dd M_store
dd M_exitcolon

CENTRY "sign" C_sign 4
dd C_0lt
dd M_cjump
dd L_sign
dd M_literal
dd 45
dd C_hold
L_sign:
dd M_exitcolon

CENTRY "c(.)" C_counted_paren_dot_paren 4	; convert the top of stack to a counted string ( n1 -- 'cs )
dd C_paren_dot_paren ; ( 'text n2 )
dd M_xswap		; ( n2 'text )
dd M_literal
dd 1
dd M_minus		; ( n2 'text-1 )
dd M_xswap
dd M_over		; ( 'text-1 n2 'text-1 )
dd M_cstore		; ( 'text-1 )
dd M_exitcolon

CENTRY "(.)" C_paren_dot_paren 3	; convert the top of stack to a string ( n1 -- 'text n2 )
dd M_dup		; ( n -- n n )
dd C_abs		; ( n n -- n u )
dd C_fromhash	; pad = h+256; >num = pad+1024
dd C_hashs		; ( n u1 -- n n2 )
dd M_xswap		; ( n n2 -- n2 n )
dd C_sign		; ( n2 n -- n2 )
dd C_hashfrom	; ( u1 -- a n )
dd M_exitcolon

CENTRY "." C_dot 1	; print the top of stack ( n -- )
dd C_paren_dot_paren ; ( n1 -- 'text n2 )
dd C_type
dd C_space
dd M_exitcolon

CENTRY ".r" C_dotr 2
dd M_rpush
dd M_dup
dd C_abs
dd C_fromhash
dd C_hashs
dd M_xswap
dd C_sign
dd C_hashfrom
dd M_rpop
dd M_over
dd M_minus
dd M_literal
dd 0
dd C_max
dd C_spaces
dd C_type
dd M_exitcolon

CENTRY "hex" C_hex 3
dd M_literal
dd 16
dd MV_Base
dd M_store
dd M_exitcolon
CENTRY "decimal" C_decimal 7
dd M_literal
dd 10
dd MV_Base
dd M_store
dd M_exitcolon

CENTRY "digit" C_digit 5 ; ( c -- )
dd M_dup
dd M_literal
dd 65
dd M_literal
dd 91
dd C_within
dd M_cjump
dd L_digit
dd M_literal
dd 55
dd M_minus
dd M_jump
dd L_digit_1
L_digit:
dd M_dup
dd M_literal
dd 97
dd M_literal
dd 123
dd C_within
dd M_cjump
dd L_digit_2
dd M_literal
dd 87
dd M_minus
dd M_jump
dd L_digit_3
L_digit_2:
dd M_dup
dd M_literal
dd 48
dd M_literal
dd 58
dd C_within
dd M_cjump
dd L_digit_4
dd M_literal
dd 48
dd M_minus
dd M_jump
dd L_digit_5
L_digit_4:
dd M_drop
dd C_false
dd M_exitcolon
L_digit_5:
L_digit_3:
L_digit_1:
dd M_dup
dd MV_Base
dd M_fetch
dd M_less
dd M_cjump
dd L_digit_6
dd C_true
dd M_jump
dd L_digit_7
L_digit_6:
dd M_drop
dd C_false
L_digit_7:
dd M_exitcolon

CENTRY "number" C_number 6 ; ( a n1 -- n2 -1 | a n1 0 )
dd M_xswap	; ( a n1 -- n1 a )
dd M_dup	; ( n1 a -- n1 a a )
dd M_cfetch	; ( n1 a a -- n1 a c )
dd M_literal
dd 45		; ( n1 a c -- n1 a c - )
dd M_equal	; ( n1 a c -- n1 a f )
dd M_cjump	; ( n1 a c -- n1 a )
dd L_number_no_minus	; c != -

dd C_1plus	; c == - ( n1 a -- n1 a+1 )
dd M_xswap
dd C_1minus	; c == - ( a+1 n1 -- a+1 n1-1 )
dd M_literal
dd -1		; ( a+1 n1-1 -- a+1 n1-1 -1 )
dd M_rpush	; ( a+1 n1-1 -- a+1 n1-1 ) (R -- -1)
dd M_jump
dd L_number_digits

L_number_no_minus:		; c != -
dd M_xswap	; ( n1 a -- a n1)
dd M_literal
dd 1
dd M_rpush	; ( a n1 1 -- a n1 ) (R -- 1)

L_number_digits:	; ( a n1 ) (R sign )
dd M_dup	; ( a n1 n1 ) (R sign)
dd M_rpush	; ( a n1 ) (R sign n1)
dd M_literal
dd 0		; ( a n1 0) (R sign n1)
dd M_xswap	; ( a 0 n1) (R sign n1)
dd M_literal
dd 0		; ( a 0 n1 0) (R sign n1)
dd M_doinit	; ( a num=0 ) (R sign n1 nindex nlimit ) num = 0

L_number_loop:
dd MV_Base	; ( a num Base )	(R sign n1 nindex nlimit )
dd M_fetch	; ( a num base )	(R sign n1 nindex nlimit)
dd M_multiply	; ( a num*base )	(R sign nindex nlimit)
dd M_over	; ( a num*base a)		(R sign nindex nlimit)
dd M_i		; ( a num*base a nindex)	(R sign nindex nlimit)
dd M_plus	; ( a num*base a+nindex)	(R sign nindex nlimit)
dd M_cfetch	; ( a num*base c)		(R sign nindex nlimit)
dd C_digit	; ( a num*base d 0|-1 )		(R sign nindex nlimit)
dd M_cjump
dd L_number_not_a_digit ; not a digit
dd M_plus	; ( a num*base+d )		(R sign nindex nlimit)
dd M_jump
dd L_number_next

L_number_not_a_digit:	; ( a num*base d )		(R sign nindex nlimit)
dd M_drop
dd M_unloop
dd M_rpop
dd M_rpop
dd M_drop
dd C_false
dd M_exitcolon

L_number_next:
dd M_doloop
dd L_number_loop

dd M_rpop
dd M_drop
dd C_nip
dd M_rpop
dd M_multiply
dd C_true
dd M_exitcolon

CENTRY "abort" C_abort 5
dd MV_Abortvec
dd M_fetch
dd M_execute
dd M_exitcolon

CENTRY "bufferfilename@" C_bufferfilename_fetch 15 ; ( index -- 'counted-string ) fetch label
dd C_cells
dd MV_Bufferfilenames
dd M_plus
dd M_fetch
dd M_exitcolon

CENTRY "bufferfilename!" C_bufferfilename_store 15 ; ( 'text index -- ) store label
dd C_cells
dd MV_Bufferfilenames
dd M_plus
dd M_store
dd M_exitcolon

CENTRY ">word" C_toword 5 ; ( 'Bufferfds -- 'Wordfd )
dd MC_WORDNUM
dd C_cells_plus
dd M_exitcolon

CENTRY "wordfd@" C_wordfd_fetch 7
dd MV_Bufferfds
dd C_toword
dd M_fetch
dd M_exitcolon

CENTRY "wordfd!" C_wordfd_store 7
dd MV_Bufferfds
dd C_toword
dd M_store
dd M_exitcolon

CENTRY "wordfilename@" C_wordfilename_fetch 13
dd MV_Bufferfilenames
dd C_toword
dd M_fetch
dd M_exitcolon

CENTRY "wordfilename!" C_wordfilename_store 13
dd MV_Bufferfilenames
dd C_toword
dd M_store
dd M_exitcolon

CENTRY ">line" C_toline 5 ; ( 'Bufferfds -- 'Wordfd )
dd MC_LINENUM
dd C_cells_plus
dd M_exitcolon

CENTRY "linefd@" C_linefd_fetch 7
dd MV_Bufferfds
dd C_toline
dd M_fetch
dd M_exitcolon

CENTRY "linefd!" C_linefd_store 7
dd MV_Bufferfds
dd C_toline
dd M_store
dd M_exitcolon

CENTRY "linefilename@" C_linefilename_fetch 13
dd MV_Bufferfilenames
dd C_toline
dd M_fetch
dd M_exitcolon

CENTRY "linefilename!" C_linefilename_store 13
dd MV_Bufferfilenames
dd C_toline
dd M_store
dd M_exitcolon

CENTRY ">doublequote" C_todoublequote 12 ; ( 'Bufferfds -- 'Doublequotefd )
dd MC_DOUBLEQUOTENUM
dd C_cells_plus
dd M_exitcolon

CENTRY "doublequotefd@" C_doublequotefd_fetch 14
dd MV_Bufferfds
dd C_todoublequote
dd M_fetch
dd M_exitcolon

CENTRY "doublequotefd!" C_doublequotefd_store 14
dd MV_Bufferfds
dd C_todoublequote
dd M_store
dd M_exitcolon

CENTRY "doublequotefilename@" C_doublequotefilename_fetch 20
dd MV_Bufferfilenames
dd C_todoublequote
dd M_fetch
dd M_exitcolon

CENTRY "doublequotefilename!" C_doublequotefilename_store 20
dd MV_Bufferfilenames
dd C_todoublequote
dd M_store
dd M_exitcolon

CENTRY ">closeparen" C_tocloseparen 11 ; ( 'Bufferfds -- 'Closeparenfd )
dd MC_CLOSEPARENNUM
dd C_cells_plus
dd M_exitcolon

CENTRY "closeparenfd@" C_closeparenfd_fetch 13
dd MV_Bufferfds
dd C_tocloseparen
dd M_fetch
dd M_exitcolon

CENTRY "closeparenfd!" C_closeparenfd_store 13
dd MV_Bufferfds
dd C_tocloseparen
dd M_store
dd M_exitcolon

CENTRY "closeparenfilename@" C_closeparenfilename_fetch 19
dd MV_Bufferfilenames
dd C_tocloseparen
dd M_fetch
dd M_exitcolon

CENTRY "closeparenfilename!" C_closeparenfilename_store 19
dd MV_Bufferfilenames
dd C_tocloseparen
dd M_store
dd M_exitcolon

; stdinput : set all buffer fd's to -1, Infd = stdin
; args : set all buffer fd's to -1, Infd = #p/<pid>/args
; input@ : buffer fds and Infd -> stack
; input! : stack -> buffer fds and Infd
; -input : close all buffer fds and Infd, set buffer fds to -1
; buffer file names are setup in boot

CENTRY "stdinput" C_stdinput 8 ; stream input from stdin into Text input buffer
dd MC_STDIN
dd MV_Infd
dd M_store

dd MV_Bufferfds
dd MC_NBUFFERS
dd M_literal
dd 0
dd M_doinit
L_stdinput_loop:

dd M_literal
dd -1
dd M_over	; ( 'Bufferfd -1 'Bufferfd )
dd M_store

dd M_literal
dd 1
dd C_cells
dd M_plus

dd M_doloop
dd L_stdinput_loop
dd M_drop
dd M_exitcolon

CENTRY "args" C_args 4 ; stream input from #p/<pid>/args into Text input buffer
dd MV_Argsfilename	; ( 'args_filename_counted_string ) filled by the starter
dd M_cfetch
dd M_literal
dd 0
dd M_equal
dd M_cjump
dd L_args_read
dd M_exitcolon

L_args_read:
dd MV_Argsfilename
dd C_count
dd C_ro
dd C_open_file
dd M_drop
dd MV_Infd
dd M_store

dd M_exitcolon

CENTRY "input@" C_input_fetch 6 ; ( -- Bufferfds Infd #Buffers+1 ) save input stream onto the stack and replace the buffer fd's with -1

dd MV_Bufferfds
dd MC_NBUFFERS
dd M_literal
dd 0
dd M_doinit
L_input_fetch_loop:

dd M_dup	; ( 'Bufferfd 'Bufferfd )
dd M_fetch

dd M_xswap	; ( fd 'Bufferfd )

dd M_literal
dd -1
dd M_over	; ( fd 'Bufferfd -1 'Bufferfd )
dd M_store	; ( fd 'Bufferfd )

dd M_literal
dd 1
dd C_cells
dd M_plus

dd M_doloop
dd L_input_fetch_loop
dd M_drop	; ( fd0 fd1 .. fdn )

dd MV_Infd
dd M_fetch	; ( fd0 fd1 .. fdn infd )

dd MC_NBUFFERS
dd M_literal
dd 1
dd M_plus	; ( fd0 fd1 .. fdn infd n+1 )

dd M_exitcolon

CENTRY "input!" C_input_store 6 ; ( fd0 fd1 .. fdn infd n+1 | empty -- ) restore input stream from the stack or stdinput
dd M_dup		; check if there is #Buffers+1 on the top of stack

dd MC_NBUFFERS
dd M_literal
dd 1
dd M_plus
dd M_equal	; is the top of stack == #Buffers+1
dd M_cjump
dd L_input_store_no_stream	; top of stack <> #Buffers+1, there is no input stream on the stack, use the default input

dd M_drop	; drop the #Buffers+1 on the top of stack

dd MV_Infd
dd M_store	; ( fd0 fd1 .. fdn )

dd MV_Bufferfds
dd MC_NBUFFERS
dd C_cells
dd M_plus	; ( fd0 fd1 .. fdn 'Bufferfds+(NBUFFERS*cellsize) )

dd MC_NBUFFERS
dd M_literal
dd 0
dd M_doinit
L_input_store_loop:

dd M_literal
dd 1
dd C_cells
dd M_minus	; ( fd0 fd1 .. fdn 'Bufferfds-(1*cellsize) )
dd M_dup	; ( fd0 fd1 .. fdn 'Bufferfds-(1*cellsize) 'Bufferfds-(1*cellsize) )
dd M_rpush	; ( fd0 fd1 .. fdn 'Bufferfds-(1*cellsize) ) (R 'Bufferfds-(1*cellsize) )
dd M_store

dd M_rpop	; ( fd0 fd1 .. fdn-1 'Bufferfds-(1*cellsize) )

dd M_doloop
dd L_input_store_loop
dd M_drop	; remove the 'Bufferfds on top

dd MV_Eof
dd C_off	; reset Eof back to 0

dd C_true	; ( true )
dd M_exitcolon

L_input_store_no_stream:	; there is no input stream on the stack
dd C_stdinput	; no input stream on the stack, use default input from now
dd C_false		; ( 0 )
dd M_exitcolon

; closefds: close all buffer fds and Infd, set buffer fds and Infd to -1
CENTRY "-input" C_close_input 6 ; (  )	; close the current input stream
dd MV_Bufferfds
dd MC_NBUFFERS
dd M_literal
dd 0
dd M_doinit
L_close_input:

dd M_dup	; ( 'Bufferfd 'Bufferfd )
dd M_fetch
dd M_literal
dd -1
dd C_neq
dd M_cjump
dd L_close_next	; == -1, check next fd

dd M_dup	; ( 'Bufferfd 'Bufferfd )
dd M_fetch	; ( 'Bufferfd fd )
dd C_close_file	; ( 'Bufferfd ioresult )
dd M_drop	; ( 'Bufferfd )

dd M_dup	; ( 'Bufferfd 'Bufferfd )
dd M_literal
dd -1
dd M_xswap	; ( 'Bufferfd -1 'Bufferfd )
dd M_store	; ( 'Bufferfd )

L_close_next:
dd M_literal
dd 1
dd C_cells
dd M_plus

dd M_doloop
dd L_close_input

dd M_drop

dd M_literal
dd -1
dd MV_Infd	; ( -1 'Infd )
dd M_dup	; ( -1 'Infd 'Infd )
dd M_fetch	; ( -1 'Infd fd )
dd C_close_file	; ( -1 'Infd ioresult )
dd M_drop	; ( -1 'Infd )
dd M_store

dd MV_Eof
dd C_off	; reset Eof back to 0

dd M_exitcolon

CENTRY "-+input" C_restore_input 7 ; ( <input> -- ) ; use the input stream on the stack or abort
dd C_close_input

dd C_input_store
dd C_0eq
dd M_cjump
dd L_restore_input_exit	; input stream restored

; no input stream on the stack to restore, show error and abort
dd C_space
dd M_literal
dd L_restore_input_error_message
dd C_count
dd C_type
dd C_space
dd C_depth
dd C_dot
dd C_cr

dd C_abort
L_restore_input_exit:	; input stream restored, get out
dd M_exitcolon

CENTRY "concat" C_concat 6 ; ( 'cs1 'cs2 -- 'cs1+'cs2 ) concatenate counted string2 to counted-string1

; move the contents of cs2 to cs1+1+count1. cs2+1 cs1+c1+1 c2 cmove
dd C_2dup	; ( 'cs1 'cs2 'cs1 'cs2 )
dd M_dup	; ( 'cs1 'cs2 'cs1 'cs2 'cs2 )
dd M_cfetch	; ( 'cs1 'cs2 'cs1 'cs2 c2 )
dd M_rpush	; ( 'cs1 'cs2 'cs1 'cs2 ) (R c2 )
dd C_1plus	; ( 'cs1 'cs2 'cs1 'cs2+1 ) (R c2 )
dd M_over	; ( 'cs1 'cs2 'cs1 'cs2+1 'cs1 ) (R c2 )
dd M_dup	; ( 'cs1 'cs2 'cs1 'cs2+1 'cs1 'cs1 ) (R c2 )
dd M_cfetch	; ( 'cs1 'cs2 'cs1 'cs2+1 'cs1 c1 ) (R c2 )
dd M_plus	; ( 'cs1 'cs2 'cs1 'cs2+1 'cs1+c1 ) (R c2 )
dd C_1plus	; ( 'cs1 'cs2 'cs1 'cs2+1 'cs1+c1+1 ) (R c2 )
dd M_rpop	; ( 'cs1 'cs2 'cs1 'cs2+1 'cs1+c1+1 c2 ) (R )
dd M_cmove	; ( 'cs1 'cs2 'cs1 )

; update the count in cs1. c1 = c1+c2
dd M_cfetch	; ( 'cs1 'cs2 c1 )
dd M_xswap	; ( 'cs1 c1 'cs2 )
dd M_cfetch	; ( 'cs1 c1 c2 )
dd M_plus	; ( 'cs1 c1+c2 )
dd M_over	; ( 'cs1 c1+c2 'cs1 )
dd M_cstore	; ( 'cs1 )

dd M_exitcolon

; if (.) can return a counted string, this would be simpler
CENTRY "buffername" C_buffername 10 ; ( index -- 'counted_string ) build the buffer fd's filename
dd C_bufferfilename_fetch	; ( 'fcs ) fcs = filename counted string
dd M_literal
dd L_bin_prefix	; address of the counted string 3#n/
dd C_pad
dd M_literal
dd 4
dd M_cmove	; pad has 3#n/

dd C_pad	; ( 'fcs pad )
dd MV_Infd
dd M_fetch
dd C_counted_paren_dot_paren ; ( 'fcs pad 'cs )
dd C_concat	; Now, pad has 4#n/0 ( 'fcs pad )

dd M_xswap	; ( pad 'fcs )
dd C_concat	; Now, pad has a proper counted string
dd M_exitcolon

; max of a counted string is 256 bytes. Hence, cannot use it.
; reads into Tib and puts the read count on the stack. Could move the file reading into accept.
CENTRY "query" C_query 5 ; ( index -- read_count ) read from the indexed Fd in Bufferfds into Tib

L_query_again:
dd MV_Eof
dd C_off	; clear EOF flag

dd M_dup
dd C_cells	; ( index index*cellsize ) number of bytes
dd MV_Bufferfds
dd M_plus	; ( index index*cellsize+'Bufferfds ) address of the fd
dd M_fetch	; ( index fd )

dd M_dup	; ( index fd fd )
dd M_literal
dd -1
dd M_equal
dd M_cjump	; if fd == -1 ( index fd )
dd L_query	; when not -1

dd M_drop	; when fd == -1 ( index )
dd M_dup
dd M_dup
dd M_rpush	; ( index index ) (R index )
dd C_buffername
dd C_count	; ( index 'filename-counted-string -- 'text count ) (R index )
dd C_ro
dd C_open_file	; ( index fd ioresult ) (R index )
dd C_invert
dd M_cjump
dd L_query_opened	; if open suceeded, go here

dd M_drop	; ( index ) (R index ) returned false, could not open-file. write error message
dd M_literal
dd L_open_failed		; open error
dd C_count
dd C_type
dd C_dot	; show the index
dd C_cr
dd C_abort	; abort on open error. How about terminate?

L_query_opened:	; ( index fd ) (R index ) store the opened fd
dd M_dup	; ( index fd fd )
dd M_rpop	; ( index fd fd index )
dd C_cells	; ( index fd fd index*cellsize ) number of bytes
dd MV_Bufferfds
dd M_plus	; ( index fd fd index*cellsize+'Bufferfds ) address of the filename's counted string
dd M_store	; ( index fd )

L_query:		; ( index fd ) when fd != -1
dd MV_Tib
dd M_literal
dd 4096		; ( index fd Tib 4096 )
dd C_read_file ; ( index read_count ioresult )
dd M_cjump
dd L_query_read_failed

dd M_dup	; ( index read_count read_count )

dd M_cjump
dd L_query_read_0

dd M_dup	; read_count > 0 ( index read_count read_count )
dd M_literal
dd 4096
dd M_equal

dd M_cjump
dd L_query_read_successful

dd M_literal
dd L_query_too_long ; could not find a delimiter in 4096 bytes, reevaluate
dd C_count
dd C_type
dd C_dot	; show the read_count
dd C_cr
dd C_abort	; abort on read error. How about terminate?
dd M_exitcolon

L_query_read_failed:
dd M_literal
dd L_read_failed ; read error
dd C_count
dd C_type
dd C_dot	; show the index
dd C_cr
dd C_abort	; abort on read error. How about terminate without the fallback interpreter?
dd M_exitcolon

L_query_read_0:

dd M_drop	; ( index ) read_count == 0
dd M_rpush	; ( ) (R index ) save index for use after restoring input
dd MV_Eof
dd C_on		; end of file, qrestore_input
dd C_restore_input

dd M_rpop	; ( index ) (R )
dd M_jump	; ( index )
dd L_query_again

L_query_read_successful:
dd C_nip
dd M_exitcolon	; ( read_count ) successful read, get out

CENTRY "parse" C_parse 5 ; ( read_count -- 'Wordb ) Wordb has a counted string. read_count bytes read into Tib

dd M_dup	; ( read_count read_count ) check if count > 255 bytes, then invalid word
dd M_literal
dd 256
dd M_less
dd M_cjump
dd L_parse_1

dd M_dup	; ( read_count read_count )
dd MV_Wordb
dd M_cstore	; ( store read_count at Wordb[0] )
dd M_rpush
dd MV_Tib
dd MV_Wordb
dd M_literal
dd 1
dd M_plus	; ( 'Tib 'Wordb+1 ) (R read_count )
dd M_rpop	; ( 'Tib 'Wordb+1 read_count )
dd M_cmove	; copy bytes from Tib to Wordb to make it a counted string at Wordb

dd MV_Wordb
dd M_exitcolon	; ( 'Wordb ) Wordb has the counted string

L_parse_1:
dd M_literal
dd L_long_word
dd C_count
dd C_type
dd C_cr
dd C_abort
dd M_exitcolon

CENTRY "word" C_word 4 ; ( -- 'Wordb ) read from #n/Infd/word into Tib and then parse to a counted string in Wordb
dd MC_WORDNUM
dd C_query
dd C_parse
dd M_exitcolon

CENTRY "line" C_line 4 ; ( -- count ) read from #n/Infd/line into Tib
dd MC_LINENUM
dd C_query
dd M_exitcolon

CENTRY "doublequote" C_doublequote 11 ; ( -- count ) read from #n/Infd/doublequote into Tib
dd MC_DOUBLEQUOTENUM
dd C_query
dd M_literal
dd 1
dd M_minus	; to remove the trailing double quote character from the count
dd M_exitcolon

CENTRY "cdoublequote" C_counted_doublequote 12 ; ( -- 'Wordb ) read from #n/Infd/doublequote into Tib and then parse to a counted string in Wordb
dd C_doublequote
dd C_parse
dd M_exitcolon

CENTRY "closeparen" C_closeparen 10 ; ( -- count ) read from #n/Infd/closeparen
dd MC_CLOSEPARENNUM
dd C_query
dd M_exitcolon

CENTRY "findname" C_findname 8 ; ( a1 -- a2 f ) ; loop through the dictionary names
dd MV_Findadr
dd M_store
dd MV_Dtop
dd M_fetch	; get latest dictionary link

L_findname_loop:	( 'link )	address of link dictionary item
dd C_qdup
dd M_cjump
dd L_findname_not_found	; seached until the first dictionary entry, nil now. get out

dd M_dup	; ( 'link 'link )
dd C_cell_plus	; ( 'link 'len) lenth + initial name address
dd M_cfetch	; ( 'link immediate|hidden|len) length + initial name
dd M_literal
dd 64		; check the reveal'ed flag 1=hidden, 0=reveal
dd M_binand	; if hidden, goto L_findname_previous else L_findname_revealed
dd M_cjump
dd L_findname_revealed
dd M_jump	; smudge'd dictionary entry, get the previous entry
dd L_findname_previous

L_findname_revealed:		; reveal'ed dictionary entry
dd M_dup	; ( 'link 'link )
dd C_cell_plus	; ( 'link 'len )
dd C_count	; ( 'link 'name immediate|hidden|len )
dd M_literal
dd 63
dd M_binand	; ( 'link 'name (immediate|hidden|len)&63=len )
dd MV_Findadr
dd M_fetch	; ( 'link 'name (immediate|hidden|len)&63=len 'find ) 'find = counted string to find
dd C_count	; ( 'link 'name (immediate|hidden|len)&63=len 'find-name find-length )
dd C_compare	; ( 'link f ) compare dictionary entry with name
dd C_0eq	; found a match?
dd M_cjump
dd L_findname_previous	; not matched, try previous link
dd C_cell_plus	; match found
dd C_true
dd M_exitcolon

L_findname_previous:
dd M_fetch	; ( 'previous-link ) compare dictionary entry with name
dd M_jump
dd L_findname_loop	; ( 'previous-link ) looping to check it

L_findname_not_found:	; not found, getting out
dd MV_Findadr
dd M_fetch
dd C_false
dd M_exitcolon	( 'find false ) 'find = address of the name not found

CENTRY "find" C_find 4 ; ( a1 -- a2 f )?
dd C_findname
dd M_cjump
dd L_find_4
dd M_dup
dd M_cfetch
dd M_xswap
dd M_over
dd M_literal
dd 63
dd M_binand
dd M_plus
dd C_1plus
dd C_aligned
dd M_xswap
dd M_literal
dd 128
dd M_binand
dd M_cjump
dd L_find_1
dd M_literal
dd 1
dd M_jump
dd L_find_2
L_find_1:
dd M_literal
dd -1
L_find_2:
dd M_exitcolon
dd M_jump
dd L_find_3
L_find_4:
dd C_false
L_find_3:
dd M_exitcolon

CENTRY "'" C_single_quote 1
dd C_word
dd C_find
dd C_0eq
dd M_cjump
dd L_single_quote_exit
dd C_space
dd C_count
dd C_type
dd M_literal
dd L170
dd C_count
dd C_type
dd C_cr
dd C_abort
L_single_quote_exit:
dd M_exitcolon

CENTRY "?stack" C_qstack 6
dd M_stackptr
dd MV_S0
dd M_greater
dd M_cjump
dd L_qstack_exit
dd M_literal
dd L_stack_underflow_message
dd C_count
dd C_type
dd C_cr
dd C_abort
L_qstack_exit:
dd M_exitcolon

dd MC_STDOUT	; ( str -- str 1) ; debug code to show the word found
dd M_over		; ( str 1 str )
dd C_count 		; ( str 1 a n)
dd M_syswrite
dd M_drop		; drop the return value of write

CENTRY "interpret" C_interpret 9 ; ( 'Wordb -- ) there is a counted string in the Wordb

dd C_find	; ( 'Wordb -- a1 f )
dd M_cjump
dd L_interpret_not_found

dd M_execute	; found in dictionary, execute
dd C_qstack		; check stack status
dd M_exitcolon

L_interpret_not_found:	; ( 'Wordb ) not found in the dictionary, check for number?
dd C_count
dd C_number ; ( a n1 -- n2 -1 | a n1 0 )
dd C_0eq
dd M_cjump
dd L_interpret_exit
dd C_space	; the word is neither in the dictionary nor a number
dd C_type	; show the word
dd M_literal
dd L_unknown_interpret_input	; error I?
dd C_count
dd C_type
dd C_cr
dd C_abort

L_interpret_exit:		; is a number
dd M_exitcolon

CENTRY "create" C_create 6	; compiles dictionary header until the pfa (link, len, name, cfa)
dd C_align	; sets Dp = aligned here
dd C_here	; ( -- here )
dd M_rpush	; ( -- ) (R -- linkaddr )
dd MV_Dtop	; ( -- Dtop ) (R -- linkaddr )
dd M_fetch	; ( Dtop -- dtop ) (R -- linkaddr )
dd C_comma	; ( dtop -- ) (R -- linkaddr )
dd C_word	; get the word from the input stream ( -- 'counted-string ) in Wordb
dd M_dup	; ( a -- a a ) (R -- linkaddr )
dd M_cfetch	; ( a a -- a len ) (R -- linkaddr )
dd C_here	; ( a len -- a len here ) (R -- linkaddr )
dd M_xswap	; ( a len here -- a here len ) (R -- linkaddr )
dd C_1plus	; ( a here len -- a here len+1 ) (R -- linkaddr ) using len+1 to copy even the length byte
dd M_dup	; ( a here len+1 -- a here len+1 len+1 ) (R -- linkaddr )
dd M_rpush	; ( a here len+1 len+1 -- a here len+1 ) (R -- linkaddr len+1 )
dd M_cmove	; ( a here len+1 -- ) (R -- linkaddr len+1 )
dd M_rpop	; ( -- len+1 ) (R -- linkaddr )
dd C_allot	; ( -- ) (R -- linkaddr ) here = here+len+1
dd C_align	; sets Dp = aligned here
dd M_literal
dd M_variable
dd M_fetch	; ( -- variablecfa) (R -- linkaddr )
dd C_comma	; ( -- ) put the variablecfa into the cfa
dd M_rpop	; ( -- linkaddr) (R -- )
dd MV_Dtop
dd M_store	; Dtop = just created link address
dd M_exitcolon

CENTRY "variable" C_variable 8	; compile to put the there then on the stack
dd C_create
dd C_there
dd C_comma	; put the next available variable location in pfa

dd M_literal
dd 1
dd C_cells
dd C_vallot	; there = there+8, stored at Vp
dd M_exitcolon

CENTRY "constant" C_constant 8 ; ( n -- ) do the same as variable but change the cfa to (constant)
dd C_create	; create dictionary header upto the cfa
dd M_literal
dd M_constant
dd M_fetch	; ( Contstantcfa -- (constant) )
dd C_here	; ( (constant) -- (constant) here )
dd M_literal
dd 1
dd C_cells	; ( (constant) here -- (constant) here 8 )
dd M_minus	; ( (constant) here 8 -- (constant) here-8 )
dd M_store	; ( (constant) here-8 -- ) changed cfa from (variable) to (constant) 
dd C_comma	; store n into the dictionary
dd M_exitcolon

CENTRY "immediate" C_immediate 9 ; set immediate flag on the latest defined dictionary entry
dd MV_Dtop
dd M_fetch
dd C_cell_plus
dd M_dup
dd M_cfetch
dd M_literal
dd 128
dd M_binor
dd M_xswap
dd M_cstore
dd M_exitcolon

CENTRY ">cfa" C_tocfa 4
dd C_count
dd M_literal
dd 63
dd M_binand
dd M_plus
dd C_aligned
dd M_exitcolon

CENTRY "compile" C_compile 7
dd C_findname

dd M_cjump
dd L_compile_not_found	; not found in the dictionary

dd M_dup	; found in the dictionary
dd M_cfetch	; get the immediate|hidden|len byte
dd M_literal
dd 128
dd M_binand
dd M_cjump
dd L_compile_1	; not immediate
dd C_tocfa	; immediate
dd M_execute
dd C_qstack
dd M_jump
dd L_compile_done

L_compile_1:	; not immediate
dd C_tocfa	; store cfa into the dictionary
dd C_comma

L_compile_done:
dd M_jump
dd L_compile_exit

L_compile_not_found:
dd C_count
dd C_number	; ( a n1 -- n2 -1 | a n1 0 )
dd C_0eq
dd M_cjump
dd L_compile_parsed_number
dd C_space
dd C_type
dd M_literal
dd L_unknown_compile_input
dd C_count
dd C_type
dd C_cr
dd C_abort
dd M_jump
dd L_compile_exit

L_compile_parsed_number:
dd M_literal
dd M_literal
dd C_comma
dd C_comma

L_compile_exit:
dd M_exitcolon

CENTRY "]" C_close_bracket 1
dd MV_State
dd C_on
L_close_bracket:
dd C_word
dd M_dup
dd M_cfetch
dd C_0eq
dd M_cjump
dd L_close_bracket_1
dd M_drop
dd C_word
dd M_jump
dd L_close_bracket_2
L_close_bracket_1:
dd C_compile
dd MV_State
dd M_fetch
L_close_bracket_2:
dd M_cjump
dd L_close_bracket_3
dd M_jump
dd L_close_bracket
L_close_bracket_3:
dd M_exitcolon

CIENTRY "[" CI_open_bracket 1
dd MV_State
dd C_off
dd M_exitcolon

CENTRY "smudge" C_smudge 6
dd MV_Dtop
dd M_fetch
dd C_cell_plus
dd M_dup
dd M_cfetch
dd M_literal
dd 64
dd M_binor
dd M_xswap
dd M_cstore
dd M_exitcolon

CENTRY "reveal" C_reveal 6
dd MV_Dtop
dd M_fetch
dd C_cell_plus
dd M_dup
dd M_cfetch
dd M_literal
dd 64
dd C_invert
dd M_binand
dd M_xswap
dd M_cstore
dd M_exitcolon

CENTRY ":" C_colon 1
dd C_create	; create a dictionary header with (variable) at cfa
dd C_smudge
dd M_literal
dd M_colon
dd M_fetch	; ( Coloncfa -- (colon) ) fetches the cfa of M_colon
dd C_here	; ( (colon) -- (colon) here )
dd M_literal
dd 1
dd C_cells
dd M_minus	; ( (colon) here -- (colon) here-8 )
dd M_store	; ( (colon) here-8 -- ) change the cfa from (variable) to colon
dd C_close_bracket
dd M_exitcolon

CIENTRY ";" CI_semicolon 1
dd M_literal
dd M_exitcolon
dd C_comma
dd MV_State
dd C_off
dd C_reveal
dd M_exitcolon

CIENTRY "recurse" CI_recurse 7
dd MV_Dtop
dd M_fetch
dd C_cell_plus
dd C_tocfa
dd C_comma
dd M_exitcolon

CENTRY "char" C_char 4	; ( -- c ) fetch the first character of the next word from input
dd C_word	; ( -- a ) puts the address of the counted string from the input on the stack
dd C_1plus	; skip the count
dd M_cfetch	; fetch the first character
dd M_exitcolon

CENTRY "literal" C_literal 7	; ( n -- ) adds (literal) n to the dictionary
dd M_literal
dd M_literal
dd C_comma
dd C_comma
dd M_exitcolon

CENTRY "sliteral" C_sliteral 8	; ( -- ) adds (sliteral) a n to the dictionary
dd M_literal
dd M_sliteral
dd C_comma	; adds (sliteral) to the dictionary
dd C_here	; ( here )

dd C_counted_doublequote	; ( here 'Wordb ) Wordb has the counted string
dd M_dup	; ( here 'Wordb 'Wordb )
dd M_cfetch	; ( here 'Wordb count )
dd C_1plus	; ( here 'Wordb count+1 )
dd M_rpush	; ( here 'Wordb ) (R count+1 )
dd M_xswap	; ( 'Wordb here ) (R count+1 )
dd M_rfetch	; ( 'Wordb here count+1 ) (R count+1 )
dd M_cmove	; ( ) (R count+1 )
dd M_rpop
dd C_allot	; here = here+count+1
dd C_align	; align here
dd M_exitcolon

CENTRY "string" C_string 6 ; ( -- ) store the following word as a counted string onto the dictionary
dd C_word
dd M_dup
dd M_cfetch
dd C_1plus
dd M_rpush
dd C_here
dd M_rfetch
dd M_cmove
dd M_rpop
dd C_allot
dd M_exitcolon

CIENTRY "[char]" CI_char_brackets 6	; take the next character from the input stream during compilation
dd C_word	; assuming that the character is a 1-byte word
dd C_1plus
dd M_cfetch
dd C_literal
dd M_exitcolon

CIENTRY "[']" CI_quote_brackets 3 ; take the address of next token from the input stream during compilation
dd C_single_quote
dd C_literal
dd M_exitcolon

CIENTRY "(" CI_openparen 1	; ignore until ) from the input stream during compilation
dd C_closeparen
dd M_drop
dd M_exitcolon

CIENTRY "\\" CI_backslash 1 ; if the line is longer than 4096, C_query throws an error
dd C_line
dd M_drop
dd M_exitcolon

CENTRY "(?abort)" C_qabort_parens 8
dd MV_State
dd M_cjump
dd L_qabort_parens
dd C_space
dd C_type
dd C_cr
dd C_abort
dd M_jump
dd L_qabort_parens_1
L_qabort_parens:
dd C_2drop
L_qabort_parens_1:
dd M_exitcolon

CIENTRY "abort\"" CI_abort_double_quote 6
dd C_sliteral
dd M_literal
dd C_qabort_parens
dd C_comma
dd M_exitcolon

; could make this work for strings longer than 256 bytes.
; But, for now, strings longer than 256 bytes are not supported by " or c" or s" or ."
; this does not store the count in the dictionary
CENTRY "\"" C_double_quote 1	; ( | .. " -- 'text count ) stores string in the dictionary and also leaves the address and count of the string on the stack - to use strings at the interpreter prompt
dd C_counted_doublequote	; ( 'Wordb )
dd C_count			; ( 'Wordb+1 count )
dd M_rpush			; ( 'Wordb+1 ) (R count )
dd C_here			; ( 'Wordb+1 here ) (R count )
dd M_rfetch			; ( 'Wordb+1 here count ) (R count )
dd M_cmove

dd C_here	; ( here )
dd M_rpop	; ( here count )
dd M_dup	; ( here count count )
dd C_allot	; ( here count ) here = here+count
dd M_exitcolon

CENTRY "c\"" C_counted_double_quote 2	; ( | ..." -- 'counted-string ) stores counted string in the dictionary. For use in interpretive mode.
dd C_counted_doublequote	; ( 'Wordb )
dd M_dup			; ( 'Wordb 'Wordb )
dd M_cfetch			; ( 'Wordb count )
dd C_1plus			; ( 'Wordb count+1 )
dd M_rpush			; ( 'Wordb ) (R count+1 )
dd C_here			; ( 'Wordb here ) (R count+1 )
dd M_rfetch			; ( 'Wordb here count ) (R count+1 )
dd M_cmove

dd C_here	; ( here )
dd M_rpop	; ( here count+1 )
dd C_allot	; ( here ) here = here+count+1
dd M_exitcolon

; for compiling counted strings into the definition. Puts the ( 'text count ) on the stack at run time
CIENTRY "s\"" CI_sdouble_quote 2	; ( | ..." -- 'text count ) add the string from the input stream to the dictionary as (sliteral) count string - at run-time puts the ( -- addr n) of the counted string on the stack.
dd C_sliteral
dd M_exitcolon

CIENTRY ".\"" CI_dotstr 2	; ( | ..." -- ) ." = s" type
dd C_sliteral
dd M_literal
dd C_type
dd C_comma
dd M_exitcolon

CIENTRY "if" CI_if 2
dd M_literal
dd M_cjump
dd C_comma
dd C_here
dd M_literal
dd 0
dd C_comma
dd M_exitcolon
CIENTRY "else" CI_else 4
dd M_literal
dd M_jump
dd C_comma
dd C_here
dd M_rpush
dd M_literal
dd 0
dd C_comma
dd C_here
dd M_xswap
dd M_store
dd M_rpop
dd M_exitcolon
CIENTRY "then" CI_then 4
dd C_here
dd M_xswap
dd M_store
dd M_exitcolon
CIENTRY "begin" CI_begin 5
dd C_here
dd M_exitcolon
CIENTRY "again" CI_again 5
dd M_literal
dd M_jump
dd C_comma
dd C_comma
dd M_exitcolon
CIENTRY "until" CI_until 5
dd M_literal
dd M_cjump
dd C_comma
dd C_comma
dd M_exitcolon
CIENTRY "while" CI_while 5
dd M_literal
dd M_cjump
dd C_comma
dd C_here
dd M_literal
dd 0
dd C_comma
dd M_exitcolon
CIENTRY "repeat" CI_repeat 6
dd M_literal
dd M_jump
dd C_comma
dd M_xswap
dd C_comma
dd C_here
dd M_xswap
dd M_store
dd M_exitcolon
CIENTRY "do" CI_do 2
dd M_literal
dd M_doinit		; compile this into the definition. Puts limit and index on the run stack at run time
dd C_comma		; puts (do) into the dictionary
dd M_literal
dd 0			; ( -- 0 )
dd C_here		; ( 0 -- 0 here1 )
dd M_exitcolon
CIENTRY "loop" CI_loop 4	; ( 0 here1 -- )
dd M_literal
dd M_doloop		; ( 0 here1 -- 0 here1 (loop) )
dd C_comma		; dictionary has (do) ... (loop) ( 0 here1 (loop) -- 0 here1 )
dd C_comma		; dictionary has (do) ... (loop) here1 ( 0 here1 -- 0 )
dd C_qdup
dd M_cjump
dd L234
dd C_here
dd M_xswap
dd M_store
L234:
dd M_exitcolon
CIENTRY "+loop" CI_ploop 5
dd M_literal
dd M_doploop
dd C_comma
dd C_comma
dd C_qdup
dd M_cjump
dd L236
dd C_here
dd M_xswap
dd M_store
L236:
dd M_exitcolon
CENTRY "r/o" C_ro 3
dd M_literal
dd 0
dd M_exitcolon
CENTRY "w/o" C_wo 3
dd M_literal
dd 1
dd M_exitcolon
CENTRY "r/w" C_rw 3
dd M_literal
dd 2
dd M_exitcolon

CENTRY "cstring" C_cstring 7 ; ( 'text count o -- o+'pad+1024 ) \ copy string to pad+o and add a null byte at the end
dd C_pad	; ( 'text count o 'pad )
dd M_literal
dd 1024		; ( 'text count o 'pad 1024 )
dd M_plus	; ( 'text count o 'pad+1024 )
dd M_plus	; ( 'text count o+'pad+1024 ) o=padoffset
dd M_dup
dd M_rpush	; ( 'text count o+'pad+1024 ) (R o+'pad+1024 )
dd M_xswap	; ( 'text o+'pad+1024 count ) (R o+'pad+1024 )
dd M_dup	; ( 'text o+'pad+1024 count count ) (R o+'pad+1024 )
dd M_rpush	; ( 'text o+'pad+1024 count ) (R o+'pad+1024  count )
dd M_cmove	; moves the filename from 'text to o+'pad+1024
dd M_literal
dd 0		; ( 0 ) (R o+'pad+1024  count )
dd M_rpop	; ( 0 count ) (R o+'pad+1024 )
dd M_rfetch	; ( 0 count o+'pad+1024 ) (R o+'pad+1024 )
dd M_plus	; ( 0 count+o+'pad+1024 ) (R o+'pad+1024 )
dd M_cstore	; makes the filename to a null terminated string
dd M_rpop ;  ( o+'pad+1024 )
dd M_exitcolon

CENTRY "cstring0" C_cstring0 8 ; ( 'text count -- 'text ) \ copy string to pad+1024 and add a null byte at the end
dd M_literal
dd 0
dd C_cstring
dd M_exitcolon

CENTRY "cstring1" C_cstring1 8 ; ( 'text count -- 'text ) \ copy string to pad+1536 and add a null byte at the end
dd M_literal
dd 512
dd C_cstring
dd M_exitcolon

CENTRY "open-file" C_open_file 9 ; ( 'text count mode -- fd ioresult )
dd M_rpush	; ( 'text count ) (R mode)
dd C_cstring0 ; ( 'padtext ) (R mode )
dd M_rpop	; ( 'padtext mode ) (R )
dd M_sysopen
dd M_dup
dd M_literal
dd -1
dd M_greater
dd M_exitcolon

CENTRY "close-file" C_close_file 10	; ( fd -- ioresult )
dd M_sysclose
dd C_0eq
dd M_exitcolon

CENTRY "read-file" C_read_file 9	; ( fd 'text count -- count2 ioresult )
dd M_sysread
dd M_dup
dd M_literal
dd -1
dd C_neq
dd M_exitcolon

CENTRY "write-file" C_write_file 10	; ( fd 'text count -- ioresult )
dd M_syswrite
dd M_literal
dd -1
dd C_neq
dd M_exitcolon

CENTRY "reposition-file" C_reposition_file 15	;	( fd n type -- ioresult )
dd M_sysseek
dd M_literal
dd -1
dd C_neq
dd M_exitcolon

CENTRY "?fcheck" C_qfcheck 7
dd C_0eq
dd M_cjump
dd L_qfcheck_exit
dd C_space
dd M_literal
dd L_io_error
dd C_count
dd C_type
dd C_cr
dd C_abort
L_qfcheck_exit:
dd M_exitcolon

CENTRY "create-file" C_create_file 11 ; ( a n mode perm -- fd ioresult ) not part of the original ff. could move this to a forth file.
dd M_rpush	; ( a n mode ) (R perm)
dd M_rpush	; ( a n ) (R perm mode)
dd C_pad	; ( a n padaddr)
dd M_literal
dd 1024		; ( a n padaddr 1024 )
dd M_plus	; ( a n padaddr+1024 )
dd M_xswap	; ( a padaddr+1024 n )
dd M_dup	; ( a padaddr+1024 n n )
dd M_rpush	; ( a padaddr+1024 n ) (R perm mode n )
dd M_cmove	; moves the filename from a to paddaddr+1024
dd M_literal
dd 0		; ( 0 )
dd M_rpop	; ( 0 n ) (R perm mode)
dd C_pad	; ( 0 n padaddr)
dd M_plus	; ( 0 padaddr+n )
dd M_literal
dd 1024		; ( 0 padaddr+n 1024 )
dd M_plus	; ( 0 padaddr+n+1024 )
dd M_cstore	; ( ) makes the filename to a null terminated string
dd C_pad
dd M_literal
dd 1024		; ( padaddr 1024 )
dd M_plus	; ( padaddr+1024 )
dd M_rpop	; ( padaddr+1024 mode) (R perm )
dd M_rpop	; ( padaddr+1024 mode perm ) (R )
dd M_syscreate
dd M_dup
dd M_literal
dd -1
dd M_greater
dd M_exitcolon

CENTRY "bye" C_bye 3
dd M_literal
dd 0
dd M_terminate
dd M_exitcolon

CENTRY "include" C_include 7	; this does not work
dd C_word

dd M_rpush

dd C_input_fetch	; save the old input onto the stack and clears the input bufferfds

dd M_rpop
dd C_count
dd C_ro
dd C_open_file

dd C_qfcheck

dd MV_Infd		; open the new file
dd M_store
dd M_exitcolon

CENTRY "crash" C_crash 5
dd M_literal
dd L251
dd C_count
dd C_type
dd C_cr
dd C_abort
dd M_exitcolon

CENTRY "quit" C_quit 4 ; interpreter loop
dd M_reset ; initialize return stack
dd M_clear	; SP = sstack_end initialize data stack

L_quit_interpreter_loop:
dd C_word
dd C_interpret
dd M_jump
dd L_quit_interpreter_loop
dd M_exitcolon	; why is this needed?

CENTRY "(abort)" C_parenabort 7 ; TODO correct below stack notations
dd MV_State	; ( mv_State -- )
dd C_off	; off sets variable state = 0

dd MC_STDIN
dd MV_Infd
dd M_store
dd MC_STDOUT
dd MV_Outfd
dd M_store
dd MC_STDERR
dd MV_Errfd
dd M_store

dd C_stdinput
dd C_quit	; quit resets stacks and is the interpreter loop
dd M_exitcolon	; why is this needed? quit does not return unless it breaks


dd M_literal	; test code
dd 66
dd MV_Wordb
dd M_store
dd MC_STDOUT
dd MV_Wordb
dd M_literal
dd 1
dd M_syswrite
dd M_drop		; drop the return value of write
dd MC_STDIN
dd MV_Wordb
dd M_literal
dd 1
dd M_sysread
dd M_drop		; drop the return value of read

CENTRY "initialize" C_initialize 10	; initialize buffer file names and buffer fds, why not hard code this?
dd MV_Bufferfds
dd MC_NBUFFERS
dd M_literal
dd 0
dd M_doinit
L_initialize_fd_loop:

dd M_dup
dd M_literal
dd -1
dd M_xswap
dd M_store

dd M_literal
dd 1
dd C_cells
dd M_plus

dd M_doloop
dd L_initialize_fd_loop
dd M_drop

dd MV_Bufferfilenames
dd MC_NBUFFERS
dd M_literal
dd 0
dd M_doinit
L_initialize_filename_loop:

dd M_dup
dd M_literal
dd 0
dd M_xswap
dd M_store

dd M_literal
dd 1
dd C_cells
dd M_plus

dd M_doloop
dd L_initialize_filename_loop
dd M_drop

dd M_literal
dd L_line_filename
dd C_wordfilename_store

dd M_literal
dd L_word_filename
dd C_linefilename_store

dd M_literal
dd L_doublequote_filename
dd C_doublequotefilename_store

dd M_literal
dd L_closeparen_filename
dd C_closeparenfilename_store
dd M_exitcolon

CENTRY "debug" C_debug 5 ; ( n -- ) show the n along with the debug message and depth
dd M_literal
dd L_debug_msg
dd C_count
dd C_type

dd C_dot
dd C_space

dd C_depth
dd C_dot
dd C_cr
dd M_exitcolon

CENTRY "boot" C_boot 4
dd M_reset ; initialize return stack
dd M_clear	; SP = sstack_end initialize data stack

dd M_literal
dd C_parenabort ; ( (abort) -- )
dd MV_Abortvec	; variable that puts (abort) code address on the stack
dd M_store	; variable abortvec = (abort) code address

dd MC_STDIN
dd MV_Infd	; might be overwritten by args below
dd M_store	; stdin = 0
dd MC_STDOUT
dd MV_Outfd
dd M_store
dd MC_STDERR
dd MV_Errfd
dd M_store

dd MV_State
dd C_off	; off stores 0 at state
dd C_decimal	; decimal sets base = 10

dd C_initialize	; sets up the buffer filenames and buffer fd's

dd C_args	; process args

dd C_quit	; interpreter loop when there are no args or fall through after processing args
dd M_exitcolon

; putting the strings at the bottom to not mess with cell alignment above
L_bin_prefix:
db "#n/"
L_line_filename:
db "/word"
L_word_filename:
db "/line"
L_doublequote_filename:
db "/doublequote"
L_closeparen_filename:
db "/closeparen"

L_restore_input_error_message:
db "unable to restore input from the stack, aborting.." ; comments for testing the awk parser
L_open_failed:
db "open file failed"
L_read_failed:
db "read file failed"
L170:
db " Q?"
L_stack_underflow_message:
db " stack underflow"
L_unknown_interpret_input:
db " I?"
L_unknown_compile_input:
db " C?"
L_io_error:
db "I/O error"
L251:
db "uninitialized execution vector"
L255:
db " ok"
L_query_too_long:
db "input is longer than 4096 bytes without a delimiter"
L305:
db "read error"
L_long_word:
db "word is too long to be interpreted"
L_debug_msg:
db "debug message "