Solo Forth development history in 2016-05

Description of the page content

Solo Forth development history in 2016-05.

Tags:

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

2016-05-02

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

2016-05-04

[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.

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

2016-05-07

( ?( )

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

: 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 ?)