Solo Forth development history in 2015-06
Description of the page content
Solo Forth development history in 2015-06.
2015-06-02
Start, based on the disassembled code of Abersoft Forth.
First changes:
Some fig-Forth words are renamed with their modern forms: vlist as words, -dup as ?dup, minus as negate, dminus as dnegate, s->d as s>d, mon as bye, free as unused.
Old synonyms are removed: end and endif.
The editor is removed.
branch and back are modified to do absolute branches. The branches are converted with a simple substitution, thanks to the comments prepared by the disassembling of Abersoft Forth.
New words, from the Afera library: \, .(, char and [char], 2-, 1-, 2*.
2+ and 1+ are converted to Z80.
forth is not immediate any more.
' is converted to non-immediate; new immediate version: ['].
2015-06-03
dliteral is renamed as 2literal.
Removed: verify.
2015-06-04
New: upperc and uppers.
Improvement: -find is made case insensitive.
key is documented.
Removed: udg, init-disc, .cpu.
New: <>.
Improvement: the lower part of the screen can be used.
Removed: loadt, savet, (tape) and tape headers.
Removed: triad.
Change: inp renamed as p@; outp renamed as p!.
Change: stacks and buffers are moved to the bottom of the memory map, before the interpreter. They must be below 0xC000 in order to use the memory banks.
Change: r renamed as r@; the Z80 code of i is moved to r@, and the cfa of i is pointed to the pfa of r@. This is logical and faster (formerly r was a colon word that called i).
New: clit and cliteral. Their code ocuppies 46 bytes, but there are 84 compiled bytes that save one byte when using clit instead of lit, and it's faster.
Change: bleep is moved to the blocks disk.
Improvement: quit is optimized: faster and smaller.
New: bounds; used in type.
Removed: not (synonym of 0=).
Change: offset deactivated.
New: block>sector and first tries with the new version of r/w, that uses the sectors of the disk. The screens can be listed, but only the first time. They are shown corrupted when trying to access them more than once. Something is wrong.
New: plotted?, with the code of Afera's point.
New: [if] [else] [then], from Afera. They still need changes.
New: copied require and its related words from lina ciforth and started adapted them.
2015-06-05
New: nip, tuck.
Improvement: 2drop rewritten in Z80.
New: rdrop, in Z80 (exit is pointed to it); 2rdrop and unloop.
Removed: plot (faster version, from Afera, added to the blocks disk); draw (faster version will be create).
Improvement: Error messages are included in screens 4 and 5 of the blocks disk. In order to avoid numbers 0 and 16 (that coincide with the first lines of screens 4 and 5, and are incompatible with the fsb format), some error messages are reorganized (and updated in the main source).
New: -rot in the blocks disk.
New: recurse.
Change: pfa is renamed as nfa>pfa; the rest of the family is renamed with the prefix "pfa>". This is a first step before reorganizing the headers to make them faster, probably moving the lfa before the nfa, and also modifying ' and ['] to return the cfa instead of the pfa.
Fix: there was an old relative branch calculation in then.
Fix: cliteral, recently implemented, used comma!
Fix: +buf used clit for the new b/buf 4 +, that is greater than 0xFF! Now the blocks in disk work fine.
Change: The first six user variables, unused, are moved to the end of the space. All the related pointers are apdated. Conditional compilation is used, just in case. The final goal is to reorganize the parameter area, removing all unnecessary fig-Forth stuff.
Change: Entry points are moved to the start (new origin).
New: Copied decode from Afera. First changes to adapt it.
2015-06-06
New: msg-scr, idea from lina ciforth, useful to customize the organization of the screens on disk.
2015-06-07
Change: faster and smaller versions of ink and paper, from the Afera library. This saves 264 bytes!
New: constants true and false; primitives on and off.
Change: conditional compilation flag to free the IX register, originally used as the user variables pointer, in order to hold next. This way jumps to next are faster and save one byte per jump (52 bytes saved).
Change: user_variables_pointer_init_value is removed. The fig-Forth model uses it in cold, but it's not needed because the memory map is not calculated during the cold start. In fact it is not used by Abersoft Forth.
Fix: The new version of at, taken from Spectrum Forth-83, had a copying mistake, a missing dup.
New: continued, as a factor of load.
Change: optimizations in the definitions, thanks to the new words: 1- instead of 1 minus, 2- instead of 2 -. Also 2dup instead of over over, an oversight of Abersoft Forth.
Improvement: Some operators are (re)written, using Z80 code from DZX-Forth.
2015-06-08
Improvement: faster blanks and erase, with Z80 jumps into fill.
Improvement: the branches of x (the null word) are optimized.
Improvement: one branch removed from ." (2 bytes less, and faster in compiling mode).
Change: Now ' and ['] return the cfa, not the pfa.
New: cfa>pfa, cfa>lfa, cfa>nfa (pfa>nfa and pfa>lfa could be removed).
Change: forget is updated to the new behaviour of ' and moved to the blocks file; also the code in the blocks file is updated.
2015-06-09
Change: flash, bright, gover and inverse are moved to the disk.
Problem detected with (emit) and those four booleans attributes.
New: pick, from DZX-Forth.
Change: The original system to print out with link wasn't practical, because it copied to the printer everything that was printed on the screen. It is removed. Now the new words printer and display are used instead.
2015-06-10
Changes in (emit), in order to fix the problems with boolean attributes. It seems the channel must be opened every time; or the temporary attributes must be set. Finally, all color words are written in Z80, in the kernel, sharing one main routine: printing the chars required to set the temporary attribute, and then calling the ROM routine that makes it permanent. This method works for all attributes and print flags. Example:
paper_nfa:
db 0x05+0x80,'PAPE','R'+0x80
paper_lfa:
dw bright_nfa
paper_:
dw paper_pfa
paper_pfa:
ld a,paper_char
jp color
ink_nfa:
db 0x03+0x80,'IN','K'+0x80
ink_lfa:
dw paper_nfa
ink_:
dw ink_pfa
ink_pfa:
ld a,ink_char
color:
; Set a color attribute (ink, paper, bright, flash, inverse or gover).
; a = attribute control char
; (tos) = color attribute value
rst 0x10
pop hl
ld a,l
rst 0x10
call rom_set_permanent_colors_0x1CAD
_jp_next
The color words are removed from the blocks disk.
Improvement: smaller and faster ?terminal.
Change: the use of the IX register to hold the address of next is made definitive. The conditional compilation for the old method is removed.
Improvement: when the IX register must be preserved because of ROM calls, now ld ix,next is used instead of push ix and pop ix; it's faster and easier, and uses the same memory (4 bytes).
New: ms, time@, time! and time0, copied from Afera.
2015-06-11
The parameters of enclose have been exchanged. This saves a swap in word.
New: pixel-add Z80 routine in the library disk.
Improvement: plot and plotted? use the whole screen.
2015-06-13
The parsing bug has been found. The problem is enclose use an 8-bit register as offset counter. It can not be used to scan a 512-byte buffer. The code has been rewritten to use a pair register as offset counter.
There's a second bug: something fails when the parsing of the screen passes from the first to the second disk block.
Some experimental changes to the null word, with simpler and faster flow.
2015-06-17
Modification in expect; the code that manages the delete key wasted some bytes.
Fix: on and off changed only the first part of the value! That was the reason the second block of screens was not parsed: in was not properly set to zero in the null word.
Improvement: One byte saved in id..
Fix: typo in number in pixel. Now the new point and plot work with Y coordinate range 0..191.
New: the strings module of the Afera library is included in the disk.
New: code (based on create, that will be rewritten), end-code, assembler (empty vocabulary).
New: [defined], [undefined], ?--> and ?\ are included in the kernel, copied from the Afera library. They are essential to manage the disk screens.
Improvement: 2swap is rewritten is Z80, copying the code from DZX-Forth.
Change: size is moved to the disk. It's needed only by system.
Change: -find is renamed as find, and factored out with context-find, in order to implement defined?, needed by required.
Change: i' is moved to the disk.
New: rp, required to rewrite i' outside the kernel.
New: [true] and [false], fram Afera.
2015-06-18
Improvement: Macros are used to create the headers.
Fix: ?exit.
Improvement: faster and smaller 2@ and 2over, do_two_constant.
if 0 ; XXX OLD -- From Abersoft Forth
inc hl ; T06 1
inc hl ; T06 1 ; high part
ld e,(hl) ; T07 1
inc hl ; T06 1
ld d,(hl) ; T07 1
push de ; T11 1
dec hl ; T06 1
dec hl ; T06 1
ld d,(hl) ; T07 1
dec hl ; T06 1
ld e,(hl) ; T07 1
push de ; T11 1
_jp_next ; T08 2
;T104 14 TOTAL
else ; XXX NEW -- From DZX-Forth
ld e,(hl) ; T07 1
inc hl ; T06 1
ld d,(hl) ; T07 1
inc hl ; T06 1
ld a,(hl) ; T07 1
inc hl ; T06 1
ld h,(hl) ; T07 1
ld l,a ; T04 1
ex de,hl ; T04 1
jp pushde ; T10 3
; T11 0 push de
; T11 0 push hl
; T86 12 TOTAL
; Faster and shorter than the code of C/PM fig-Forth 1.1g
; (T94 14):
if 0
EXX ; T04 1 ; save IP
POP HL ; T10 1 ; addr
LD C,(HL) ; T07 1
INC HL ; T06 1
LD B,(HL) ; T07 1 ; dH
INC HL ; T06 1
LD E,(HL) ; T07 1
INC HL ; T06 1
LD D,(HL) ; T07 1 ; dL
PUSH DE ; T11 1 ; (S2)<--dL
PUSH BC ; T11 1 ; (S1)<--dH
EXX ; T04 1 ; restore IP
_jp_next ; T08 2 ; jp (ix)
; T94 14
endif
New: 2r@.
Change: First changes to modify the format of the name field, removing the end bit of the last char. The new format will make some things easier.
Change: dr0 removed.
Improvement: nip used in / and */.
2015-06-19
Improvement: The new format of name fields is finished and working. The old format can be selected with conditional compilation, just in case, until the system is fully tested.
Some things, like id., are simpler now:
_colon_header id_dot_,'ID','.'
if fig_name_field?
dw pad_
dw c_lit_
db max_word_length+1
dw c_lit_
db 0x5F ; XXX why this char?
dw fill_
dw dup_,nfa_to_lfa_,over_ ; ( nfa lfa nfa )
dw minus_ ; ( nfa len+1 )
dw pad_,swap_,cmove_
dw pad_,count_ ; ( pad len+name_bound_bit_mask+n )
dw c_lit_
db max_word_length
dw and_ ; ( pad len )
dw two_dup_,plus_,one_minus_ ; address of the last char ( pad len pad+len-1 )
if 0 ; XXX OLD
dw dup_,fetch_
dw lit_,0xFF7F,and_
dw swap_,store_
else ; XXX NEW
dw dup_,c_fetch_
dw c_lit_
db 0x7F
dw and_,swap_,c_store_
endif
dw type_,space_
dw semicolon_s_
else ; XXX NEW -- name field without end bit in the last char
dw count_
dw c_lit_
db max_word_length_bit_mask
dw and_
dw type_,space_
dw semicolon_s_
endif
The main change is (find):
_code_header paren_find_,'(FIND',')'
; (FIND) ( ca nfa --- pfa b tf | ff )
if fig_name_field?
; XXX TODO optimize speed with absolute jumps?
; XXX TODO -- return cfa instead of pfa
; XXX TODO -- always return two elements, after Forth-94
pop de ; nfa
paren_find.begin:
; (sp) = string address
; de = nfa
pop hl ; string address
push hl ; save for next iteration
ld a,(de) ; length byte
xor (hl) ; filter deviations
and 0x3F ; mask msb and precedence bit
jr nz,paren_find.skip_name_field ; lengths differ
paren_find.compare_next_char:
inc hl ; next character in string
inc de ; next character in name field
ld a,(de)
xor (hl) ; filter deviations
add a,a
jr nz,paren_find.not_a_match ; no match
jr nc,paren_find.compare_next_char ; match so far, loop again
; The string matches.
; de = address of the last char of the name field
ld hl,0x0005 ; offset from lfa-1 to pfa
add hl,de
ex (sp),hl ; pfa to stack
paren_find.search_for_length_byte:
dec de ; position de on nfa
ld a,(de)
or a ; msb=1?; if so, length byte
jp p,paren_find.search_for_length_byte ; no, try next char
ld e,a ; length byte
ld d,0x00
ld hl,true
jp pushde ; name field found, return
paren_find.not_a_match:
; Above name field not a match, try next one
jr c,paren_find.name_field_skipped ; carry = end of name field
paren_find.skip_name_field:
; Find end of name field
inc de
ld a,(de)
or a ; msb=1?
jp p,paren_find.skip_name_field ; no, loop
paren_find.name_field_skipped:
inc de ; lfa
ex de,hl
ld e,(hl)
inc hl
ld d,(hl)
ld a,d
or e ; end of dictionary?
jp nz,paren_find.begin ; if not, continue
; No match found, return
pop hl ; drop string address
jp false_pfa
else
ld (ip_backup),bc ; save Forth IP
pop de ; nfa
pop hl ; string address
ld (paren_find.string_address),hl
paren_find.begin:
; Compare the string with a new word.
; de = nfa
ld (paren_find.nfa_backup),de ; save for later
paren_find.string_address: equ $+1
ld hl,0 ; string address
ld a,(de) ; name field length byte
ld c,a ; save for later
and max_word_length_bit_mask ; actual length
cp (hl)
jr nz,paren_find.not_a_match ; lengths differ
; Lengths match.
ld a,c ; name field length byte
and max_word_length_bit_mask ; actual length
ld b,a
paren_find.compare_next_char:
inc hl ; next character in string
inc de ; next character in name field
ld a,(de)
cp (hl)
jr nz,paren_find.not_a_match ; no match
djnz paren_find.compare_next_char ; match so far, loop again
; The string matches.
; de = address of the last char of the name field
; c = name field length byte
ld hl,5 ; offset from lfa-1 to pfa
add hl,de
push hl ; pfa
ld e,c ; length byte
ld d,0
ld hl,true
ld bc,(ip_backup) ; restore Forth IP
jp pushde
paren_find.not_a_match:
; Not a match, try next one.
paren_find.nfa_backup: equ $+1
ld hl,0 ; nfa
ld a,c ; length byte
and max_word_length_bit_mask ; actual length
ld c,a ; actual length
inc c ; plus the length byte
ld b,0
add hl,bc ; hl = lfa
ld e,(hl)
inc hl
ld d,(hl)
ld a,d
or e ; end of dictionary?
jp nz,paren_find.begin ; if not, continue
; No match found, return.
ld bc,(ip_backup) ; restore Forth IP
jp false_pfa
endif
Change: The new word header substitutes create. create is changed after Forth-94. Its role in fig-Forth was already taken by code.
Change: First steps to implement a modern version of find, after
Fix: message had a strange condition, from Abersoft Forth, to prevent from printing message number zero when warning is on.
Added ?branch to decode. Solo Forth uses both 0branch (branch if zero) and ?branch (branch if not zero).
2015-06-20
The new version of find, rewritten after Forth-83 and Forth-94, seems to work fine. Also the new version of the name field works fine. Conditional compilation is used for both changes, just in case.
New: error does not push the values of blk and in, but stores them in a new double variable called error-pos. where fetchs them from there. This is cleaner and more flexible, because the last error position can be shown any time.
New: label, a define word that returns the address of its pfa, like a variable, but stores nothing into it. Useful to create machine code routines or data buffers.
New: nfa>string, adapted from DZX-Forth. It was a natural factor of the new version of id..
Improvement: error saves the error number into the new variable error#.
Change: slit, sliteral, s, and s" are moved from the disk to the kernel. Basic string support is needed to manage the disk screens (require, locate, compare and others).
New: scr/disk constant, screens per disk. It will be needed to compile a variant for +3DOS, or to use disk drives of different sizes.
New: cells, cell and cell+.
New: set of hex numbers printing words, adapted from lina.
2015-06-21
compare is finished. Some changes were necessary in the code of DZX-Forth.
; ----------------------------------------------
_code_header compare_,'COMPAR','E'
; Adapted from DZX-Forth.
pop de ; de = len2
pop hl ; hl = ca2
ex (sp),hl ; hl = len1 ; ( ca1 ca2 )
ld a,d
cp h
jr nz,compare.lengths
ld a,e
cp l
compare.lengths:
; cy = string2 is longer than string1?
jr c,compare.ready
ex de,hl
compare.ready:
; de = length of the short string
; hl = length of the long string
ld l,c
ld h,b ; hl = Forth IP
pop bc ; bc = ca2
ex (sp),hl ; hl = ca1 ; save Forth IP
push af ; save carry flag
compare_.compare_strings: equ $+1 ; XXX not used yet
call compare_strings_case_sensitive
;jr z,compare.match
jr nz,compare.no_match
compare.match:
; The smaller string matches.
pop af ; restore flags
jr compare.end
compare.no_match:
; The smaller string does not match.
pop bc ; useless carry flag
compare.end:
pop bc ; restore Forth IP
ld hl,1
jp c,pushhl
dec hl ; 0
jp z,pushhl ; string1 equals string2
dec hl ; -1
jp pushhl
compare_strings_case_sensitive:
; Copied from DZX-Forth.
; Used by 'compare' and 'search'.
; Input:
; HL = a1
; BC = a2
; DE = len
; Output:
; Z = match?
ld a,e
or d
ret z
ld a,(bc)
cp (hl)
ret nz
inc hl
inc bc
dec de
jp compare_strings_case_sensitive
New: <mark, <resolve, >mark and >resolve,, after Forth-83. <resolve substitutes fig-Forth's back. With this words, the code of control structures is clearer, more legible, and it's easier to implement new ones.
Change: A bit simpler and faster endcase.
Change: cswap is renamed as flip, after eForth; upperc is renamed as upper.
New: :noname, copied from the Afera library.
New: search, adapted from DZX-Forth.
Change: count is rewritten in Z80, faster and smaller (using the end of clit to push the result).
2015-06-22
Improvement: faster and smaller > and <, using code from DZX-Forth. New: 0>, based on the same code.
_code_header zero_greater_than_,'0','>'
pop de
ld hl,0
jp is_de_less_than_hl
_code_header greater_than_,'','>'
pop hl
pop de
jp is_de_less_than_hl
_code_header less_than_,'','<'
if 1 ; XXX NEW -- from DZX-Forth
pop de
pop hl
is_de_less_than_hl:
call compare_de_hl_signed
if size_optimization?
jp true_if_cy
else
jp c,true_pfa
jp false_pfa
endif
else ; XXX OLD
pop de ; n2
pop hl ; n1
ld a,d
xor h ; one of them negative?
jp m,less_than.wich_negative ; if so, determine which
; no one is negative
and a ; clear carry
sbc hl,de
less_than.wich_negative:
if 0 ; XXX OLD
; Original version from Abersoft Forth, badly optimized
; because of the two 'ld hl' and two `jp push_hl`.
inc h
dec h ; h negative?
jp m,less_than.true
ld hl,false
jp push_hl
less_than.true:
ld hl,true
jp push_hl
else ; XXX NEW
; Version from CP/M fig-Forth 1.1g,
; with additional improvement for speed:
; bit 7,h ; h negative?
; ld hl,false
; jp z,push_hl
; inc l ; true ; XXX TODO -- change to `dec hl` when true=-1
; jp push_hl
; Optimized for space:
bit 7,h ; h negative?
jp z,false_pfa
jp true_pfa
endif
endif
Faster and smaller version of u<, in Z80; the correspondent u> is added.
; ----------------------------------------------
_code_header 'U','>'
pop hl
u_greater_than.hl:
pop de
jp u_less_than.de_hl
; ----------------------------------------------
if 0 ; XXX OLD -- original
_colon_header u_less_than_,'U','<'
dw two_dup_
dw xor_
dw zero_less_than_
dw zero_branch_,branch_destination_0x6585
dw drop_
dw zero_less_than_
dw zero_equals_
dw branch_,u_less_than_.end
branch_destination_0x6585:
dw minus_
dw zero_less_than_
u_less_than_.end:
dw semicolon_s_
else
_code_header u_less_than_,'U','<'
pop de
pop hl
u_less_than.de_hl:
call compare_de_hl_unsigned
if size_optimization?
jp true_if_cy
else
jp c,true_pfa
jp false_pfa
endif
endif
New: emits, converted from eForth; spaces is rewritten to use it.
line is removed; it was a rest from the editor.
Faster and smaller lfa>nfa:
if 0 ; XXX OLD
_colon_header lfa_to_nfa_,'LFA>NF','A'
lfa_to_nfa.begin:
dw one_minus_,dup_,c_fetch_ ; ( a c )
dw c_lit_
db name_bound_bit_mask
dw and_
dw zero_branch_,lfa_to_nfa.begin ; until
dw semicolon_s_
else ; XXX NEW
_code_header lfa_to_nfa_,'LFA>NF','A'
pop hl
lfa_to_nfa.do:
dec hl
bit name_bound_bit,(hl)
jp z,lfa_to_nfa.do:
jp push_hl
endif
Improvement: simpler and faster version of the null word.
_colon_header x_,'',0,immediate
if 0 ; XXX OLD -- original version
dw blk_,fetch_ ; input stream from disk?
dw zero_branch_,x.from_terminal
; From disk.
dw one_,blk_,plus_store_ ; next disk buffer
dw in_,off_ ; clear `in`, preparing parsing of input text
dw blk_,fetch_,b_slash_scr_,one_minus_,and_,zero_equals_ ; last buffer?
dw zero_branch_,x.end
; The last buffer, the end of the text block.
dw question_exec_ ; error if not executing
; Discard the address of `?stack` after `execute` in the interpretation loop.
dw from_r_,drop_
dw branch_,x.end
x.from_terminal:
dw from_r_,drop_
x.end:
dw semicolon_s_
else ; XXX NEW -- simpler and faster flow
dw blk_,fetch_ ; input stream from disk?
dw zero_branch_,x.exit ; if not, branch
; From disk.
dw one_,blk_,plus_store_ ; next disk buffer
dw in_,off_ ; clear `in`, preparing parsing of input text
; Note: This check of the last block is specific for 2 blocks per screen;
; the generic slower check would be `blk @ b/scr 1- and`.
dw blk_,fetch_,one_,and_ ; was it the last block of the screen?
dw question_branch_,x.end ; if not, branch
; Last block of the screen.
dw question_exec_ ; error if not executing
x.exit:
dw r_drop_
x.end:
dw semicolon_s_
endif
New smaller and faster versions of min and max, in Z80. New: umin and umax. All of them are adapted from DZX-Forth:
; ----------------------------------------------
_code_header umax_,'UMA','X'
; umax ( u1 u2 -- u1 | u2 )
pop de
pop hl
call compare_de_hl_unsigned
jp max.1
; ----------------------------------------------
_code_header umin_,'UMI','N'
; umin ( u1 u2 -- u1 | u2 )
pop de
pop hl
call compare_de_hl_unsigned
jp max.2
; ----------------------------------------------
if 0 ; XXX OLD
_colon_header min_,'MI','N'
dw two_dup_
dw greater_than_
dw zero_branch_,min.end
dw swap_
min.end:
dw drop_
dw semicolon_s_
else
_code_header min_,'MI','N'
pop de
pop hl
call compare_de_hl_signed
jp max.2
endif
; ----------------------------------------------
if 0 ; XXX OLD
_colon_header max_,'MA','X'
dw two_dup_
dw less_than_
dw zero_branch_,max.end
dw swap_
max.end:
dw drop_
dw semicolon_s_
else
_code_header max_,'MA','X'
pop de
max.de:
pop hl
call compare_de_hl_signed
max.1:
ccf
max.2:
jp c,push_hl
ex de,hl
jp push_hl
endif
Change: in renamed as >in, blanks renamed as blank,; forgot during the vocabulary modernizing.
First tries to implement a more efficient parsing method, with parse.
Change: screen, p! and p@ are moved to the disk.
Improvement: Optimized version of s>d:
_code_header s_to_d_,'S>','D'
if 0 ; XXX OLD
pop de
ld hl,0
ld a,d
and 0x80 ; negative?
jr z,s_to_d.end ; jump if not negative
dec hl
s_to_d.end:
jp push_de_hl
else ; XXX NEW
ld hl,0
pop de
ld a,d
or a
jp p,push_de_hl ; jump if positive
dec hl
jp push_de_hl
endif
Fix: severe error recently introduced in id..
New: 2>r and 2r>, adapted from DZX-Forth:
; ----------------------------------------------
_header _two_to_r,'2>','R'
; 2>r ( -- x1 x2 ) ( R: x1 x2 -- )
ld hl,(return_stack_pointer)
ld de,-cell*2
add hl,de
ld (return_stack_pointer),hl
jp two_store.into_hl_pointer
; ----------------------------------------------
_header _two_from_r,'2R','>'
; 2r> ( -- x1 x2 ) ( R: x1 x2 -- )
ld hl,(return_stack_pointer)
push hl
ld de,cell*2
add hl,de
ld (return_stack_pointer),hl
jp two_fetch_pfa
The original fig-Forth text is removed. It has become obsolete after implementing parse:
if 0 ; XXX OLD
_colon_header text_,'TEX','T'
; text ( c "ccc<c>" -- pad len )
; Accept following text to `pad`. _c_ is the text delimiter.
dw here_,c_slash_l_,one_plus_,blank_ ; fill the word buffer with blanks
dw word_
dw here_ ; origin
dw pad_ ; destination
dw c_slash_l_,one_plus_ ; count
dw cmove_
dw pad_,count_
dw semicolon_s_
endif
variable, 2variable, constant, 2constant and label are simplified, rewritten around create.
Adapted ." to parse:
_colon_header dot_quote_,'.','"',immediate
if 0 ; XXX OLD
dw c_lit_
db '"'
dw comp_question_ ; compiling?
dw zero_branch_,dot_quote.interpreting
; Compiling.
dw compile_,paren_dot_quote_
dw word_
dw here_,c_fetch_,one_plus_,allot_
dw semicolon_s_
dot_quote.interpreting:
dw word_,here_,count_,type_
dw semicolon_s_
else
dw c_lit_
db '"'
dw parse_ ; ( ca len )
dw comp_question_
dw zero_branch_,dot_quote.interpreting
; Compiling.
dw compile_,paren_dot_quote_,s_comma_
dw semicolon_s_
dot_quote.interpreting:
dw type_
dw semicolon_s_
endif
Copied .s from Afera. The original algorithm was taken from v.Forth.
: .s ( -- )
depth
dup s>d <# [char] > hold #s [char] < hold #> type space
if sp@ 2- s0 @ 2- do i @ . -2 +loop then ;
Copied 2nip from Afera to the library disk. The original code was taken from DZX-Forth.
2015-06-23
New: parse-word.
Improved cmove:
_code_header cmove_,'CMOV','E'
if 0 ; XXX OLD
ld l,c ; 04t 01b
ld h,b ; 04t 01b
pop bc ; 10t 01b
pop de ; 10t 01b
ex (sp),hl ; 19t 01b
ld a,b ; 04t 01b
or c ; 04t 01b
jr z,cmove.end ; 07t 02b / 12t
ldir ; 02b ; 21t/01t
cmove.end:
pop bc ; 10t 01b
; 62t 12b TOTAL
_jp_next
else ; XXX NEW
exx ; 04t 01b
pop bc ; 10t 01b
pop de ; 10t 01b
pop hl ; 10t 01b
ld a,b ; 04t 01b
or c ; 04t 01b
jr z,cmove.end ; 07t 02b / 12t
ldir ; 02b ; 21t/01t
cmove.end:
exx ; 04t 01b
; 52t 11b TOTAL
_jp_next
endif
Change: cmove> and move are moved to the kernel. move is rewritten in Z80, with code from DZX-Forth.
New: $!, with the code of DZX-Forth's packed. Name after lina's string words.
Improvement: faster and smaller -trailing, with code from DZX-Forth:
if 0 ; XXX OLD
_colon_header minus_trailing_,'-TRAILIN','G'
dw dup_,zero_
dw paren_do_
minus_trailing.do:
dw two_dup_,plus_
dw one_minus_
dw c_fetch_,b_l_,not_equals_
dw zero_branch_,minus_trailing.space
; not a space
dw leave_
dw branch_,minus_trailing.loop
minus_trailing.space:
dw one_minus_
minus_trailing.loop:
dw paren_loop_,minus_trailing.do
dw semicolon_s_
else ; XXX NEW
_code_header minus_trailing_,'-TRAILIN','G'
pop de
pop hl
push hl
add hl,de
ex de,hl
; de = address after the string
; hl = length of the string
minus_trailing.begin:
ld a,l
or h ; exhausted?
jp z,push_hl
dec de ; next char
ld a,(de)
cp ' ' ; space?
jp nz,push_hl
dec hl ; new length
jp minus_trailing.begin ; repeat
endif
Fix: 2>r and 2r> had typos in the header macro.
Faster and smaller char, with parse-word instead of word.
First tries with require and its related words, adapted from lina ciforth.
New: binary number printing words, after the lina's tool for hex numbers.
2015-06-24
A bit better code for (do), from CP/M fig-Forth 1.1g
_code_header paren_do_,'(DO',')'
if 0 ; XXX OLD -- original from Abersoft Forth
ld hl,(return_stack_pointer) ; 20t 03b
dec hl ; 06t 01b
dec hl ; 06t 01b
dec hl ; 06t 01b
dec hl ; 06t 01b
ld (return_stack_pointer),hl ; 16t 03b
pop de ; 10t 01b
ld (hl),e ; 07t 01b
inc hl ; 06t 01b
ld (hl),d ; 07t 01b
pop de ; 10t 01b
inc hl ; 06t 01b
ld (hl),e ; 07t 01b
inc hl ; 06t 01b
ld (hl),d ; 07t 01b
;126t 19b TOTAL
else ; XXX NEW -- from CP/M fig-Forth 1.1g
exx ; 04t 01b
pop de ; 10t 01b
pop bc ; 10t 01b
ld hl,(return_stack_pointer) ; 20t 03b
dec hl ; 06t 01b
ld (hl),b ; 07t 01b
dec hl ; 06t 01b
ld (hl),c ; 07t 01b
dec hl ; 06t 01b
ld (hl),d ; 07t 01b
dec hl ; 06t 01b
ld (hl),e ; 07t 01b
ld (return_stack_pointer),hl ; 16t 03b
exx ; 04t 01b
;116t 18b TOTAL
endif
2015-06-25
Fix: require and locate needed to save the parsed words to the circular string buffer.
Fix: emits didn't check values less than zero; this affected spaces and d.r.
New: smove, equivalent to swap move but much faster.
New: bank, required to use a memory page to store the name fields and link fields.
_code_header bank_,'BAN','K'
; doc{
;
; bank ( n -- )
;
; Page memory bank _n_ at 0xC000..0xFFFF.
;
; }doc
di
pop de ; e = bank
ld a,(sys_bankm) ; get the saved status of BANKM
and 0xF8 ; erase bits 0-2
or e ; modify bits 0-2
ld (sys_bankm),a ; update BANKM
out (bank1_port),a ; page the bank
ei
_jp_next
The fig-Forth name field format is definitively removed. It remained as an option, just in case, but everything works fine with the new format.
- Fix:
plothad a typo in the compilation of the Z80 code.
- Fix: branches shown by
decodestill were relatives.
Finished the conversion of [if] [else] [then].
Counted the number of times constants 0, 1, 2 and 3 are compiled in the code, in order to decide about them:
| Number | Times compiled (not including error numbers) |
|---|---|
| 0 | 20 |
| 1 | 11 |
| 2 | 11 |
| 3 | 6 |
2015-06-26
First changes to store the name and link fields in a memory bank (with a pointer to the correspondent cfa), freeing dictionary memory.
2015-06-27
Fix: The final memory bank selection in (find) corrupted the returned cfa.
Fix: The algorithm of the new cfa>nfa (for name fields in paged memory) had a bug.
Fix: The new nfa>string (for name fields in a paged memory) had a wrong header.
New: the version header for name fields in paged memory is finished.
2015-06-28
First tries with field names in paged memory. So far the code was tried without actually changing the memory bank, but using the same memory addresses. nfa>cfa and words need to change the bank.
New: n@ fetchs from the names bank.
Change: renamed s0 to sp0 and r0 to rp0, after Laxen&Perry's F83.
The old original optional code related to fig-Forth's find is removed. The new version of find with all its related words has been working fine.
2015-06-29
Fix: immediate and smudge didn't paged the names bank.
New: postpone:
_colon_header postpone_,'POSTPONE',immediate
; doc{
;
; postpone ( "name" -- ) \ ANS Forth, C I
;
; Skip leading space delimiters. Parse name delimited by a
; space. Find name. Append the compilation semantics of _name_ to
; the current definition.
;
; }doc
dw defined_ ; ( ca 0 | cfa 1 | cfa -1 )
dw dup_,question_defined_ ; error if not found
dw zero_less_than_ ; non-immediate word?
dw zero_branch_,postpone.end
; Non-immediate word.
dw compile_,compile_ ; compile `compile`
postpone.end:
dw comma_ ; compile the cfa
dw semicolon_s_
First drafts of alternative definitions of do-loop structures, with code adapted from Spectrum Forth-83, v.Forth and DZX-Forth, in order to implement ?do.
Change: now variable and 2variable do not initialize their contents, after ANS Forth. 3 has been removed.
Fix: continued could not be used from the command line, because it does not save and restore the input-source specification. A check is added, with ?loading; (load) is factored out, and called also by load.
fig-Forth recognizes the end of the input stream when a null character is found. Disk buffers already have a null at the end of the actual data space, and expect adds it after the typed text. enclose parses the null character as an unconditional delimiter and treats it apart in order to simulate the null word has been parsed, which is the word that actually does the unnesting.
The problem of the described method is the null character needs a special parsing treatment, what makes new words like skip and scan to be less versatile.
In order to solve that, a change has been made: instead of a null character, a null word is stored at the end of the buffers: a null character surrounded by spaces. This way, the null character needs no special treatment during the parsing. This new method is compatible with the original fig-Forth parsing words, though they will be replaced.
Change: expect is improved after Forth-83 (it does not add anything after the text any more); query is updated accordingly, adding the null word at the end of the received text.
Fix: The new version of word didn't updated >in to the space after the word, what caused the new versions of s", .( and .", that use parse, to include the first space of their strings.
