1
0
mirror of https://github.com/dschmenk/PLASMA.git synced 2024-06-01 03:41:34 +00:00
PLASMA/src/toolsrc/plforth.pla

1958 lines
39 KiB
Plaintext

include "inc/cmdsys.plh"
include "inc/args.plh"
include "inc/fileio.plh"
include "inc/conio.plh"
include "inc/longjmp.plh"
//
// Internal variables
//
word vlist, infunc, inptr, IIP, W
word vmvect, startheap, arg
word keyinbuf = $1FF
const JSR = $20 // 6502 JSR opcode needed for VM entry
const SRCREFS = 2
const INBUF_SIZE = 128
byte srclevel = 0
word inbufptr
byte inref[SRCREFS]
word previnptr[SRCREFS]
//
// Internal buffers
//
res[SRCREFS * INBUF_SIZE] inbuf
res[t_except] exitforth
//
// RSTACK
//
const RSTK_SIZE = 16
byte RSP = RSTK_SIZE
word RSTACK[RSTK_SIZE]
//
// Vocabulary hash table
//
const HASH_SIZE = 64 // Must be power of two!
const HASH_MASK = HASH_SIZE-1
word hashtbl[HASH_SIZE]
//
// State flags
//
const exit_flag = $01
const trace_flag = $02
const step_flag = $04
const comp_itc_flag = $10
const comp_pbc_flag = $20
const comp_flag = comp_itc_flag | comp_pbc_flag
//
// Mode and state
//
byte comp_mode = comp_itc_flag
byte state = 0
byte savestate = 0
word brkentry = 0
word brkcfa = 0
byte brk = 0
byte _get_estack = $8A // TXA
byte = $49, $FF // EOR #$FF
byte = $38 // SEC
byte = $69, $10 // ADC #$10
byte = $C9, $11 // CMP #$11
byte = $90, $02 // BCC +2
byte = $A2, $10 // LDX #ESTKSZ/2
byte = $CA // DEX
byte = $95 // STA
byte _estkl = $D0 // ESTKL,X
byte = $A9, $00 // LDA #$00
byte = $95 // STA
byte _estkh = $C0 // ESTKH,X
byte = $60 // RTS
byte _reset_estack = $A2, $10 // LDX #ESTKSZ/2
byte = $60 // RTS
//
// FORTH dictionary layout
//
// bytes usage
// ----- -----
// [1] name length
// [1..255] name
// [1] FFA (flag field address)
// [2] LFA (link field address)
// [2] HFA (hash field address)
// [2] CFA (code field address)
// [2..] PFA (param field address)
//
//
// Mask and flags for dictionary entries
//
const inline_flag = $01
const inlinew_flag = $02
const param_flag = $04
const showcr_flag = $08 // Help pretty print SHOW
const itc_flag = $10
const imm_flag = $20
const componly_flag = $40
const interponly_flag = $80
//
// Predefine instrinsics
//
predef _swap_(a,b)#2, _dashdup_(a)#1, _over_(a,b)#3, _rot_(a,b,c)#3
predef _abs_(a)#1, _max_(a,b)#1, _min_(a,b)#1, _wplusset_(a,b)#0
predef _ffa_(a)#1, _lfa_(a)#1, _hfa_(a)#1, _cfa_(a)#1, _pfa_(a)#1, _allot_(a)#0
predef _branch_#0, _0branch_(a)#0, _if_#0, _else_#0, _then_#0
predef _begin_#0, _again_#0, _until_#0, _while_#0, _repeat_#0
predef _case_#0, _of_#0, _endof_#0, _endcase_#0
predef _dodo_(a,b)#0, _do_#0, _doloop_#0, _doplusloop_(a)#0, _plusloop_#0, _loop_#0, _leave_#0, _j_#1
predef _create_#0, _itcdoes_(a)#0, _does_#0, _compoff_#0, _compon_#0
predef _compile_#0, _dictaddw_(a)#0, _dictaddb_(a)#0, _colon_#0, _semi_#0
predef _componly_#0, _interponly_#0, _immediate_#0, _exit_#0, _pad_#1, _trailing_(a,b)#2
predef _tors_(a)#0, _fromrs_#1, _toprs_#1, _lookup_#1
predef _cmove_(a,b,c)#0, _move_(a,b,c)#0, _fill_(a,b,c)#0, _plasma_(a)#0
predef _var_(a)#0, _const_(a)#0, _lit_#1, _slit_#1, _find_(a)#2
predef _tick_#0, _forget_#0, _terminal_#1, _key_#1, _prat_(a)#0
predef _blank_#0, _char_#0, _str_#0, _prstr_#0, _prpstr_#0
predef _prval_(a)#0, _prbyte_(a)#0, _prhex_(a)#0, _accept_(a,b)#1, _type_(a,b)#0
predef _vlist_#0, _tron_#0, _troff_#0, _stepon_#0, _stepoff_#0
predef _itc_#0, _pbc_#0, _comment_#0, _src_(a)#0, _srcstr_#0, _endsrc_(a)#0
predef _brk_#0, _brkon_#0, _brkoff_#0, _word_(a)#1, _count_(a)#2
predef _space_#0, _spaces_(a)#0, _show_#0, _showstack_#0, _showrstack_#0
predef _cont_#0, _restart_#0, _bye_#0, _quit_#0
predef _abort_(a)#0, _doabortstr_(a,b)#0, _abortstr_#0
predef _compword_(dentry)#0, _compliteral_(a)#0, _execword_(dentry)#0, _isnum_(a,b)#2
// DROP
char d_drop = "DROP"
byte = inline_flag | showcr_flag
word = 0, 0, 0, $30
// SWAP
char d_swap = "SWAP"
byte = 0
word = @d_drop, 0, @_swap_
// DUP
char d_dup = "DUP"
byte = inline_flag
word = @d_swap, 0, 0, $34
// -DUP
char d_dashdup = "-DUP"
byte = 0
word = @d_dup, 0, @_dashdup_
// OVER
word d_over = "OVER"
byte = 0
word = @d_dashdup, 0, @_over_
// ROT
word d_rot = "ROT"
byte = 0
word = @d_over, 0, @_rot_
// ADD
char d_add = "+"
byte = inline_flag
word = @d_rot, 0, 0, $82
// ONE PLUS
char d_inc = "1+"
byte = inline_flag
word = @d_add, 0, 0, $8C
// TWO PLUS
char d_inc2 = "2+"
byte = inlinew_flag
word = @d_inc, 0, 0, $8C8C
// ONE MINUS
char d_dec = "1-"
byte = inline_flag
word = @d_inc2, 0, 0, $8E
// TWO MINUS
char d_dec2 = "2-"
byte = inlinew_flag
word = @d_dec, 0, 0, $8E8E
// SUB
char d_sub = "-"
byte = inline_flag
word = @d_dec2, 0, 0, $84
// MUL
char d_mul = "*"
byte = inline_flag
word = @d_sub, 0, 0, $86
// DIV
char d_div = "/"
byte = inline_flag
word = @d_mul, 0, 0, $88
// DIVMOD
char d_divmod = "/MOD"
byte = inline_flag
word = @d_div, 0, 0, $36
// MOD
char d_mod = "MOD"
byte = inline_flag
word = @d_divmod, 0, 0, $8A
// NEG
char d_neg = "NEGATE"
byte = inline_flag
word = @d_mod, 0, 0, $90
// AND
char d_and = "AND"
byte = inline_flag
word = @d_neg, 0, 0, $94
// OR
char d_or = "OR"
byte = inline_flag
word = @d_and, 0, 0, $96
// XOR
char d_xor = "XOR"
byte = inline_flag
word = @d_or, 0, 0, $98
// COMPLEMENT
char d_complement = "COMPLEMENT"
byte = inline_flag
word = @d_xor, 0, 0, $92
// NOT
char d_not = "NOT"
byte = inline_flag
word = @d_complement, 0, 0, $80
// LEFT SHIFT
char d_lshift = "LSHIFT"
byte = inline_flag
word = @d_not, 0, 0, $9A
// RIGHT SHIFT
char d_rshift = "RSHIFT"
byte = inline_flag
word = @d_lshift, 0, 0, $9C
// EQUALS
char d_eq = "="
byte = inline_flag
word = @d_rshift, 0, 0, $40
// GREATER THAN
char d_gt = ">"
byte = inline_flag
word = @d_eq, 0, 0, $44
// LESS THAN
char d_lt = "<"
byte = inline_flag
word = @d_gt, 0, 0, $46
// UNSIGNED GREATER THAN
char d_ugt = "U>"
byte = 0
word = @d_lt, 0, @isugt
// UNSIGNED LESS THAN
char d_ult = "U<"
byte = 0
word = @d_ugt, 0, @isult
// LESS THAN ZERO
char d_0lt = "0<"
byte = inlinew_flag
word = @d_ult, 0, 0, $4600 // ZERO ISLT
// EQUALS ZERO
char d_0eq = "0="
byte = inlinew_flag
word = @d_0lt, 0, 0, $4000 // ZERO ISEQ
// ABS
char d_abs = "ABS"
byte = 0
word = @d_0eq, 0, @_abs_
// MIN
char d_min = "MIN"
byte = 0
word = @d_abs, 0, @_min_
// MAX
char d_max = "MAX"
byte = 0
word = @d_min, 0, @_max_
// CHAR PUT
char d_cset = "C!"
byte = inline_flag | showcr_flag
word = @d_max, 0, 0, $70
// WORD PUT
char d_wset = "!"
byte = inline_flag | showcr_flag
word = @d_cset, 0, 0, $72
// WORD PLUS PUT
char d_wplusset = "+!"
byte = showcr_flag
word = @d_wset, 0, @_wplusset_
// CHAR GET
char d_cget = "C@"
byte = inline_flag
word = @d_wplusset, 0, 0, $60
// WORD SET
char d_wget = "@"
byte = inline_flag
word = @d_cget, 0, 0, $62
// EXECUTE
char d_execute = "EXECUTE"
byte = showcr_flag
word = @d_wget, 0, @_execword_
// TO RSTACK
char d_torstk = ">R"
byte = showcr_flag
word = @d_execute, 0, @_tors_
// FROM RSTACK
char d_fromrstk = "R>"
byte = 0
word = @d_torstk, 0, @_fromrs_
// TOP OF RSTACK
char d_toprstk = "R@"
byte = 0
word = @d_fromrstk, 0, @_toprs_
// PLASMA SYMBOL LOOKUP
char d_lookup = "LOOKUP"
byte = 0
word = @d_toprstk, 0, @_lookup_
// PLASMA LINKEAGE
char d_plasma = "PLASMA"
byte = interponly_flag
word = @d_lookup, 0, @_plasma_
// VARIABLE
char d_var = "VARIABLE"
byte = interponly_flag
word = @d_plasma, 0, @_var_
// CONSTANT
char d_const = "CONSTANT"
byte = interponly_flag
word = @d_var, 0, @_const_
// CMOVE
char d_cmove = "CMOVE"
byte = showcr_flag
word = @d_const, 0, @_cmove_
// MOVE
char d_move = "MOVE"
byte = showcr_flag
word = @d_cmove, 0, @_move_
// FILL
char d_fill = "FILL"
byte = showcr_flag
word = @d_cmove, 0, @_fill_
// HERE
char d_here = "HERE"
byte = 0
word = @d_fill, 0, @heapmark
// PAD
char d_pad = "PAD"
byte = 0
word = @d_here, 0, @_pad_
// ALLOT
char d_allot = "ALLOT"
byte = showcr_flag
word = @d_pad, 0, @_allot_
// BRANCH ( not in vocabulary )
char d_branch = "(BRANCH)"
byte = param_flag | inline_flag | showcr_flag
word = 0, 0, @_branch_, $C4
// BRANCH IF 0 ( not in vocabulary )
char d_0branch = "(0BRANCH)"
byte = param_flag | inline_flag | showcr_flag
word = 0, 0, @_0branch_, $C2
// IF
char d_if = "IF"
byte = imm_flag | componly_flag
word = @d_allot, 0, @_if_
// ELSE
char d_else = "ELSE"
byte = imm_flag | componly_flag
word = @d_if, 0, @_else_
// THEN
char d_then = "THEN"
byte = imm_flag | componly_flag
word = @d_else, 0, @_then_
// CASE
char d_case = "CASE"
byte = imm_flag | componly_flag
word = @d_then, 0, @_case_
// OF
char d_of = "OF"
byte = imm_flag | componly_flag
word = @d_case, 0, @_of_
// ENDOF
char d_endof = "ENDOF"
byte = imm_flag | componly_flag
word = @d_of, 0, @_endof_
// ENDCASE
char d_endcase = "ENDCASE"
byte = imm_flag | componly_flag
word = @d_endof, 0, @_endcase_
// COMPILED DO ( not in vocabulary )
char d_dodo = "(DO)"
byte = showcr_flag
word = 0, 0, @_dodo_
// DO
char d_do = "DO"
byte = imm_flag | componly_flag
word = @d_endcase, 0, @_do_
// LEAVE
char d_leave = "LEAVE"
byte = componly_flag
word = @d_do, 0, @_leave_
// COMPILED LOOP ( not in vocabulary )
char d_doloop = "(DOLOOP)"
byte = param_flag | showcr_flag
word = 0, 0, @_doloop_
// LOOP
char d_loop = "LOOP"
byte = imm_flag | componly_flag
word = @d_leave, 0, @_loop_
// COMPILED LOOP+ ( not in vocabulary )
char d_doplusloop = "(+DOLOOP)"
byte = param_flag | showcr_flag
word = 0, 0, @_doplusloop_
// LOOP
char d_plusloop = "+LOOP"
byte = imm_flag | componly_flag
word = @d_loop, 0, @_plusloop_
// I
char d_i = "I"
byte = componly_flag
word = @d_plusloop, 0, @_toprs_
// J
char d_j = "J"
byte = componly_flag
word = @d_i, 0, @_j_
// BEGIN
char d_begin = "BEGIN"
byte = imm_flag | componly_flag
word = @d_j, 0, @_begin_
// AGAIN
char d_again = "AGAIN"
byte = imm_flag | componly_flag
word = @d_begin, 0, @_again_
// UNTIL
char d_until = "UNTIL"
byte = imm_flag | componly_flag
word = @d_again, 0, @_until_
// WHILE
char d_while = "WHILE"
byte = imm_flag | componly_flag
word = @d_until, 0, @_while_
// REPEAT
char d_repeat = "REPEAT"
byte = imm_flag | componly_flag
word = @d_while, 0, @_repeat_
// FORGET
char d_forget = "FORGET"
byte = interponly_flag
word = @d_repeat, 0, @_forget_
// CREATE
char d_create = "CREATE"
byte = showcr_flag
word = @d_forget, 0, @_create_
// RECREATE/DOES COMPILE TIME ( not in vocabulary )
char d_createdoes = "(CREATEDOES)"
byte = showcr_flag
word = 0, 0, @_itcdoes_
// DOES
char d_does = "DOES>"
byte = imm_flag | componly_flag
word = @d_create, 0, @_does_
// COMMA
char d_comma = ","
byte = showcr_flag
word = @d_does, 0, @_dictaddw_
// COMMA
char d_commab = "C,"
byte = showcr_flag
word = @d_comma, 0, @_dictaddb_
// COLON
char d_colon = ":"
byte = interponly_flag
word = @d_commab, 0, @_colon_
// COMP OFF
char d_compoff = "["
byte = imm_flag | componly_flag
word = @d_colon, 0, @_compoff_
// COMP ON
char d_compon = "]"
byte = interponly_flag
word = @d_compoff, 0, @_compon_
// COMPILE NEXT WORD
char d_compile = "[COMPILE]"
byte = imm_flag | componly_flag
word = @d_compon, 0, @_compile_
// COMPILE ONLY
char d_componly = "COMPONLY"
byte = imm_flag
word = @d_compile, 0, @_componly_
// INTERPRET ONLY
char d_interponly = "INTERPONLY"
byte = imm_flag
word = @d_componly, 0, @_interponly_
// IMMEDIATE
char d_immediate = "IMMEDIATE"
byte = imm_flag
word = @d_interponly, 0, @_immediate_
// EXIT
char d_exit = "EXIT"
byte = imm_flag | componly_flag | showcr_flag
word = @d_immediate, 0, @_exit_
// SEMI
char d_semi = ";"
byte = imm_flag | componly_flag
word = @d_exit, 0, @_semi_
// COUNT
char d_count = "COUNT"
byte = 0
word = @d_semi, 0, @_count_
// FIND
char d_find = "FIND"
byte = 0
word = @d_count, 0, @_find_
// TICK
char d_tick = "'"
byte = imm_flag
word = @d_find, 0, @_tick_
// INLINE LITERAL NUMBER ( not in vocabulary )
char d_lit = "LIT"
byte = param_flag
word = 0, 0, @_lit_
// COMPILED LITERAL VALUE FROM STACK
char d_literal = "LITERAL"
byte = imm_flag | componly_flag
word = @d_tick, 0, @_compliteral_
// ?TERMINAL
char d_terminal = "?TERMINAL"
byte = 0
word = @d_literal, 0, @_terminal_
// KEY
char d_key = "KEY"
byte = 0
word = @d_terminal, 0, @_key_
// ACCEPT
char d_accept = "ACCEPT"
byte = 0
word = @d_key, 0, @_accept_
// WORD
char d_word = "WORD"
byte = 0
word = @d_accept, 0, @_word_
// _isnum_
char d__isnum_ = "?NUM"
byte = 0
word = @d_word, 0, @_isnum_
// -TRAILING
char d_trailing = "-TRAILING"
byte = 0
word = @d__isnum_, 0, @_trailing_
// PRINT @TOS
char d_prat = "?"
byte = showcr_flag
word = @d_trailing, 0, @_prat_
// PRINT TOS
char d_prtos = "."
byte = showcr_flag
word = @d_prat, 0, @_prval_
// PRINT TOS HEX
char d_prtoshex = "$."
byte = showcr_flag
word = @d_prtos, 0, @_prhex_
// PRINT TOS HEX BYTE
char d_prtosbyte = "C$."
byte = showcr_flag
word = @d_prtoshex, 0, @_prbyte_
// EMIT
char d_emit = "EMIT"
byte = 0
word = @d_prtosbyte, 0, @putc
// CR
char d_cr = "CR"
byte = 0
word = @d_emit, 0, @putln
// SPACE
char d_space = "SPACE"
byte = 0
word = @d_cr, 0, @_space_
// SPACES
char d_spaces = "SPACES"
byte = 0
word = @d_space, 0, @_spaces_
// TYPE
char d_type = "TYPE"
byte = 0
word = @d_spaces, 0, @_type_
// BLANK
char d_blank = "BL"
byte = imm_flag
word = @d_type, 0, @_blank_
// CHAR
char d_char = "CHAR"
byte = imm_flag
word = @d_blank, 0, @_char_
// STRING
char d_str = "\""
byte = imm_flag
word = @d_char, 0, @_str_
// LITERAL STRING ( not in vocabulary )
char d_slit = "SLIT"
byte = param_flag | inline_flag
word = 0, 0, @_slit_, $2E
// PRINT STRING FROM STACK
char d_doprstr = "(.\")"
byte = showcr_flag
word = @d_str, 0, @puts
// PRINT STRING
char d_prstr = ".\""
byte = imm_flag
word = @d_doprstr, 0, @_prstr_
// PRINT PAREN STRING
char d_prpstr = ".("
byte = imm_flag
word = @d_prstr, 0, @_prpstr_
// READ SOURCE FILE FROM STACK
char d_src = "SRC"
byte = showcr_flag
word = @d_prpstr, 0, @_src_
// READ SOURCE FILE FROM INPUT
char d_srcstr = "SRC\""
byte = imm_flag
word = @d_src, 0, @_srcstr_
// END SOURCE FILE
char d_endsrc = "ENDSRC"
byte = showcr_flag
word = @d_srcstr, 0, @_endsrc_
// CONTINUE AFTER BRK
char d_cont = "CONT"
byte = interponly_flag
word = @d_endsrc, 0, @_cont_
// QUIT
char d_quit = "QUIT"
byte = showcr_flag
word = @d_cont, 0, @_quit_
// ABORT IF <> 0
char d_abort = "ABORT"
byte = showcr_flag
word = @d_quit, 0, @_abort_
// DOABORTSTR
char d_doabortstr = "(ABORT\")"
byte = showcr_flag
word = @d_abort, 0, @_doabortstr_
// ABORTSTR
char d_abortstr = "ABORT\""
byte = imm_flag
word = @d_doabortstr, 0, @_abortstr_
// COLD exitforth
char d_exitforth = "COLD"
byte = showcr_flag
word = @d_abortstr, 0, @_restart_
// COMMENT
char d_comment = "("
byte = imm_flag | showcr_flag
word = @d_exitforth, 0, @_comment_
//
// PLFORTH custom words
//
// BYE
char d_bye = "BYE"
byte = 0
word = @d_comment, 0, @_bye_
// SHOW DEFINITION
char d_show = "SHOW"
byte = interponly_flag
word = @d_bye, 0, @_show_
// SHOW STACK
char d_showstack = "SHOWSTACK"
byte = 0
word = @d_show, 0, @_showstack_
// SHOW RSTACK
char d_showrstack = "SHOWRSTACK"
byte = 0
word = @d_showstack, 0, @_showrstack_
// TRACE ON
char d_tron = "TRON"
byte = 0
word = @d_showrstack, 0, @_tron_
// TRACE OFF
char d_troff = "TROFF"
byte = 0
word = @d_tron, 0, @_troff_
// SINGLE STEP ON
char d_stepon = "STEPON"
byte = 0
word = @d_troff, 0, @_stepon_
// SINGLE STEP OFF
char d_stepoff = "STEPOFF"
byte = 0
word = @d_stepon, 0, @_stepoff_
// BREAK OUT
char d_brk = "BRK"
byte = 0
word = @d_stepoff, 0, @_brk_
// BREAK ON
char d_brkon = "BRKON"
byte = interponly_flag
word = @d_brk, 0, @_brkon_
// BREAK OFF
char d_brkoff = "BRKOFF"
byte = interponly_flag
word = @d_brkon, 0, @_brkoff_
// COMPILE USING ITC
char d_itc = "ITC"
byte = interponly_flag
word = @d_brkoff, 0, @_itc_
// COMPILE USING PLASMA BYTECODES
char d_pbc = "PBC"
byte = interponly_flag
word = @d_itc, 0, @_pbc_
//
// Start of vocabulary
//
// LIST VOCAB
char d_vlist = "VLIST"
byte = 0
word = @d_pbc, 0, @_vlist_
//
// Helper routines
//
predef _interpret_#0
def push(a)#1 // Stack hack - call as (@push)(a)#0 to leave a on eval stack
return a
end
def _dictaddw_(a)#0
*(heapalloc(2)) = a
end
def _dictaddb_(a)#0
*(heapalloc(1)) = a
end
//
// Input routines
//
def keyin#0
byte i
repeat
puts(brk ?? " BRK\n" :: " OK\n")
inptr = gets(state & comp_flag ?? ']'|$80 :: '>'|$80)
keyinbuf = inptr // Save if needed
until ^inptr
^(inptr + ^inptr + 1) = 0 // NULL terminate
inptr++
end
def endsrc#1
if srclevel > 0
srclevel--
fileio:close(inref[srclevel]) // EOF
inref[srclevel] = 0
inbufptr = inbufptr - INBUF_SIZE
inptr = previnptr[srclevel]
if srclevel == 0 // - switch back to keyboard input
infunc = @keyin
keyin
fin
fin
return srclevel == 0
end
def filein#0
byte len
repeat
len = fileio:read(inref[srclevel-1], inbufptr, INBUF_SIZE-1)
if len
if ^(inbufptr + len - 1) == $0D
len-- // Remove trailing carriage return
fin
^(inbufptr + len) = 0 // NULL terminate
inptr = inbufptr
else
if endsrc
return
fin
fin
until len
end
def nextword(delim)#2
word wordptr
byte len
repeat
if !^inptr
infunc()#0
fin
while ^inptr == delim // Skip leading delimiter
inptr++
loop
until ^inptr
wordptr = inptr
while ^inptr and ^inptr <> delim // Tokenize characters
inptr++
loop
len = inptr - wordptr
if ^inptr // Skip trailing delimiter
inptr++
fin
return wordptr, len
end
//
// Hash table routines
//
def hashname(chars, len)#1
return (len ^ ((^chars << 1) ^ ^(chars + len / 2) << 2)) & HASH_MASK
end
def addhash(dentry)#0
byte hash
hash = hashname(dentry + 1, ^dentry)
*_hfa_(dentry) = hashtbl[hash])
hashtbl[hash] = dentry
end
def buildhashtbl#0
word dentry
byte i, hash
for i = 0 to HASH_MASK
hashtbl[i] = 0
next
dentry = vlist
while dentry
hash = hashname(dentry + 1, ^dentry)
*_hfa_(dentry) = hashtbl[hash])
hashtbl[hash] = dentry
dentry = *(dentry + ^dentry + 2)
loop
end
//
// Warm start
//
def warmstart#0
(@_reset_estack)()#0
brk = 0
brkcfa = 0
RSP = RSTK_SIZE
if state & comp_flag // Undo compilation state
heaprelease(vlist)
vlist = *_lfa_(vlist)
fin
state = 0
while !endsrc; loop
infunc = @keyin
inptr = keyinbuf
^inptr = 0
end
//
// Cold start
//
def coldstart#0
warmstart
vlist = @d_vlist
heaprelease(startheap)
buildhashtbl
end
//
// Find match in dictionary
//
def find(matchchars, matchlen)#1
word dentry
byte i
dentry = hashtbl[hashname(matchchars, matchlen)]
matchchars--
while dentry
if ^dentry == matchlen
for i = matchlen downto 1
if ^(matchchars + i) <> ^(dentry + i)
break
fin
next
if i == 0
return dentry
fin
fin
dentry = *(dentry + ^dentry + 4)
loop
return 0 // Not found
end
//
// Convert input into number
//
def _isnum_(numchars, numlen)#2
word num, sign
byte numchar
sign = 1
if ^numchars == '-'
sign = -1
numchars++
numlen--
if numlen == 0
return 0, 0
fin
fin
num = 0
if ^numchars == '$'
numchars++
numlen--
if numlen == 0
return 0, 0
fin
while numlen
numchar = toupper(^numchars)
if numchar >= '0' and numchar <= '9'
num = num * 16 + numchar - '0'
elsif numchar >= 'A' and numchar <= 'F'
num = num * 16 + numchar - 'A' + 10
else
break
fin
numchars++
numlen--
loop
else
while numlen
numchar = ^numchars
if numchar < '0' or numchar > '9'
break
fin
num = num * 10 + numchar - '0'
numchars++
numlen--
loop
fin
return num * sign, numlen == 0
end
//
// Break handler
//
def showtrace(dentry)#0
puts("\n( "); _showstack_; puts(") "); puts(dentry); putc(' ')
end
def brkhandle(dentry)#0
word brk_infn, brk_inptr, brk_iip
byte brk_state
showtrace(dentry)
brk_iip = IIP
brk_infn = infunc
brk_inptr = inptr
infunc = @keyin
inptr = keyinbuf
^inptr = 0
brk_state = state & comp_flag
state = state & ~comp_flag
brk++
_interpret_
brk--
state = brk_state | state
IIP = brk_iip
infunc = brk_infn
inptr = brk_inptr
end
//
// Execute code in CFA
//
def _execword_(dentry)#0
when conio:keypressed()
is $83 // CTRL-C
conio:getkey() // Clear KB
brkhandle(dentry)
break
is $94 // CTRL-T
conio:getkey() // Clear KB
state = state ^ trace_flag
break
wend
if state & trace_flag
showtrace(dentry)
if state & step_flag
if conio:getkey() == $03 // CTRL-C
brkhandle(dentry)
fin
fin
fin
W = _cfa_(dentry)
(*W)()#0
if (@_get_estack)()#1 > 16
puts("Stack over/underflow\n")
_quit_
fin
end
def execwords(wlist)#0
word prevIP, dentry
prevIP = IIP
IIP = wlist
dentry = *IIP
while dentry
IIP = IIP + 2
_execword_(dentry)
dentry = *IIP
loop
IIP = prevIP
end
//
// Compile a word/literal into the dictionary: ITC and PBC
//
def _compword_(dentry)#0
if ^_ffa_(dentry) & interponly_flag
puts("INTERP only word\n")
_quit_
elsif state & comp_itc_flag
_dictaddw_(dentry)
elsif state & comp_pbc_flag
if ^_ffa_(dentry) & itc_flag // Check if calling ITC word
_dictaddb_($2C) // CONSTANT WORD
_dictaddw_(dentry) // Pointer to dictionary entry
_dictaddb_($54) // CALL _execword_
_dictaddw_(@_execword_)
elsif ^_ffa_(dentry) & inline_flag // inline bytecode
_dictaddb_(^_pfa_(dentry))
elsif ^_ffa_(dentry) & inlinew_flag // inline 2 bytecodes
_dictaddw_(*_pfa_(dentry))
else
_dictaddb_($54) // CALL CFA directly
_dictaddw_(*_cfa_(dentry))
fin
fin
if state & trace_flag
putc('['); puts(dentry); puts("] ")
fin
end
def _compliteral_(value)#0
if state & comp_itc_flag
_dictaddw_(@d_lit)
_dictaddw_(value) // Poke literal value into dictionary
else // comp_pbc_flag
if value >= 0 and value <= 255
if value <= 15
_dictaddb_(value << 1) // CONSTANT NIBBLE
else
_dictaddb_($2A) // CONSTANT BYTE
_dictaddb_(value) // Poke literal value into dictionary
fin
elsif value < 0 and value >= -256
if value == -1
_dictaddb_($20) // CONSTANT MINUS_ONE
else
_dictaddb_($5E) // CONSTANT NEGATIVE BYTE
_dictaddb_(value) // Poke literal value into dictionary
fin
else
_dictaddb_($2C) // CONSTANT WORD
_dictaddw_(value) // Poke literal value into dictionary
fin
fin
end
def _interpret_#0
word inchars, dentry, value
byte inlen, valid
//
// Set flags on words
//
repeat
inchars, inlen = nextword(' ')
dentry = find(inchars, inlen)
if dentry
if ^_ffa_(dentry) & imm_flag or not (state & comp_flag)
if ^_ffa_(dentry) & componly_flag and not (state & comp_flag)
puts(dentry)
puts(" : Compile only word\n")
_quit_
fin
_execword_(dentry)
else
_compword_(dentry)
fin
else
value, valid = _isnum_(inchars, inlen)
if not valid
inchars--
^inchars = inlen
puts(inchars)
puts(" ? No match\n")
warmstart
else
if state & comp_flag
_compliteral_(value)
else
(@push)(value)#0
fin
fin
fin
until state & exit_flag
state = state & ~exit_flag
end
//
// Intrinsics
//
def _swap_(a,b)#2
return b,a
end
def _dashdup_(a)#1
if a; (@push)(a)#0; fin
return a
end
def _over_(a,b)#3
return a,b,a
end
def _rot_(a,b,c)#3
return b,c,a
end
def _wplusset_(a,b)#0
*b = *b + a
end
def _abs_(a)#1
return a < 0 ?? -a :: a
end
def _min_(a,b)#1
return a > b ?? b :: a
end
def _max_(a,b)
return a > b ?? a :: b
end
def _ffa_(dentry)#1
return dentry + ^dentry + 1
end
def _lfa_(dentry)#1
return dentry + ^dentry + 2
end
def _hfa_(dentry)#1
return dentry + ^dentry + 4
end
def _cfa_(dentry)#1
return dentry + ^dentry + 6
end
def _pfa_(dentry)#1
return dentry + ^dentry + 8
end
def _tors_(a)#0
if RSP == 0
puts("Return stack overflow\n")
_quit_
fin
RSP--
RSTACK[RSP] = a
end
def _fromrs_#1
if RSP == RSTK_SIZE
puts("Return stack underflow\n")
_quit_
fin
RSP++
return RSTACK[RSP - 1]
end
def _toprs_#1
return RSTACK[RSP]
end
def _lit_#1
word lit
lit = *IIP
IIP = IIP + 2
return lit
end
def _slit_#1
word slit
slit = IIP
IIP = IIP + ^IIP + 1
return slit
end
def _allot_(a)#0
heapalloc(a)
end
def _cmove_(a,b,c)#0
memcpy(b, a, c)
end
def _move_(a,b,c)#0
memcpy(b, a, c * 2)
end
def _fill_(a,b,c)#0
memset(a, c | (c << 8), b)
end
def _pad_#1
return heapmark + 128
end
def _trailing_(a,b)#2
while b and ^(a + b - 1) == ' '
b--
loop
return a, b
end
def newdict#0
word bldptr, plist, namechars, namelen
namechars, namelen = nextword(' ')
plist = vlist
vlist = heapmark
^vlist = namelen
bldptr = vlist + 1
while namelen
^bldptr = ^namechars
bldptr++
namechars++
namelen--
loop
^bldptr = 0 // Flags
bldptr++
*bldptr = plist; // Link ptr
bldptr = bldptr + 2
*bldptr = 0; // Hash ptr
bldptr = bldptr + 2
*bldptr = bldptr + 2 // Point CFA to PFA
heapalloc(bldptr - vlist + 2)
end
def _plasma_(a)#0
newdict
^(_ffa_(vlist)) = showcr_flag
*(_cfa_(vlist)) = a // PLASMA code address
addhash(vlist)
end
def _var_(a)#0
newdict
_dictaddb_(JSR); _dictaddw_(vmvect)
_dictaddb_($2C) // CONSTANT WORD
_dictaddw_(heapmark + 3) // Poiner to variable in PFA
_dictaddb_($5C) // RET
_dictaddw_(a) // Variable storage
addhash(vlist)
end
def _const_(a)#0
newdict
_dictaddb_(JSR); _dictaddw_(vmvect)
_dictaddb_($2C) // CONSTANT WORD
_dictaddw_(a)
_dictaddb_($5C) // RET
addhash(vlist)
end
def _create_#0
newdict
_dictaddb_(JSR); _dictaddw_(vmvect)
_dictaddb_($2C) // CONSTANT WORD
_dictaddw_(heapmark + 5) // Pointer to rest of PFA
_dictaddb_($5C) // RET
_dictaddw_(0) // reserved word for DOES>
//
// 9 bytes after PFA, data follows...
//
end
def _dodoes_#0
(@push)(W + 11)#0 // Pointer to PFA storage
execwords(*(W + 2)) // Exec PFA ptr
end
def _itcdoes_(a)#0
//
// Overwrite CREATE as ITC words
//
^(_ffa_(vlist)) = ^(_ffa_(vlist)) | itc_flag
*(_cfa_(vlist)) = @_dodoes_
*(_pfa_(vlist)) = a // Fill in DOES code address
addhash(vlist)
end
def _pbcdoes_(a)#0
//
// Rewrite the end of CREATE
//
^(_pfa_(vlist) + 6) = $C4 // JUMP DOES> directly
*(_pfa_(vlist) + 7) = a
addhash(vlist)
end
def _does_#0
if state & comp_itc_flag
_dictaddw_(@d_lit)
_dictaddw_(heapmark + 8) // Pointer to DOES code
_dictaddw_(@d_createdoes)
_dictaddw_(0) // Double zero for SHOW
_dictaddw_(0)
// End of <BUILDS, beginning of DOES>
else // comp_pbc_flag
_dictaddb_($2C) // CONSTANT WORD
_dictaddw_(heapmark + 6) // Pointer to DOES code
_dictaddb_($54) // CALL
_dictaddw_(@_pbcdoes_) // Fills in code address reserved in _compbuilds_
_dictaddb_($5C) // RET
// End of BUILDS, beginning of DOES> code
fin
end
def _docolon_#0
execwords(W + 2) // Exec PFA
end
def _colon_#0
newdict
state = state | comp_mode
if state & comp_itc_flag
^(_ffa_(vlist)) = itc_flag | showcr_flag
*(_cfa_(vlist)) = @_docolon_
else // comp_pbc_flag
^(_ffa_(vlist)) = showcr_flag
_dictaddb_(JSR); _dictaddw_(vmvect)
fin
if state & trace_flag
puts(vlist); putc(' ')
fin
end
def _exit_#0
if state & comp_itc_flag
_dictaddw_(0)
elsif state & comp_pbc_flag
_dictaddb_($5C) // RET
else
puts("; Not compiling\n")
_quit_
fin
end
def _semi_#0
_exit_
if state & comp_itc_flag // Add double zero at end of definition for SHOW
_dictaddw_(0)
fin
addhash(vlist)
state = state & ~comp_flag
end
def _compile_#0
word dentry
dentry = find(nextword(' '))
if dentry
_compword_(dentry)
else
puts("No match\n")
_quit_
fin
end
def _compoff_#0
savestate = state & comp_flag
state = state & ~comp_flag
end
def _compon_#0
state = state | savestate
savestate = 0
if not (state & comp_flag)
puts("] Not compiling\n")
_quit_
fin
end
def _componly_#0
^_ffa_(vlist) = ^_ffa_(vlist) | componly_flag
end
def _interponly_#0
^_ffa_(vlist) = ^_ffa_(vlist) | interponly_flag
end
def _immediate_#0
^_ffa_(vlist) = ^_ffa_(vlist) | imm_flag
end
def _branch_#0
IIP = *IIP
end
def _0branch_(a)#0
if a
IIP = IIP + 2
else
IIP = *IIP
fin
end
def _if_#0
_compword_(@d_0branch)
_tors_(heapalloc(2)) // Save backfill address
end
def _else_#0
word backref
backref = _fromrs_
_compword_(@d_branch)
_tors_(heapalloc(2))
*backref = heapmark
end
def _then_#0
*_fromrs_ = heapmark
end
def _case_#0
_compword_(@d_dup)
_tors_(0) // Linked address list
end
def _of_#0
if state & comp_itc_flag
_dictaddw_(@d_eq)
_dictaddw_(@d_0branch)
else // comp_pbc_flag
_dictaddb_($24) // BRNE
fin
_tors_(heapalloc(2)) // Save backfill address
end
def _endof_#0
word backref, link
backref = _fromrs_
link = _fromrs_
_compword_(@d_branch)
_tors_(heapmark)
_dictaddw_(link)
if state & comp_itc_flag
*backref = heapmark
else // comp_pbc_flag
*backref = heapmark - backref // Relative branch
fin
_compword_(@d_dup)
end
def _endcase_#0
word backref, link
_compword_(@d_drop)
backref = _fromrs_
while backref
link = *backref
*backref = heapmark
backref = link
loop
_compword_(@d_drop)
end
def _dodo_(a,b)#0
if RSP < 2
puts("Return stack overflow\n")
_quit_
fin
RSP = RSP - 2
RSTACK[RSP + 1] = a
RSTACK[RSP] = b
end
def _do_#0
_compword_(@d_dodo)
_tors_(heapmark)
end
def _leave_#0
RSTACK[RSP] = RSTACK[RSP + 1] - 1
end
def _doloop_#0
RSTACK[RSP]++
if RSTACK[RSP] == RSTACK[RSP + 1]
RSP = RSP + 2
IIP = IIP + 2
else
IIP = *IIP
fin
end
def _dopbcloop_#1
RSTACK[RSP]++
if RSTACK[RSP] == RSTACK[RSP + 1]
RSP = RSP + 2
return TRUE
fin
return FALSE
end
def _doplusloop_(a)#0
RSTACK[RSP] = RSTACK[RSP] + a
if (a >= 0 and RSTACK[RSP] >= RSTACK[RSP + 1]) or (a < 0 and RSTACK[RSP] <= RSTACK[RSP + 1])
RSP = RSP + 2
IIP = IIP + 2
else
IIP = *IIP
fin
end
def _dopbcplusloop_(a)#1
RSTACK[RSP] = RSTACK[RSP] + a
if (a >= 0 and RSTACK[RSP] >= RSTACK[RSP + 1]) or (a < 0 and RSTACK[RSP] <= RSTACK[RSP + 1])
RSP = RSP + 2
return TRUE
fin
return FALSE
end
def _loop_#0
if state & comp_itc_flag
_dictaddw_(@d_doloop)
else // comp_pbc_flag
_dictaddb_($54) // CALL
_dictaddw_(@_dopbcloop_)
_dictaddb_($C2) // JUMPZ
fin
_dictaddw_(_fromrs_)
end
def _plusloop_#0
if state & comp_itc_flag
_dictaddw_(@d_doplusloop)
else // comp_pbc_flag
_dictaddb_($54) // CALL
_dictaddw_(@_dopbcplusloop_)
_dictaddb_($C2) // JUMPZ
fin
_dictaddw_(_fromrs_)
end
def _j_#1
return RSTACK[RSP + 2]
end
def _begin_#0
_tors_(heapmark)
end
def _again_#0
_compword_(@d_branch)
_dictaddw_(_fromrs_)
end
def _until_#0
_compword_(@d_0branch)
_dictaddw_(_fromrs_)
end
def _while_#0
_compword_(@d_0branch)
_tors_(heapalloc(2)) // Save backfill address
end
def _repeat_#0
word backref
backref = _fromrs_ // Backref from WHILE
_compword_(@d_branch)
_dictaddw_(_fromrs_)
*backref = heapmark // Backref to BEGIN
end
def _count_(a)#2
return a + 1, ^a
end
def _find_(a)#2
word dentry
dentry = find(_count_(a))
if dentry
return dentry, ^_ffa_(dentry) & imm_flag ?? 1 :: -1
fin
return a, 0
end
def _tick_#0
word dentry
dentry = find(nextword(' '))
if state & comp_flag
_compliteral_(dentry)
else
(@push)(dentry)#0
fin
end
def _forget_#0
word dentry
dentry = find(nextword(' '))
if dentry
if isult(dentry, startheap)
vlist = @d_vlist
dentry = startheap
else
vlist = *_lfa_(dentry)
fin
heaprelease(dentry)
buildhashtbl
else
puts("No match\n")
_quit_
fin
end
def _accept_(a,b)#1
word saveinptr
byte len
saveinptr = inptr
memcpy(heapmark + 256, keyinbuf, 80)
inptr = gets('?'|$80)
len = ^inptr
if len > b
len = b
fin
^(inptr + len + 1) = 0
memcpy(a, inptr + 1, len)
memcpy(keyinbuf, heapmark + 256, 80)
inptr = saveinptr
return len
end
def _terminal_#1
return conio:keypressed() > 127
end
def _key_#1
return conio:getkey()
end
def _word_(a)#1
word wordptr
byte len
wordptr, len = nextword(a)
wordptr--
^wordptr = len
return wordptr
end
def _space_#0
putc(' ')
end
def _spaces_(a)#0
while a
putc(' ')
a--
loop
end
def _prval_(a)#0
puti(a); putc(' ')
end
def _prbyte_(a)#0
putc('$'); putb(a); putc(' ')
end
def _prhex_(a)#0
putc('$'); puth(a); putc(' ')
end
def _prat_(a)#0
puti(*a); putc(' ')
end
def _blank_#0
if state & comp_flag
_compliteral_(32)
else
(@push)(32)#0
fin
end
def _char_#0
word str
byte len
str, len = nextword(' ')
if state & comp_flag
_compliteral_(^str)
else
(@push)(^str)#0
fin
end
def _str_#0
word str
byte len
str, len = nextword('"')
str--
^str = len
len++
if state & comp_flag
_compword_(@d_slit)
memcpy(heapalloc(len), str, len) // Add to dictionary
else
(@push)(heapmark)#0
memcpy(heapmark, str, len) // Copy to HERE
fin
end
def _type_(a,b)#0
while b and ^a
putc(^a)
a++
b--
loop
end
def _prstr_#0
word str
byte len
if state & comp_flag
_str_
_compword_(@d_doprstr)
else
str, len = nextword('"')
str--
^str = len
puts(str)
fin
end
def _prpstr_#0
word str
byte len
if state & comp_flag
_str_
_compword_(@d_doprstr)
else
str, len = nextword(')')
str--
^str = len
puts(str)
fin
end
def stodci(str, dci)
byte len, c
len = ^str
if len == 0
^dci = 0
return dci
fin
c = toupper(^(str + len)) & $7F
len--
^(dci + len) = c
while len
c = toupper(^(str + len)) | $80
len--
^(dci + len) = c
loop
return dci
end
def _lookup_#1
word symname
char symlen, dci[31]
symname, symlen = nextword(' ')
symname--
^symname = symlen
return cmdsys:lookupsym(stodci(symname, @dci))
end
def _src_(a)#0
char[64] syssrc
if srclevel >= SRCREFS
puts("Too many nested SRC")
_quit_
fin
inref[srclevel] = fileio:open(a)
if !inref[srclevel] and ^a < 16
strcpy(@syssrc, cmdsys:syspath)
strcat(@syssrc, "scripts/")
strcat(@syssrc, a)
inref[srclevel] = fileio:open(@syssrc)
fin
if inref[srclevel]
fileio:newline(inref[srclevel], $7F, $0D)
infunc = @filein
inbufptr = @inbuf + srclevel * INBUF_SIZE
previnptr[srclevel] = inptr
inptr = inbufptr
^inptr = 0
srclevel++
else
puts("Failed to open "); puts(a); putln
fin
end
def _srcstr_#0
word filename
byte len
if state & comp_flag
_str_
_compword_(@d_src)
else
filename, len = nextword('"')
filename--
^filename = len
_src_(filename)
fin
end
def _endsrc_(a)#0
if a
endsrc
fin
end
def _show_#0
word dentry, pfa, w
dentry = find(nextword(' '))
if dentry and ^_ffa_(dentry) & itc_flag // Only show ITC words
if *_cfa_(dentry) == @_docolon_
pfa = _pfa_(dentry)
else // @d_dodoes
pfa = *_pfa_(dentry)
fin
w = *pfa
while w
puts(" ")
if ^_ffa_(w) & param_flag
pfa = pfa + 2
fin
if w == @d_slit
putc('"')
puts(pfa)
putc('"')
pfa = pfa + ^pfa - 1
elsif w == @d_lit
puti(*pfa)
else
puts(w)
fin
if ^_ffa_(w) & showcr_flag; putln; fin
pfa = pfa + 2
w = *pfa
if !w
puts(" EXIT\n")
pfa = pfa + 2
w = *pfa
fin
if conio:keypressed()
conio:getkey(); conio:getkey()
fin
loop
fin
end
def _showstack_#0
word val
byte depth
for depth = 1 to (@_get_estack)()#1
val = ^(_estkl + 16 - depth) | (^(_estkh + 16 - depth) << 8)
puti(val); putc(' ')
next
end
def _showrstack_#0
byte depth
depth = RSTK_SIZE - 1
while depth >= RSP
puti(RSTACK[depth]); putc(' ')
depth--
loop
end
def _tron_#0
state = state | trace_flag
end
def _troff_#0
state = state & ~(trace_flag | step_flag)
end
def _stepon_#0
state = state | step_flag | trace_flag
end
def _stepoff_#0
state = state & ~step_flag
end
def brkpoint#0
brkhandle(brkentry)
W = _cfa_(brkentry)
if brkcfa
brkcfa()#0
else // Breakpoint was cleared
(*_cfa_(brkentry))()#0
fin
end
def _brk_#0
brkhandle(@d_brk)
end
def _brkon_#0
word dentry
if brkcfa
puts("Breakpoint already enabled\n")
else
dentry = find(nextword(' '))
if dentry
brkentry = dentry
brkcfa = *_cfa_(dentry)
*_cfa_(dentry) = @brkpoint
else
puts("No match\n")
fin
fin
end
def _brkoff_#0
*_cfa_(brkentry) = brkcfa
brkcfa = 0
end
def _cont_#0
if brk
state = state | exit_flag
else
putc('?')
fin
end
def _itc_#0
comp_mode = comp_itc_flag
end
def _pbc_#0
comp_mode = comp_pbc_flag
end
def _comment_#0
nextword(')')
end
def typelist(typestr, typemask, type)#0
word d
byte tab
puts(typestr)
tab = ^typestr
d = vlist
while d
if (typemask & ^_ffa_(d)) == type
tab = tab + 1 + ^d
if tab > 39
putln;
tab = ^d
else
puts(" ")
fin
puts(d)
if conio:keypressed(); conio:getkey(); conio:getkey(); fin
fin
d = *_lfa_(d)
loop
end
def _vlist_#0
putln
typelist("Compile only: ", componly_flag, componly_flag)
putln; putln
typelist("Interpret only: ", interponly_flag, interponly_flag)
putln; putln
typelist("Both: ", componly_flag | interponly_flag, 0)
end
//
// Quit
//
def _quit_#0
warmstart
throw(@exitforth, FALSE)
end
//
// Abort
//
def _abort_(a)#0
if a
puts("Abort\n")
_quit_
fin
end
def _doabortstr_(a,b)#0
if a
puts("Abort: "); puts(b); putln
_quit_
fin
end
def _abortstr_#0
word str
byte len
_str_
if state & comp_flag
_compword_(@d_doabortstr)
else
(@_doabortstr_)()#0
fin
end
//
// Restart FORTH
//
def _restart_#0
coldstart
throw(@exitforth, FALSE)
end
//
// Leave FORTH
//
def _bye_#0
throw(@exitforth, TRUE)
end
//
// Start FORTH
//
puts("FORTH for PLASMA 2.1\n")
if cmdsys:sysver < $0201
puts("PLASMA >= 2.01 required\n")
return
fin
//
// Compile ITC version of inline words ( speeds it up a smidge )
//
vmvect = *(@divmod + 1) // Hack - get VM entry vector from divmod
vlist = @d_vlist
while vlist
if *_cfa_(vlist) == 0
*_cfa_(vlist) = heapmark
_dictaddb_(JSR); _dictaddw_(vmvect)
if ^_ffa_(vlist) & inline_flag
_dictaddb_(^_pfa_(vlist))
elsif ^_ffa_(vlist) & inlinew_flag
_dictaddw_(*_pfa_(vlist))
else
puts(vlist); puts(": Invalid dictionary\n")
return -1
fin
_dictaddb_($5C) // RET
fin
vlist = *_lfa_(vlist)
loop
_estkl = ^(@syscall + 1) // Hack to fill in parameter stack locations
_estkh = ^(@syscall + 3)
fileio:iobufalloc(4) // Allocate a bunch of file buffers
startheap = heapmark
coldstart
//
// Check for command line argument
//
inptr = argNext(argFirst)
//
// Main start and restart entry
//
if not except(@exitforth)
if ^inptr; inptr++; _srcstr_; fin
_interpret_
fin
done