Solo Forth development history in 2016-05
Description of the page content
Solo Forth development history in 2016-05.
2016-05-01
Test and document tabulate
:
( tabulate )
need column
variable /tabulate 8 /tabulate !
\ doc{
\
\ /tabulate ( -- a )
\
\ A variable that holds the number of spaces that `tabulate`
\ counts for. Its default value is 8.
\
\ See `tabulate`.
\
\ }doc
: tabulate ( -- ) column 1+ /tabulate @ tuck mod - spaces ;
\ doc{
\
\ tabulate ( -- )
\
\ Display the appropriate number of spaces to tabulate to the
\ next position, using the value of `/tabulate`.
\
\ Note `tabulate` does not uses the "tab" control code, whose
\ behaviour depends on the screen mode (in the default screen
\ mode, it moves the cursor 16 positions to right).
\ `tabulate` is independent on the screen mode, since it uses
\ spaces.
\
\ See `/tabulate`.
\
\ }doc
Add conditional compilation to the cursor words and document them:
( column last-column row last-row at-x at-y )
[uneeded] column [unneeded] last-column [unneeded] at-y and and
?\ : column ( -- col ) xy drop ;
\ doc{
\
\ column ( -- col )
\
\ Current column (x coordinate).
\
\ }doc
[unneeded] last-column
?\ : last-column ( -- row ) column 1- ;
\ doc{
\
\ last-column ( -- col )
\
\ Last column (x coordinate) in the current screen mode.
\
\ }doc
[uneeded] row [unneeded] last-row [unneeded] at-x and and
?\ : row ( -- row ) xy nip ;
\ doc{
\
\ row ( -- row )
\
\ Current row (y coordinate).
\
\ }doc
[uneeded] row [unneeded] last-row
?\ : last-row ( -- row ) row 1- ;
\ doc{
\
\ last-row ( -- row )
\
\ Last row (y coordinate) in the current screen mode.
\
\ }doc
[unneeded] at-x
?\ : at-x ( col -- ) row at-xy ;
\ doc{
\
\ at-x ( col -- )
\
\ Set the cursor at the given column (x coordinate) and the
\ current row (y coordinate).
\
\ }doc
[unneeded] at-y
?\ : at-y ( row -- ) column swap at-xy ;
\ doc{
\
\ at-y ( row -- )
\
\ Set the cursor at the current column (x coordinate) and the
\ given row (y coordinate).
\
\ }doc
- Make
chars
an alias ofnoop
, saving 3 bytes - Add
holds
- Improve and document
overprint
andinverse
- Simplify
default-colors
- Simplify
cls
- Factor
permanent-colors
fromink
- Add color system variables
- Fix
border
(it didn't update the system variable BORDCR, which is used by G+DOS to restore the border) - Add
color
,2color
and related words - Add
clshift
, 8-bit version oflshift
2016-05-02
- Compact the library (it had become larger than 800 blocks, the capacity of a G+DOS disk)
- Add
string-parameter
- Move
[compile]
to the library
Make two library disk instead of one: The main disk library of the library doesn't include the sample games anymore. A secondary disk includes them instead of the meta benchamarks and meta tests. This was necessary because the library has grown too much, and it's near the limit of a G+DOS disk (800 KiB).
Remove sgn
. It was implemented in Forth without noticing that polarity
, implemented in Z80, did exactly the same but much faster, and it's shorter.
Add warning"
:
( warning" )
\ Credit:
\
\ Adapted from pForth and modified.
need string-parameter
: (warning") ( f -- )
string-parameter rot if type else 2drop then ;
\ doc{
\
\ (warning") ( f -- )
\
\ Inner procedure compiled by `warning"`. If _f_ is not
\ zero, print the compiled message; else do nothing.
\
\ }doc
: warning"
\ Compilation: ( "ccc<quote>" -- )
\ Execution: ( f -- )
postpone (warning") ," ; immediate compile-only
\ doc{
\
\ warning"
\
\ Compilation: ( "ccc<quote>" -- )
\
\ Parse and compile a message.
\
\ Execution: ( f -- )
\
\ If _f_ is not zero, print the compiled message; else do
\ nothing.
\
\ }doc
2016-05-03
- Add
warning"
- Make three library disks instead of two: 1) core; 2) core + meta tools; 3) core + sample games
2016-05-04
- Rename and add color words
- Move
inverse
to the library - Move
overprint
to the library - Improve
paper
andink
- Move
printer
to library - Rename
chan
tochannel
- Move
defer@
to the library (free memory aftercold
is above 32800 bytes by the first time) - Make pictured output string buffer configurable, by the new variable
/hold
- Add
words#
:
[needed] words# [if]
: words# ( -- n ) 0 trail begin ( n nt ) dup 0<> while
swap 1+ swap name<name
repeat drop ; [then]
\ doc{
\
\ words# ( -- n )
\
\ Return number _n_ of words defined in the first word list
\ of the search order.
\
\ }doc
Current count of words, after loading need
and words#
: 3 in root
, 518 in forth
, 10 in assembler
.
- Rename
s=
tostr=
. Addstr>
andstr<
. Names after Gforth. - Fix spacing in
.wid
.
2016-05-05
Rare but serious bug found in search
:
\ String of 71 chars:
s" match "
\ Shorten to 64 chars:
drop 64
\ Search for match:
s" match "
search \ wrong match at the last space of the long string!
2016-05-06
- Improve compilation and documentation of
alias
. - Replace the buggy code of
search
, adapted from DZX-Forth, with code adapted from Z88 CamelForth. - Improve
compare
. - Replace remaining
[compile]
withpostpone
. - Make
from
andlocate
optional. - Improve conditional compilation of printing control.
- Improve printing of nameless word lists.
- Fix
header,
: movecurrent-latest
to the kernel. - Improve
leave
. - Improve
2r>
- Improve
0=
,=
and<>
. - Make the faster
<
definitive.
2016-05-07
- Improve the
indexer
tool: no data space is used anymore: the block of the word is stored instead of its execution token. - Fix
mode42
, which didn't loadedmode32
, needed as default mode. - Improve the screen mode modules: Tidy sources, improve documentation and compact blocks.
- Improve
need
by increasing the circular string buffer: Sometimes[needed]
and[unneeded]
failed becauseneeded-word
was overwritten in the circular string buffer. The size of the buffer has been doubled. The definitive solution will be to implement a string stack in the system memory bank. A simple test has been added for the debugging. Documention has been improved. - Fix code typos in "printing.cursor.fsb". The module "printing.cursor.fsb" could not be loaded because of some typos.
- Fix the error of
?locate
: The word shown by.error-word
, which is the last parsed word, was inadequate when?locate
threw its error #-268. Now?locate
makes itneeded-word
. Some related documentation has been updated in the kernel. - Compact
!p
and@p
into one block. - Add
?(
: A simpler alternative to[if]
.
( ?( )
need str=
\ Note: `?((` uses 35 bytes of data space (not including
\ `str=`).
: ?( ( f "ccc<space><question><paren><space>" -- )
0= ?exit begin parse-name dup
while s" ?)" str= ?exit
repeat ; immediate
: ?) ( -- ) ; immediate
2016-05-08
- Improve
z80-asm,
, the alternative assembler: The alternative version of the assembler, not used yet, will be smaller and more versatile than the current version,z80-asm
. Many changes have been done towards that goal. Not tested yet. - Add
need-here
: An optional variant ofneed
to resolve requirements in the current block.
: need-here ( "name" -- )
parse-name
needed-word 2@ 2>r new-needed-word 2dup undefined?
if blk @ load else 2drop then 2r> needed-word 2! ;
\ doc{
\
\ need-here ( "name" -- )
\
\ If "name" is not a word found in the current search order,
\ load the current block.
\
\ This is a faster alternative to `need`, when the needed
\ word is in the same block, and conditional compilation is
\ used with `?\`, `?(` or `[if]`.
\
\ }doc
2016-05-09
Remove transfer-mode
: it was a factor of read-mode
and write-mode
, but it had no utility by itself. It has been integrated into read-mode
, while write-mode
does an unconditional branch to it. This saves 7 bytes in the kernel.
Release version 0.7.0.
Improve compilation of the assemblers: Now the contents of base
, the compilation word list and the search order are saved before compiling the assemblers, and restored at the end. Formerly base
was set to decimal at the end, while the search order and the compilation word list were set to the cold
defaults. This caused problems when an assembler was needed in special circumstances.
Add align
and aligned
.
2016-05-10
Fix [char]
.
Add the Forth-94 core tests written by John Hayes in 1995. The code had to be adapted to run from blocks, especially some tests that parsed source text lines.
Release version 0.8.0.
Fix harmless bug in locate-reneed
.
Improve compilation of "memory.misc.fsb": Remove dependency on the assembler. Add conditional compilation. Compact the blocks. Remove unused code.
Rename @cell+
to @+
, add 2@+
.
Fix !a
, !a+
, c@a+
: The module of the address register has been compacted and documented. During the process three bugs, caused by wrong Z80 opcodes, were discovered and fixed.
Simplify the circular string buffer: So far the internal offset of the buffer was stored before the buffer data. It has been moved to >csb
, which formerly was a fake variable, a constant that returned the address of the offset, and now is an actual variable. This saves a cell and is more versatile. In total, ten bytes are saved with some related changes.
Add 2storer
.
Add !>
, 2!>
and c!>
: Words that change the value of constants, inspired by IsForth's !>
.
2016-05-11
Improve value
, to
and their variants. The default versions (standard value
and to
, and non-standard 2value
, 2to
, cvalue
and cto
) have been combined into one single module, rewritten as aliases and documented. The standard alternative versions of value
, 2value
and to
have been documented.
Rename non-parsing value
/ to
to val
/ toval
.
2016-05-12
Finish refill
, improve -->
. Now refill
supports blocks. -->
has been rewritten after it.
Remove set-latest-lex
. A factor of interpret
and compile-only
that was not useful, because there are no more flags to set. Removing it saves 5 bytes.
Improve hided
.
Fix requirements of [cconst]
.
2016-05-13
Fix [else]
with refill
: Now [if]
can cross block boundaries.
Add benchmark for ?throw
.
Fix to
, 2to
and cto
: immediate
was missing.
Add load-app
:
[unneeded] load-app ?( need locate
variable loading-app
\ doc{
\
\ loading-app ( -- a )
\
\ A variable that holds a flag: Is an application being
\ loaded? This flag is modified by `load-app` and `end-app`.
\
\ See `load-app`, `end-app`.
\
\ }doc
: end-app ( -- ) loading-app off ; end-app
\ doc{
\
\ end-app ( -- )
\
\ End a app of the library.
\
\ See `load-app`, `loading-app`.
\
\ }doc
: load-app ( "name" -- )
loading-app on
blocks locate ?do loading-app @ 0= ?leave i load
loop end-app ; ?)
\ doc{
\
\ load-app ( "name" -- )
\
\ Load an application from the blocks disk. An application
\ is a set of blocks that are loaded as a whole. They don't
\ have block headers except the first one, which contains
\ "name", and therefore they don't have internal requisites.
\ Applications dont't need `-->` or any other word to change
\ the loading: The loading starts from the first block of the
\ disk that has "name" in its header, and continues until the
\ last block of the disk or until `end-app` is executed.
\
\ See `end-app`, `loading-app`.
\
\ }doc
Document fill
, erase
, blank
.
2016-05-14
Fix refill
:
; ----------------------------------------------
_colon_header refill_,'REFILL'
; doc{
;
; refill ( -- f )
;
; ----
; : refill ( -- f )
; loading? if blk @ 1+ dup block>source block? exit then
; false source-id ?exit 0= query ;
; ----
;
; Origin: Forth-94 (CORE EXT, BLOCK EXT); Forth-2012 (CORE EXT,
; BLOCK EXT).
;
; }doc
dw loading_question_ ; input source is a block?
dw zero_branch_,refill.not_loading ; if not, branch
refill.block:
dw blk_,fetch_,one_plus_,dup_,block_to_source_
dw block_question_
dw exit_
refill.not_loading
dw false_,source_id_,question_exit_
dw zero_equals_,query_
dw exit_
Fix parse-all
(was parse-line
); finish execute-parsing
and document it.
Move evaluate
and string>source
to the library: These words are not used in the kernel, and evaluate
can be rewritten after execute-parsing
, which is in the library. This saves 28 bytes in the kernel.
( execute-parsing string>source evaluate )
need ?(
[unneeded] string>source ?(
: string>source ( ca len -- )
blk off (source-id) on set-source ; ?)
\ doc{
\
\ string>source ( ca len -- )
\
\ Set the string _ca len_ as the current source.
\
\ }doc
[unneeded] execute-parsing ?( need need-here
need-here string>source
: execute-parsing ( ca len xt -- )
nest-source >r string>source r> execute unnest-source ; ?)
\ doc{
\
\ execute-parsing ( ca len xt -- )
\
\ Make _ca len_ the current input source, execute _xt_, then
\ restore the previous input source.
\
\ Origin: Gforth.
\
\ }doc
[unneeded] evaluate ?( need need-here
need-here execute-parsing
: evaluate ( i*x ca len -- j*x )
['] interpret execute-parsing ; ?)
\ doc{
\
\ evaluate ( i*x ca len -- j*x )
\
\ Save the current input source specification. Store
\ minus-one (-1) in `source-id`. Make the string described
\ by _ca len_ both the input source and input buffer, set
\ `>in` to zero, and interpret. When the parse area is
\ empty, restore the prior input source specification.
\
\ Origin: Forth-94 (CORE), Forth-2012 (CORE).
\
\ }doc
2016-05-15
Shorten hex
: A branch saves one cell, more important than speed in this case. hex
and decimal
have been documented.
Rename hided
to the correct hidden
.
2016-05-17
Move >body
and body>
to the library.
Improve up
: Now up
is a variable, not a constant that returns the address where the value is stored. This change is necessary to implement multitasking, and it saves one cell.
Improve conditional compilation of word lists tools.
Release version 0.9.0.
2016-05-18
Modify the structure of vocabularies: Now vocabularies don't keep the data of a word list in their body. Instead, they create a wordlist and store only its address. This way, vocabulary
can be moved to the library, even if there are three vocabularies in the kernel (root
, forth
and assembler
). But the main advantage of this change is conversion can work in both directions: a word list identifier can be get from a vocabulary name, no matter if the vocabulary was created with vocabulary
or out of an existent word list; and a vocabualary can be created from a word list, and its structure will be identical to those created by vocabulary
.
Move vocabulary
to the library; adapt assembler
.
Use wordlist
for parse-escaped-string
: No need to use vocabulary
for a standard tool.
Use wordlist
for replaces
(under development).
Improve format of error messages: Now backslash is printer after the error code, and only when text messages are active. This looks clearer and saves 2 bytes in the kernel.
Fix >body
and body>
: Their codes were exchanged when they were moved to the library.
2016-05-21
Improve the decode
tool: Improve the check in colon-cfa?
. Compact decode-special
. Fix decode
, which showed the usage instructions before checking the word.
2016-05-31
Prepare improved implementation of the search order, written after the standard words.
Prepare improving 0
, 1
and 2
. These constants save one compiled byte (because in the kernel the _literal
macro compiles bytes with clit
; and the outer interpreter is been modified to do the same), but they are slower than literals at run-time. Removing them would free 26 bytes from the kernel.
Simple benchmark for cliteral
, which saves one compiled byte and is a bit faster at run-time:
( cliteral-bench )
\ 2016-05-31
need cliteral need bench{ need }bench.
: literal-bench ( n -- )
bench{ 0 do [ cell ] literal drop loop }bench. ;
: cliteral-bench ( n -- )
bench{ 0 do [ cell ] cliteral drop loop }bench. ;
: run ( n -- )
dup cr
." literal " literal-bench cr
." cliteral " cliteral-bench cr ;
\ Times Frames (1 frame = 50th of second)
\ ----- ---------------------------------
\ literal cliteral
\ ------- -----------
\ 10000 54 52 (0.96)
\ 65535 355 345 (0.97)
Improve compilation of 8-bit literals:
literal
is replaced with the new word 1literal
in interpret-table
. This causes 8-bit literals will be compiled by cliteral
instead of literal
, what saves one byte of data space and is faster at run-time. cliteral
was moved from the library to the kernel, and byte?
was added in order to do the check.
; ----------------------------------------------
_code_header byte_question_,'BYTE?'
; doc{
;
; byte? ( n|b -- f )
;
; Is _n|b_ an 8-bit number?
;
; }doc
; Credit:
; Word adapted from DZX-Forth.
pop hl
ld l,h
jp zero_equals.hl
; ----------------------------------------------
_colon_header c_literal_,'CLITERAL',immediate+compile_only
; doc{
;
; cliteral ( b -- )
;
; Compile _b_ in the current definition.
;
; This word does the same than `literal` but saves one byte
; of data space and is a bit faster at run-time (0.97 of
; execution speed).
;
; ----
; : cliteral ( b -- )
; postpone clit c, ;
; ----
;
; Origin: Comus.
;
; }doc
dw compile_,c_lit_,c_comma_
dw exit_
; ----------------------------------------------
_colon_header literal_,'LITERAL',immediate+compile_only
; doc{
;
; literal ( n -- )
;
; Compile _n_ in the current definition.
;
; ----
; : literal ( n -- )
; postpone lit , ;
; ----
;
; }doc
dw compile_,lit_,comma_
dw exit_
; ----------------------------------------------
_colon_header one_literal_,'1LITERAL',immediate+compile_only
; doc{
;
; 1literal ( n|b -- )
;
; Compile _n|b_ in the current definition.
;
; ----
; : 1literal ( n|b -- )
; dup byte? if postpone cliteral exit then postpone literal ;
; ----
;
; }doc
dw dup_,byte_question_
dw zero_branch_,literal_pfa
dw branch_,c_literal_pfa
These changes add 31 bytes to the kernel, but they will make the programs smaller and faster.
Improve 0
, 1
and 2
: Now they are code words (faster than byte constants created by cconstant
). 0
is an alias of false
(more practical than the other way around, because there are several Z80 jumps to the code field of false
) and cell
is an alias of 2
. These changes need no extra memory, and make these so much used constants faster.
Improve constant
and cconstant
: now their run-time code runs directly into @
and c@
, so it's faster. This change saves 8 bytes.
Improve 2constant
: now its run-time code (instead of that of 2r>
, less used) runs directly into 2@
. This makes double constants faster and saves one byte from the kernel.
Add -1
: It is defined with the former code of true
, and true
is converted to an alias. This saves 8 bytes in the kernel and makes any compiled -1 faster than a literal and one cell smaller.
Add ''
and >>name
: They allow to get the execution token pointer of a name, and convert it to its associated name token; this makes it possible to get the actual name of an alias, what is impossible from its shared execution token.
( >>link name>> >>name '' >body body> )
[unneeded] >>link
?\ need alias ' cell+ alias >>link ( xtp -- lfa ) exit
[unneeded] name>>
?\ : name>> ( nt -- xtp ) [ 2 cells ] literal - ; exit
[unneeded] >>name
?\ : >>name ( xtp -- nt ) [ 2 cells ] literal + ; exit
need ?(
[unneeded] '' ?( need need-here need-here name>>
: '' ( "name" -- xtp ) defined dup ?defined name>> ; exit ?)