mirror of
https://github.com/dschmenk/PLASMA.git
synced 2026-03-14 16:16:40 +00:00
1953 lines
45 KiB
Plaintext
1953 lines
45 KiB
Plaintext
include "inc/cmdsys.plh"
|
|
include "inc/args.plh"
|
|
include "inc/fileio.plh"
|
|
include "inc/conio.plh"
|
|
include "inc/longjmp.plh"
|
|
sysflags restxt1|resxtxt1 // Reserve 80 column text pages
|
|
//
|
|
// Internal variables
|
|
//
|
|
const JSR = $20 // 6502 JSR opcode needed for VM entry
|
|
const RTS = $60 // 6502 RTS opcode
|
|
const JMP = $4C // 6502 JMP opcode
|
|
const SRCREFS = 2
|
|
const INBUF_SIZE = 128
|
|
word latest, infunc, inptr, IIP, W
|
|
word vmvect, startheap, arg
|
|
byte srclevel = 0
|
|
//
|
|
// Internal buffers
|
|
//
|
|
word strbuf, inbuf
|
|
res[t_except] exitforth
|
|
//
|
|
// Input references, pointers, and saved values
|
|
//
|
|
byte nullstr = 0
|
|
word keyinbuf = @nullstr // Point somewhere benign for starters (updated in keyin)
|
|
word inbufptr = @nullstr
|
|
byte inref[SRCREFS]
|
|
word previnptr[SRCREFS]
|
|
//
|
|
// 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_pbc_flag
|
|
byte state = 0
|
|
word brkentry = 0
|
|
word brkcfa = 0
|
|
byte brk = 0
|
|
//
|
|
// 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, _ifdup_(a)#1, _over_(a,b)#3, _rot_(a,b,c)#3, _dup2_(a,b)#4
|
|
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
|
|
predef _unloop_#0, _leave_#0, _j_#1, _defer_#0, _is_(a)#0, _noname_#0
|
|
predef _create_#0, _itcdoes_(a)#0, _does_#0, _compoff_#0, _compon_#0, _state_#1
|
|
predef _postpone_#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, _latest_#1, _recurse_#0
|
|
predef _cmove_(a,b,c)#0, _move_(a,b,c)#0, _fill_(a,b,c)#0, _plasma_(a)#0
|
|
predef _compare_(a,b,c,d)#1, _var_(a)#0, _const_(a)#0, _lit_#1, _slit_#1, _find_(a)#2
|
|
predef _tick_#0, _forget_#0, _keypressed_#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, _prbin_(a)#0, _prbinw_(a)#0
|
|
predef _accept_(a,b)#1, _type_(a,b)#0
|
|
predef _words_#0, _tron_#0, _troff_#0, _stepon_#0, _stepoff_#0
|
|
predef _itc_#0, _pbc_#0, _comment_#0, _src_(a)#0, _srcstr_#0, _endsrc_#0, _ifendsrc_(a)#0
|
|
predef _brk_#0, _brkon_#0, _brkoff_#0, _word_(a)#1, _count_(a)#2
|
|
predef _space_#0, _spaces_(a)#0, _see_#0, _prstack_#0, _prrstack_#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
|
|
predef _interpret_#0
|
|
//
|
|
// Forth Vocabulary
|
|
//
|
|
// DROP
|
|
char d_drop = "DROP", inline_flag | showcr_flag; word = 0, 0, 0, $30
|
|
// DROP2
|
|
char d_drop2 = "DROP2", inlinew_flag | showcr_flag; word = @d_drop, 0, 0, $3030
|
|
// SWAP
|
|
char d_swap = "SWAP", 0; word = @d_drop2, 0, @_swap_
|
|
// DUP
|
|
char d_dup = "DUP", inline_flag; word = @d_swap, 0, 0, $34
|
|
// DUP2
|
|
char d_dup2 = "DUP2", 0; word = @d_dup, 0, @_dup2_
|
|
// ?DUP
|
|
char d_ifdup = "?DUP", 0; word = @d_dup2, 0, @_ifdup_
|
|
// OVER
|
|
char d_over = "OVER", 0; word = @d_ifdup, 0, @_over_
|
|
// ROT
|
|
char d_rot = "ROT", 0; word = @d_over, 0, @_rot_
|
|
// ADD
|
|
char d_add = "+", inline_flag; word = @d_rot, 0, 0, $82
|
|
// ONE PLUS
|
|
char d_inc = "1+", inline_flag; word = @d_add, 0, 0, $8C
|
|
// TWO PLUS
|
|
char d_inc2 = "2+", inlinew_flag; word = @d_inc, 0, 0, $8C8C
|
|
// ONE MINUS
|
|
char d_dec = "1-", inline_flag; word = @d_inc2, 0, 0, $8E
|
|
// TWO MINUS
|
|
char d_dec2 = "2-", inlinew_flag; word = @d_dec, 0, 0, $8E8E
|
|
// SUB
|
|
char d_sub = "-", inline_flag; word = @d_dec2, 0, 0, $84
|
|
// MUL
|
|
char d_mul = "*", inline_flag; word = @d_sub, 0, 0, $86
|
|
// DIV
|
|
char d_div = "/", inline_flag; word = @d_mul, 0, 0, $88
|
|
// DIVMOD
|
|
char d_divmod = "/MOD", inline_flag; word = @d_div, 0, 0, $36
|
|
// MOD
|
|
char d_mod = "MOD", inline_flag; word = @d_divmod, 0, 0, $8A
|
|
// NEG
|
|
char d_neg = "NEGATE", inline_flag; word = @d_mod, 0, 0, $90
|
|
// AND
|
|
char d_and = "AND", inline_flag; word = @d_neg, 0, 0, $94
|
|
// OR
|
|
char d_or = "OR", inline_flag; word = @d_and, 0, 0, $96
|
|
// XOR
|
|
char d_xor = "XOR", inline_flag; word = @d_or, 0, 0, $98
|
|
// COMPLEMENT
|
|
char d_complement = "COMPLEMENT", inline_flag; word = @d_xor, 0, 0, $92
|
|
// NOT
|
|
char d_not = "NOT", inline_flag; word = @d_complement, 0, 0, $80
|
|
// LEFT SHIFT
|
|
char d_lshift = "LSHIFT", inline_flag; word = @d_not, 0, 0, $9A
|
|
// RIGHT SHIFT
|
|
char d_rshift = "RSHIFT", inline_flag; word = @d_lshift, 0, 0, $9C
|
|
// EQUALS
|
|
char d_eq = "=", inline_flag; word = @d_rshift, 0, 0, $40
|
|
// NOT EQUALS
|
|
char d_ne = "<>", inline_flag; word = @d_eq, 0, 0, $42
|
|
// GREATER THAN
|
|
char d_gt = ">", inline_flag; word = @d_ne, 0, 0, $44
|
|
// LESS THAN
|
|
char d_lt = "<", inline_flag; word = @d_gt, 0, 0, $46
|
|
// UNSIGNED GREATER THAN
|
|
char d_ugt = "U>", 0; word = @d_lt, 0, @isugt
|
|
// UNSIGNED LESS THAN
|
|
char d_ult = "U<", 0; word = @d_ugt, 0, @isult
|
|
// LESS THAN ZERO
|
|
char d_0lt = "0<", inlinew_flag; word = @d_ult, 0, 0, $4600 // ZERO ISLT
|
|
// GREATER THAN ZERO
|
|
char d_0gt = "0>", inlinew_flag; word = @d_0lt, 0, 0, $4400 // ZERO ISGT
|
|
// EQUALS ZERO
|
|
char d_0eq = "0=", inlinew_flag; word = @d_0gt, 0, 0, $4000 // ZERO ISEQ
|
|
// NOT EQUAL ZERO
|
|
char d_0ne = "0<>", inlinew_flag; word = @d_0eq, 0, 0, $4200 // ZERO ISNE
|
|
// ABS
|
|
char d_abs = "ABS", 0; word = @d_0ne, 0, @_abs_
|
|
// MIN
|
|
char d_min = "MIN", 0; word = @d_abs, 0, @_min_
|
|
// MAX
|
|
char d_max = "MAX", 0; word = @d_min, 0, @_max_
|
|
// CHAR PUT
|
|
char d_cset = "C!", inline_flag | showcr_flag; word = @d_max, 0, 0, $70
|
|
// WORD PUT
|
|
char d_wset = "!", inline_flag | showcr_flag; word = @d_cset, 0, 0, $72
|
|
// WORD PLUS PUT
|
|
char d_wplusset = "+!", showcr_flag; word = @d_wset, 0, @_wplusset_
|
|
// CHAR GET
|
|
char d_cget = "C@", inline_flag; word = @d_wplusset, 0, 0, $60
|
|
// WORD GET
|
|
char d_wget = "@", inline_flag; word = @d_cget, 0, 0, $62
|
|
// EXECUTE
|
|
char d_execute = "EXECUTE", showcr_flag; word = @d_wget, 0, @_execword_
|
|
// TO RSTACK
|
|
char d_torstk = ">R", showcr_flag; word = @d_execute, 0, @_tors_
|
|
// FROM RSTACK
|
|
char d_fromrstk = "R>", 0; word = @d_torstk, 0, @_fromrs_
|
|
// TOP OF RSTACK
|
|
char d_toprstk = "R@", 0; word = @d_fromrstk, 0, @_toprs_
|
|
// PLASMA SYMBOL LOOKUP
|
|
char d_lookup = "LOOKUP", 0; word = @d_toprstk, 0, @_lookup_
|
|
// PLASMA LINKEAGE
|
|
char d_plasma = "PLASMA", interponly_flag; word = @d_lookup, 0, @_plasma_
|
|
// VARIABLE
|
|
char d_var = "VARIABLE", interponly_flag; word = @d_plasma, 0, @_var_
|
|
// CONSTANT
|
|
char d_const = "CONSTANT", interponly_flag; word = @d_var, 0, @_const_
|
|
// CMOVE
|
|
char d_cmove = "CMOVE", showcr_flag; word = @d_const, 0, @_cmove_
|
|
// MOVE
|
|
char d_move = "MOVE", showcr_flag; word = @d_cmove, 0, @_move_
|
|
// FILL
|
|
char d_fill = "FILL", showcr_flag; word = @d_cmove, 0, @_fill_
|
|
// LATEST
|
|
char d_latest = "LATEST", 0; word = @d_fill, 0, @_latest_
|
|
// HERE
|
|
char d_here = "HERE", 0; word = @d_latest, 0, @heapmark
|
|
// PAD
|
|
char d_pad = "PAD", 0; word = @d_here, 0, @_pad_
|
|
// ALLOT
|
|
char d_allot = "ALLOT", showcr_flag; word = @d_pad, 0, @_allot_
|
|
// BRANCH ( not in vocabulary )
|
|
char d_branch = "(BRANCH)", param_flag | inline_flag | showcr_flag; word = 0, 0, @_branch_, $C4
|
|
// BRANCH IF 0 ( not in vocabulary )
|
|
char d_0branch = "(0BRANCH)", param_flag | inline_flag | showcr_flag; word = 0, 0, @_0branch_, $C2
|
|
// RECURSE
|
|
char d_recurse = "RECURSE", imm_flag | componly_flag; word = @d_allot, 0, @_recurse_
|
|
// IF
|
|
char d_if = "IF", imm_flag | componly_flag; word = @d_recurse, 0, @_if_
|
|
// ELSE
|
|
char d_else = "ELSE", imm_flag | componly_flag; word = @d_if, 0, @_else_
|
|
// THEN
|
|
char d_then = "THEN", imm_flag | componly_flag; word = @d_else, 0, @_then_
|
|
// CASE
|
|
char d_case = "CASE", imm_flag | componly_flag; word = @d_then, 0, @_case_
|
|
// OF
|
|
char d_of = "OF", imm_flag | componly_flag; word = @d_case, 0, @_of_
|
|
// ENDOF
|
|
char d_endof = "ENDOF", imm_flag | componly_flag; word = @d_of, 0, @_endof_
|
|
// ENDCASE
|
|
char d_endcase = "ENDCASE", imm_flag | componly_flag; word = @d_endof, 0, @_endcase_
|
|
// COMPILED DO ( not in vocabulary )
|
|
char d_dodo = "(DO)", showcr_flag; word = 0, 0, @_dodo_
|
|
// DO
|
|
char d_do = "DO", imm_flag | componly_flag; word = @d_endcase, 0, @_do_
|
|
// LEAVE
|
|
char d_leave = "LEAVE", componly_flag | showcr_flag; word = @d_do, 0, @_leave_
|
|
// UNLOOP
|
|
char d_unloop = "UNLOOP", componly_flag; word = @d_leave, 0, @_unloop_
|
|
// COMPILED LOOP ( not in vocabulary )
|
|
char d_doloop = "(DOLOOP)", param_flag | showcr_flag; word = 0, 0, @_doloop_
|
|
// LOOP
|
|
char d_loop = "LOOP", imm_flag | componly_flag; word = @d_unloop, 0, @_loop_
|
|
// COMPILED LOOP+ ( not in vocabulary )
|
|
char d_doplusloop = "(+DOLOOP)", param_flag | showcr_flag; word = 0, 0, @_doplusloop_
|
|
// LOOP
|
|
char d_plusloop = "+LOOP", imm_flag | componly_flag; word = @d_loop, 0, @_plusloop_
|
|
// I
|
|
char d_i = "I", componly_flag; word = @d_plusloop, 0, @_toprs_
|
|
// J
|
|
char d_j = "J", componly_flag; word = @d_i, 0, @_j_
|
|
// BEGIN
|
|
char d_begin = "BEGIN", imm_flag | componly_flag; word = @d_j, 0, @_begin_
|
|
// AGAIN
|
|
char d_again = "AGAIN", imm_flag | componly_flag; word = @d_begin, 0, @_again_
|
|
// UNTIL
|
|
char d_until = "UNTIL", imm_flag | componly_flag; word = @d_again, 0, @_until_
|
|
// WHILE
|
|
char d_while = "WHILE", imm_flag | componly_flag; word = @d_until, 0, @_while_
|
|
// REPEAT
|
|
char d_repeat = "REPEAT", imm_flag | componly_flag; word = @d_while, 0, @_repeat_
|
|
// FORGET
|
|
char d_forget = "FORGET", interponly_flag; word = @d_repeat, 0, @_forget_
|
|
// CREATE
|
|
char d_create = "CREATE", showcr_flag; word = @d_forget, 0, @_create_
|
|
// RECREATE/DOES COMPILE TIME ( not in vocabulary )
|
|
char d_createdoes = "(CREATEDOES)", showcr_flag; word = 0, 0, @_itcdoes_
|
|
// DOES
|
|
char d_does = "DOES>", imm_flag | componly_flag; word = @d_create, 0, @_does_
|
|
// COMMA
|
|
char d_comma = ",", showcr_flag; word = @d_does, 0, @_dictaddw_
|
|
// CHAR COMMA
|
|
char d_commab = "C,", showcr_flag; word = @d_comma, 0, @_dictaddb_
|
|
// STATE
|
|
char d_state = "STATE", 0; word = @d_commab, 0, @_state_
|
|
// COLON
|
|
char d_colon = ":", interponly_flag; word = @d_state, 0, @_colon_
|
|
// NONAME
|
|
char d_noname = ":NONAME", interponly_flag; word = @d_colon, 0, @_noname_
|
|
// DEFER
|
|
char d_defer = "DEFER", interponly_flag; word = @d_noname, 0, @_defer_
|
|
// IS
|
|
char d_is = "IS", interponly_flag; word = @d_defer, 0, @_is_
|
|
// COMP OFF
|
|
char d_compoff = "[", imm_flag | componly_flag; word = @d_is, 0, @_compoff_
|
|
// COMP ON
|
|
char d_compon = "]", interponly_flag; word = @d_compoff, 0, @_compon_
|
|
// COMPILE WORD ON STACK
|
|
char d_compword = "COMPILE,", componly_flag; word = @d_compon, 0, @_compword_
|
|
// POSTPONE (COMPILE) NEXT WORD
|
|
char d_postpone = "POSTPONE", imm_flag | componly_flag; word = @d_compword, 0, @_postpone_
|
|
// COMPILE ONLY
|
|
char d_componly = "COMPONLY", imm_flag; word = @d_postpone, 0, @_componly_
|
|
// INTERPRET ONLY
|
|
char d_interponly = "INTERPONLY", imm_flag; word = @d_componly, 0, @_interponly_
|
|
// IMMEDIATE
|
|
char d_immediate = "IMMEDIATE", imm_flag; word = @d_interponly, 0, @_immediate_
|
|
// EXIT
|
|
char d_exit = "EXIT", imm_flag | componly_flag; word = @d_immediate, 0, @_exit_
|
|
// SEMI
|
|
char d_semi = ";", imm_flag | componly_flag; word = @d_exit, 0, @_semi_
|
|
// COUNT
|
|
char d_count = "COUNT", 0; word = @d_semi, 0, @_count_
|
|
// FIND
|
|
char d_find = "FIND", 0; word = @d_count, 0, @_find_
|
|
// TICK
|
|
char d_tick = "'", imm_flag; word = @d_find, 0, @_tick_
|
|
// INLINE LITERAL NUMBER ( not in vocabulary )
|
|
char d_lit = "LIT", param_flag; word = 0, 0, @_lit_
|
|
// COMPILED LITERAL VALUE FROM STACK
|
|
char d_literal = "LITERAL", imm_flag | componly_flag; word = @d_tick, 0, @_compliteral_
|
|
// KEY?
|
|
char d_keypressed = "KEY?", 0; word = @d_literal, 0, @_keypressed_
|
|
// KEY
|
|
char d_key = "KEY", 0; word = @d_keypressed, 0, @_key_
|
|
// ACCEPT
|
|
char d_accept = "ACCEPT", 0; word = @d_key, 0, @_accept_
|
|
// WORD
|
|
char d_word = "WORD", 0; word = @d_accept, 0, @_word_
|
|
// _isnum_
|
|
char d__isnum_ = "NUM?", 0; word = @d_word, 0, @_isnum_
|
|
// -TRAILING
|
|
char d_trailing = "-TRAILING", 0; word = @d__isnum_, 0, @_trailing_
|
|
// COMPARE
|
|
char d_compare = "COMPARE", 0; word = @d_trailing, 0, @_compare_
|
|
// PRINT @TOS
|
|
char d_prat = "?", 0; word = @d_compare, 0, @_prat_
|
|
// PRINT TOS
|
|
char d_prtos = ".", 0; word = @d_prat, 0, @_prval_
|
|
// PRINT TOS HEX
|
|
char d_prtoshex = "$.", 0; word = @d_prtos, 0, @_prhex_
|
|
// PRINT TOS HEX BYTE
|
|
char d_prtosbyte = "C$.", 0; word = @d_prtoshex, 0, @_prbyte_
|
|
// PRINT TOS BINARY
|
|
char d_prtosbinw = "%.", 0; word = @d_prtosbyte, 0, @_prbinw_
|
|
// PRINT TOS BINARY BYTE
|
|
char d_prtosbin = "C%.", 0; word = @d_prtosbinw, 0, @_prbin_
|
|
// EMIT
|
|
char d_emit = "EMIT", 0; word = @d_prtosbin, 0, @putc
|
|
// CR
|
|
char d_cr = "CR", showcr_flag; word = @d_emit, 0, @putln
|
|
// SPACE
|
|
char d_space = "SPACE", 0; word = @d_cr, 0, @_space_
|
|
// SPACES
|
|
char d_spaces = "SPACES", 0; word = @d_space, 0, @_spaces_
|
|
// TYPE
|
|
char d_type = "TYPE", 0; word = @d_spaces, 0, @_type_
|
|
// BLANK
|
|
char d_blank = "BL", imm_flag; word = @d_type, 0, @_blank_
|
|
// CHAR
|
|
char d_char = "CHAR", imm_flag; word = @d_blank, 0, @_char_
|
|
// STRING
|
|
char d_str = "\"", imm_flag; word = @d_char, 0, @_str_
|
|
// LITERAL STRING ( not in vocabulary )
|
|
char d_slit = "SLIT", param_flag | inline_flag; word = 0, 0, @_slit_, $2E
|
|
// PRINT STRING FROM STACK
|
|
char d_doprstr = "(.\")", 0; word = @d_str, 0, @puts
|
|
// PRINT STRING
|
|
char d_prstr = ".\"", imm_flag; word = @d_doprstr, 0, @_prstr_
|
|
// PRINT PAREN STRING
|
|
char d_prpstr = ".(", imm_flag; word = @d_prstr, 0, @_prpstr_
|
|
// READ SOURCE FILE FROM STACK
|
|
char d_src = "SRC", showcr_flag; word = @d_prpstr, 0, @_src_
|
|
// READ SOURCE FILE FROM INPUT
|
|
char d_srcstr = "SRC\"", imm_flag; word = @d_src, 0, @_srcstr_
|
|
// IF END SOURCE FILE
|
|
char d_ifendsrc = "?ENDSRC", showcr_flag; word = @d_srcstr, 0, @_ifendsrc_
|
|
// END SOURCE FILE
|
|
char d_endsrc = "ENDSRC", showcr_flag; word = @d_ifendsrc, 0, @_endsrc_
|
|
// CONTINUE AFTER BRK
|
|
char d_cont = "CONT", interponly_flag; word = @d_endsrc, 0, @_cont_
|
|
// QUIT
|
|
char d_quit = "QUIT", showcr_flag; word = @d_cont, 0, @_quit_
|
|
// ABORT IF <> 0
|
|
char d_abort = "?ABORT", showcr_flag; word = @d_quit, 0, @_abort_
|
|
// DOABORTSTR
|
|
char d_doabortstr = "(?ABORT\")", showcr_flag; word = @d_abort, 0, @_doabortstr_
|
|
// ABORTSTR
|
|
char d_abortstr = "?ABORT\"", imm_flag; word = @d_doabortstr, 0, @_abortstr_
|
|
// COLD exitforth
|
|
char d_exitforth = "COLD", showcr_flag; word = @d_abortstr, 0, @_restart_
|
|
// COMMENT
|
|
char d_comment = "(", imm_flag; word = @d_exitforth, 0, @_comment_
|
|
//
|
|
// PLFORTH custom words
|
|
//
|
|
// BYE
|
|
char d_bye = "BYE", 0; word = @d_comment, 0, @_bye_
|
|
// SEE DEFINITION
|
|
char d_see = "SEE", interponly_flag; word = @d_bye, 0, @_see_
|
|
// PRINT STACK
|
|
char d_prstack = ".S", showcr_flag; word = @d_see, 0, @_prstack_
|
|
// PRINT RSTACK
|
|
char d_prrstack = ".RS", showcr_flag; word = @d_prstack, 0, @_prrstack_
|
|
// TRACE ON
|
|
char d_tron = "TRON", showcr_flag; word = @d_prrstack, 0, @_tron_
|
|
// TRACE OFF
|
|
char d_troff = "TROFF", showcr_flag; word = @d_tron, 0, @_troff_
|
|
// SINGLE STEP ON
|
|
char d_stepon = "STEPON", showcr_flag; word = @d_troff, 0, @_stepon_
|
|
// SINGLE STEP OFF
|
|
char d_stepoff = "STEPOFF", showcr_flag; word = @d_stepon, 0, @_stepoff_
|
|
// BREAK OUT
|
|
char d_brk = "BRK", showcr_flag; word = @d_stepoff, 0, @_brk_
|
|
// BREAK ON
|
|
char d_brkon = "BRKON", interponly_flag; word = @d_brk, 0, @_brkon_
|
|
// BREAK OFF
|
|
char d_brkoff = "BRKOFF", interponly_flag; word = @d_brkon, 0, @_brkoff_
|
|
// COMPILE USING ITC
|
|
char d_itc = "ITC", interponly_flag; word = @d_brkoff, 0, @_itc_
|
|
// COMPILE USING PLASMA BYTECODES
|
|
char d_pbc = "PBC", interponly_flag; word = @d_itc, 0, @_pbc_
|
|
//
|
|
// Start of vocabulary
|
|
//
|
|
// LIST VOCAB WORDS
|
|
char d_words = "WORDS", showcr_flag; word = @d_pbc, 0, @_words_
|
|
//
|
|
// Machine code helper routines
|
|
//
|
|
asm _get_estackdepth#1
|
|
!SOURCE "vmsrc/plvmzp.inc"
|
|
TXA
|
|
EOR #$FF
|
|
SEC
|
|
ADC #ESTKSZ/2
|
|
CMP #ESTKSZ/2+1
|
|
BCC +
|
|
LDX #ESTKSZ/2
|
|
+ DEX
|
|
STA ESTKL,X
|
|
LDA #$00
|
|
STA ESTKH,X
|
|
RTS
|
|
end
|
|
asm _get_estack(index)#1
|
|
LDA #ESTKSZ/2
|
|
CLC
|
|
SBC ESTKL,X
|
|
TAY
|
|
LDA ESTKL,Y
|
|
STA ESTKL,X
|
|
LDA ESTKH,Y
|
|
STA ESTKH,X
|
|
RTS
|
|
end
|
|
asm _reset_estack#0
|
|
LDX #ESTKSZ/2
|
|
end
|
|
asm _push(a)#0 // Stack hack - call as _push(a)to leave a on eval stack
|
|
RTS
|
|
end
|
|
//def _ffa_(dentry)#1
|
|
// return dentry + ^dentry + 1
|
|
//end
|
|
asm _ffa_(dentry)#1
|
|
LDA ESTKL,X
|
|
STA ESTKH-1,X
|
|
LDA (ESTKH-1,X)
|
|
SEC
|
|
ADC ESTKL,X
|
|
STA ESTKL,X
|
|
BCC +
|
|
INC ESTKH,X
|
|
+ RTS
|
|
end
|
|
//def _pfa_(dentry)#1
|
|
// return dentry + ^dentry + 8
|
|
//end
|
|
asm _pfa_(dentry)#1
|
|
LDY #$08
|
|
BNE +
|
|
end
|
|
//def _hfa_(dentry)#1
|
|
// return dentry + ^dentry + 4
|
|
//end
|
|
asm _hfa_(dentry)#1
|
|
LDY #$04
|
|
BNE +
|
|
end
|
|
//def _lfa_(dentry)#1
|
|
// return dentry + ^dentry + 2
|
|
//end
|
|
asm _lfa_(dentry)#1
|
|
LDY #$02
|
|
BNE +
|
|
end
|
|
//def _cfa_(dentry)#1
|
|
// return dentry + ^dentry + 6
|
|
//end
|
|
asm _cfa_(dentry)#1
|
|
LDY #$06
|
|
+ LDA ESTKL,X
|
|
STA ESTKH-1,X
|
|
TYA
|
|
CLC
|
|
ADC (ESTKH-1,X)
|
|
ADC ESTKL,X
|
|
STA ESTKL,X
|
|
BCC +
|
|
INC ESTKH,X
|
|
CLC
|
|
+ RTS
|
|
end
|
|
//def hashname(chars, len)#1
|
|
// return (len ^ ((^chars << 1) ^ ^(chars + len / 2) << 2)) & HASH_MASK
|
|
//end
|
|
asm hashname(chars, len)#1
|
|
LDA ESTKL+1,X
|
|
STA SRCL
|
|
LDA ESTKH+1,X
|
|
STA SRCH
|
|
LDA ESTKL,X
|
|
LSR
|
|
TAY
|
|
LDA (SRC), Y
|
|
ASL
|
|
ASL
|
|
EOR ESTKL,X
|
|
STA ESTKL,X
|
|
LDY #$00
|
|
LDA (SRC),Y
|
|
ASL
|
|
EOR ESTKL,X
|
|
AND #63 ; HASH_MASK
|
|
INX
|
|
STA ESTKL,X
|
|
STY ESTKH,X
|
|
RTS
|
|
end
|
|
//
|
|
// Helper routines
|
|
//
|
|
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")
|
|
memcpy(keyinbuf, gets(state & comp_flag ?? ']'|$80 :: '>'|$80), INBUF_SIZE)
|
|
inptr = keyinbuf // Reset inptr to beginning of buffer
|
|
until ^inptr
|
|
if ^inptr > INBUF_SIZE-1
|
|
^inptr = INBUF_SIZE-1
|
|
fin
|
|
^(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 addhash(dentry)#0
|
|
byte hash
|
|
|
|
hash = hashname(dentry + 1, ^dentry)
|
|
*_hfa_(dentry) = hashtbl[hash]
|
|
hashtbl[hash] = dentry
|
|
end
|
|
def buildhashtbl#0
|
|
word dentry
|
|
byte hash
|
|
|
|
memset(@hashtbl, 0, HASH_SIZE * 2)
|
|
dentry = latest
|
|
while dentry
|
|
hash = hashname(dentry + 1, ^dentry)
|
|
*_hfa_(dentry) = hashtbl[hash]
|
|
hashtbl[hash] = dentry
|
|
dentry = *_lfa_(dentry)
|
|
loop
|
|
end
|
|
//
|
|
// Warm start
|
|
//
|
|
def warmstart#0
|
|
_reset_estack()
|
|
brk = 0
|
|
brkcfa = 0
|
|
RSP = RSTK_SIZE
|
|
if state & comp_flag // Undo compilation state
|
|
heaprelease(latest)
|
|
latest = *_lfa_(latest)
|
|
fin
|
|
state = 0
|
|
while !endsrc; loop
|
|
infunc = @keyin
|
|
inptr = keyinbuf
|
|
^inptr = 0
|
|
end
|
|
//
|
|
// Cold start
|
|
//
|
|
def coldstart#0
|
|
warmstart
|
|
latest = @d_words
|
|
heaprelease(startheap)
|
|
buildhashtbl
|
|
end
|
|
//
|
|
// Find match in dictionary
|
|
//
|
|
def find(matchchars, matchlen)#1
|
|
word dentry
|
|
byte i
|
|
|
|
for i = 0 to matchlen-1
|
|
^(matchchars + i) = toupper(^(matchchars + i))
|
|
next
|
|
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 = *_hfa_(dentry)
|
|
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 == '$' // Hexadecimal
|
|
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
|
|
elsif ^numchars == '%' // Binary
|
|
numchars++
|
|
numlen--
|
|
if numlen == 0
|
|
return 0, 0
|
|
fin
|
|
while numlen
|
|
numchar = ^numchars
|
|
if numchar == '0' or numchar == '1'
|
|
num = num * 2 + numchar - '0'
|
|
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
|
|
putln; puts("( "); _prstack_; puts(") "); puts(dentry); putc(' ')
|
|
end
|
|
def brkhandle(dentry)#0
|
|
word brk_infn, brk_inptr, brk_iip
|
|
byte brk_state
|
|
char brk_inbuf[INBUF_SIZE + 1]
|
|
|
|
showtrace(dentry)
|
|
brk_iip = IIP
|
|
brk_infn = infunc
|
|
brk_inptr = inptr
|
|
memcpy(@brk_inbuf, keyinbuf, INBUF_SIZE + 1)
|
|
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
|
|
memcpy(keyinbuf, @brk_inbuf, INBUF_SIZE + 1)
|
|
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_estackdepth() > 32
|
|
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)
|
|
else // 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 not (state & comp_flag) or (^_ffa_(dentry) & imm_flag)
|
|
if not (state & comp_flag) and (^_ffa_(dentry) & componly_flag)
|
|
puts(dentry)
|
|
puts(" : Compile only word\n")
|
|
_quit_
|
|
fin
|
|
_execword_(dentry)
|
|
else
|
|
_compword_(dentry)
|
|
fin
|
|
else
|
|
value, valid = _isnum_(inchars, inlen)
|
|
if valid
|
|
if state & comp_flag
|
|
_compliteral_(value)
|
|
else
|
|
_push(value)
|
|
fin
|
|
else
|
|
inchars--
|
|
^inchars = inlen
|
|
puts(inchars)
|
|
puts(" ? No match\n")
|
|
if !brk; warmstart; fin
|
|
fin
|
|
fin
|
|
until state & exit_flag
|
|
state = state & ~exit_flag
|
|
end
|
|
//
|
|
// Intrinsics
|
|
//
|
|
def _swap_(a,b)#2
|
|
return b,a
|
|
end
|
|
def _ifdup_(a)#1
|
|
if a; _push(a); fin
|
|
return a
|
|
end
|
|
def _dup2_(a,b)#4
|
|
return a,b,a,b
|
|
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 _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 + 768 // Make sure to avoid JIT heap usage
|
|
end
|
|
def _trailing_(a,b)#2
|
|
while b and ^(a + b - 1) == ' '
|
|
b--
|
|
loop
|
|
return a, b
|
|
end
|
|
def _compare_(a,b,c,d)#1
|
|
byte i, l
|
|
|
|
l = b < d ?? b :: d
|
|
for i = 0 to l - 1
|
|
if ^(a + i) <> ^(c + i)
|
|
return ^(a + i) < ^(c + i) ?? -1 :: 1
|
|
fin
|
|
next
|
|
if b < d return -1
|
|
elsif b > d return 1
|
|
fin
|
|
return 0
|
|
end
|
|
def _latest_#1
|
|
return latest
|
|
end
|
|
def newdict#0
|
|
word plist, namechars, namelen
|
|
byte i
|
|
|
|
namechars, namelen = nextword(' ')
|
|
plist = latest
|
|
latest = heapalloc(namelen + 8)
|
|
for i = 0 to namelen-1
|
|
^(latest + i + 1) = toupper(^(namechars + i))
|
|
next
|
|
//memcpy(latest + 1, namechars, namelen)
|
|
^latest = namelen
|
|
^_ffa_(latest) = 0
|
|
*_lfa_(latest) = plist
|
|
*_hfa_(latest) = 0
|
|
*_cfa_(latest) = _pfa_(latest)
|
|
end
|
|
def _plasma_(a)#0
|
|
newdict
|
|
^_ffa_(latest) = showcr_flag
|
|
*_cfa_(latest) = a // PLASMA code address
|
|
addhash(latest)
|
|
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(latest)
|
|
end
|
|
def _const_(a)#0
|
|
newdict
|
|
_dictaddb_(JSR); _dictaddw_(vmvect)
|
|
_dictaddb_($2C) // CONSTANT WORD
|
|
_dictaddw_(a)
|
|
_dictaddb_($5C) // RET
|
|
addhash(latest)
|
|
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>
|
|
addhash(latest)
|
|
//
|
|
// 9 bytes after PFA, data follows...
|
|
//
|
|
end
|
|
def _state_#1
|
|
return state & comp_flag
|
|
end
|
|
def _dodoes_#0
|
|
_push(W + 11) // Pointer to PFA storage
|
|
execwords(*(W + 2)) // Exec PFA ptr
|
|
end
|
|
def _itcdoes_(a)#0
|
|
//
|
|
// Overwrite CREATE as ITC words
|
|
//
|
|
^_ffa_(latest) = ^_ffa_(latest) | itc_flag
|
|
*_cfa_(latest) = @_dodoes_
|
|
*_pfa_(latest) = a // Fill in DOES code address
|
|
end
|
|
def _pbcdoes_(a)#0
|
|
//
|
|
// Rewrite the end of CREATE
|
|
//
|
|
^(_pfa_(latest) + 6) = $C4 // JUMP DOES> directly
|
|
*(_pfa_(latest) + 7) = a
|
|
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 _dodefer_#0
|
|
_execword_(*(W + 2)) // Exec deferred word
|
|
end
|
|
def _defer_#0
|
|
newdict
|
|
_dictaddb_(RTS); _dictaddw_(0) // NO-OP and space for deferred pfa
|
|
addhash(latest)
|
|
end
|
|
def _is_(a)#0
|
|
word dentry
|
|
|
|
dentry = find(nextword(' '))
|
|
if dentry
|
|
^_ffa_(dentry) = ^_ffa_(a)
|
|
if ^_ffa_(dentry) & itc_flag
|
|
*_cfa_(dentry) = @_dodefer_
|
|
*_pfa_(dentry) = a
|
|
else // comp_pbc_flag
|
|
*_cfa_(dentry) = _pfa_(dentry)
|
|
^_pfa_(dentry) = JMP
|
|
*(_pfa_(dentry) + 1) = *_cfa_(a)
|
|
fin
|
|
else
|
|
puts(a); puts(" Not found")
|
|
_quit_
|
|
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_(latest) = itc_flag | showcr_flag
|
|
*_cfa_(latest) = @_docolon_
|
|
else // comp_pbc_flag
|
|
^_ffa_(latest) = showcr_flag
|
|
_dictaddb_(JSR); _dictaddw_(vmvect)
|
|
fin
|
|
if state & trace_flag
|
|
puts(latest); putc(' ')
|
|
fin
|
|
end
|
|
def _noname_#0
|
|
word plist
|
|
|
|
plist = latest
|
|
latest = heapalloc(8)
|
|
^latest = 0
|
|
*_lfa_(latest) = plist
|
|
*_hfa_(latest) = 0
|
|
state = state | comp_mode
|
|
if state & comp_itc_flag
|
|
^_ffa_(latest) = itc_flag | showcr_flag
|
|
*_cfa_(latest) = @_docolon_
|
|
else // comp_pbc_flag
|
|
^_ffa_(latest) = showcr_flag
|
|
*_cfa_(latest) = _pfa_(latest)
|
|
_dictaddb_(JSR); _dictaddw_(vmvect)
|
|
fin
|
|
if state & trace_flag
|
|
puts(latest); putc(' ')
|
|
fin
|
|
end
|
|
def _exit_#0
|
|
if state & comp_itc_flag
|
|
_dictaddw_(0)
|
|
elsif state & comp_pbc_flag
|
|
_dictaddb_($5C) // RET
|
|
fin
|
|
end
|
|
def _semi_#0
|
|
_exit_
|
|
if state & comp_itc_flag // Add double zero at end of definition for SHOW
|
|
_dictaddw_(0)
|
|
fin
|
|
if ^latest
|
|
addhash(latest) // COLON definition
|
|
else
|
|
_push(latest) // NONAME definition
|
|
fin
|
|
state = state & ~comp_flag
|
|
end
|
|
def _postpone_#0
|
|
word dentry
|
|
|
|
dentry = find(nextword(' '))
|
|
if dentry
|
|
_compword_(dentry)
|
|
else
|
|
puts("No match\n")
|
|
_quit_
|
|
fin
|
|
end
|
|
def _compoff_#0
|
|
state = state & ~comp_flag
|
|
end
|
|
def _compon_#0
|
|
state = state | comp_mode
|
|
end
|
|
def _componly_#0
|
|
^_ffa_(latest) = ^_ffa_(latest) | componly_flag
|
|
end
|
|
def _interponly_#0
|
|
^_ffa_(latest) = ^_ffa_(latest) | interponly_flag
|
|
end
|
|
def _immediate_#0
|
|
^_ffa_(latest) = ^_ffa_(latest) | imm_flag
|
|
end
|
|
def _branch_#0
|
|
IIP = *IIP
|
|
end
|
|
def _0branch_(a)#0
|
|
if a
|
|
IIP = IIP + 2
|
|
else
|
|
IIP = *IIP
|
|
fin
|
|
end
|
|
def _recurse_#0
|
|
_compword_(latest)
|
|
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 _unloop_#0
|
|
if RSP > RSTK_SIZE-1
|
|
puts("Return stack underflow\n")
|
|
_quit_
|
|
fin
|
|
RSP = RSP + 2
|
|
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)
|
|
fin
|
|
end
|
|
def _forget_#0
|
|
word dentry
|
|
|
|
dentry = find(nextword(' '))
|
|
if dentry
|
|
if isult(dentry, startheap)
|
|
latest = @d_words
|
|
dentry = startheap
|
|
else
|
|
latest = *_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 _keypressed_#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 _prbin_(a)#0
|
|
byte i
|
|
putc('%')
|
|
for i = 0 to 7
|
|
putc(a & $80 ?? '1' :: '0')
|
|
a = a << 1
|
|
next
|
|
putc(' ')
|
|
end
|
|
def _prbinw_(a)#0
|
|
byte i
|
|
putc('%')
|
|
for i = 0 to 15
|
|
putc(a & $8000 ?? '1' :: '0')
|
|
a = a << 1
|
|
next
|
|
putc(' ')
|
|
end
|
|
def _prat_(a)#0
|
|
puti(*a); putc(' ')
|
|
end
|
|
def _blank_#0
|
|
if state & comp_flag
|
|
_compliteral_(32)
|
|
else
|
|
_push(32)
|
|
fin
|
|
end
|
|
def _char_#0
|
|
word str
|
|
byte len
|
|
|
|
str, len = nextword(' ')
|
|
if state & comp_flag
|
|
_compliteral_(^str)
|
|
else
|
|
_push(^str)
|
|
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(strbuf)
|
|
memcpy(strbuf, str, len) // Copy to internal string buffer
|
|
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_#0
|
|
endsrc
|
|
end
|
|
def _ifendsrc_(a)#0
|
|
if a
|
|
endsrc
|
|
fin
|
|
end
|
|
def _see_#0
|
|
word dentry, pfa, w
|
|
|
|
dentry = find(nextword(' '))
|
|
if dentry
|
|
putc('$'); puth(dentry); putc(' '); puts(dentry)
|
|
if ^_ffa_(dentry) & imm_flag; puts(" IMMEDIATE"); fin
|
|
if ^_ffa_(dentry) & componly_flag; puts(" COMPILE-ONLY"); fin
|
|
if ^_ffa_(dentry) & interponly_flag; puts(" INTERPRET-ONLY"); fin
|
|
putln
|
|
if ^_ffa_(dentry) & itc_flag // Only show ITC words
|
|
puts("-----\n")
|
|
when *_cfa_(dentry)
|
|
is @_docolon_
|
|
pfa = _pfa_(dentry)
|
|
break
|
|
is @_dodefer_
|
|
pfa = _pfa_(*_pfa_(dentry))
|
|
break
|
|
is @_dodoes_
|
|
pfa = *_pfa_(dentry)
|
|
break
|
|
otherwise // ???
|
|
pfa = @d_exit
|
|
wend
|
|
putc('$'); puth(pfa); putc(' ')
|
|
w = *pfa
|
|
while w
|
|
if ^_ffa_(w) & param_flag
|
|
pfa = pfa + 2
|
|
when w
|
|
is @d_slit
|
|
putc('"')
|
|
puts(pfa)
|
|
putc('"')
|
|
pfa = pfa + ^pfa - 1
|
|
break
|
|
is @d_lit
|
|
puti(*pfa)
|
|
break
|
|
is @d_branch
|
|
is @d_0branch
|
|
is @d_doloop
|
|
puts(w); puts(" $"); puth(*pfa)
|
|
break
|
|
otherwise
|
|
puts(w)
|
|
wend
|
|
else
|
|
puts(w)
|
|
fin
|
|
pfa = pfa + 2
|
|
if ^_ffa_(w) & showcr_flag
|
|
putln; putc('$'); puth(pfa)
|
|
fin
|
|
putc(' ')
|
|
w = *pfa
|
|
if !w
|
|
pfa = pfa + 2
|
|
w = *pfa
|
|
if w; puts("EXIT\n"); putc('$'); puth(pfa); putc(' '); fin // Early exit
|
|
fin
|
|
if conio:keypressed()
|
|
conio:getkey(); conio:getkey()
|
|
fin
|
|
loop
|
|
puts("EXIT\n")
|
|
fin
|
|
fin
|
|
end
|
|
def _prstack_#0
|
|
byte index, depth
|
|
depth = _get_estackdepth()
|
|
index = 0
|
|
while index < depth
|
|
puti(_get_estack(index)); putc(' ')
|
|
index++
|
|
loop
|
|
end
|
|
def _prrstack_#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, width
|
|
|
|
width = cmdsys:_sysflags_ & vid80col ?? 79 :: 39
|
|
puts(typestr)
|
|
tab = ^typestr
|
|
d = latest
|
|
while d
|
|
if ^d // Skip NONAME definitions
|
|
if (typemask & ^_ffa_(d)) == type
|
|
tab = tab + 1 + ^d
|
|
if tab > width
|
|
putln;
|
|
tab = ^d
|
|
else
|
|
puts(" ")
|
|
fin
|
|
puts(d)
|
|
if conio:keypressed(); conio:getkey(); conio:getkey(); fin
|
|
fin
|
|
fin
|
|
d = *_lfa_(d)
|
|
loop
|
|
end
|
|
def _words_#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("PLEIADES FORTH v2.20\n")
|
|
if cmdsys:sysver < $0220
|
|
puts("PLASMA >= 2.20 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
|
|
latest = @d_words
|
|
while latest
|
|
if *_cfa_(latest) == 0
|
|
*_cfa_(latest) = heapmark
|
|
_dictaddb_(JSR); _dictaddw_(vmvect)
|
|
if ^_ffa_(latest) & inline_flag
|
|
_dictaddb_(^_pfa_(latest))
|
|
elsif ^_ffa_(latest) & inlinew_flag
|
|
_dictaddw_(*_pfa_(latest))
|
|
else
|
|
puts(latest); puts(": Invalid dictionary\n")
|
|
return -1
|
|
fin
|
|
_dictaddb_($5C) // RET
|
|
fin
|
|
latest = *_lfa_(latest)
|
|
loop
|
|
keyinbuf = heapalloc(INBUF_SIZE + 1)
|
|
fileio:iobufalloc(4) // Allocate a bunch of file buffers
|
|
strbuf = heapalloc(256)
|
|
inbuf = heapalloc(SRCREFS * INBUF_SIZE)
|
|
startheap = heapmark
|
|
coldstart
|
|
//
|
|
// Check for command line argument
|
|
//
|
|
inptr = argNext(argFirst)
|
|
while ^inptr and ^(inptr + 1) == '-'
|
|
when toupper(^(inptr + 2))
|
|
is 'T' // Trace flag
|
|
_tron_
|
|
is 'D' // Debug flag (indirect threaded code)
|
|
_itc_
|
|
break
|
|
otherwise
|
|
puts("Usage: +PLFORTH [-T] [-D] [SCRIPT NAME]\n")
|
|
return 0
|
|
wend
|
|
inptr = argNext(inptr)
|
|
loop
|
|
//
|
|
// Main start and restart entry
|
|
//
|
|
if not except(@exitforth)
|
|
if ^inptr; inptr++; _srcstr_; fin
|
|
_interpret_
|
|
fin
|
|
done
|