User Tools

Site Tools


en:pfw:prefixes

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
en:pfw:prefixes [2023-09-04 18:17] – gelöscht - Externe Bearbeitung (Unbekanntes Datum) 127.0.0.1en:pfw:prefixes [2023-09-04 18:17] (current) – ↷ Seite von pfw:prefixes nach en:pfw:prefixes verschoben uho
Line 1: Line 1:
 +====== Prefix TO ======
  
 +A simple forth implementation of TO for values,\\
 +extendable with other prefixes,\\
 +extendable for other word types.\\
 +(an 20dec2022)
 +
 +
 +===== VARIABLE & VALUE, pros & cons =====
 +
 +=== Style ===
 +  VARIABLE with @ ! and +!    = nice pure forth style
 +  VALUE with TO and +TO       = typical non forth style
 +
 +=== Psychology ===
 +• VARIABLE\\
 +The name provides the location of the variable.
 +! and @ produce programming noise that easily causes errors.
 +For pointers you need even the combinations @ @ and @ ! .\\
 +• VALUE\\
 +The name gives the value itself, which is very readable.
 +
 +=== Efficiency ===
 +Generally variables or values are more often read than written.
 +With values you get rid of many fetch commands.\\
 +( BASE @  STATE @  >IN @ )
 +
 +=== Programming technique ===
 +Variables and values allow nearly the same programming techniques.
 +The weak point of values is that sometimes the address is needed.
 +For example if you want to access a value from assembler or in
 +factorisations like this:
 +
 +AN and WO are variables:
 +   : EXCHANGE  ( an wo -- ) 2>r 2r@ @ swap @ r> ! r> ! ;
 +That's not possible with values.
 +AN and WO are values:
 +   an wo   to an to wo
 +We solved that (in noForth) with the ADR prefix.
 +ADR before a value returns the location of the value. That gives
 +VALUE at least all the technical capabilities of VARIABLE.
 +
 +=== Extendable ===
 +With the code below you can define
 +  * prefixes with other functions ( +TO INCR DECR ADR *TO ... )
 +  * prefixes for other word types ( 2VALUE STRINGVALUE ... )
 +
 +===== About the code =====
 +
 +PREFIX stands for the global prefix (symbolic, a very small number).
 +PFX stands for the real action in a specific situation.
 +A PREFIX searches the PFX-LIST for the appropriate PFX.
 +
 +Two steps in the code are //**not portable**//:
 +  : WORD-TYPE ( token -- word-type ) @ ;
 +  : DATA-ADDR ( token -- data-addr ) >body ;
 +
 +Example: 
 +  10 value TEST
 +Given the token of TEST we need a function WORD-TYPE that can determine
 +that TEST is a value. For indirect threading this could simply be a @
 +assuming that the token = CFA and that CFA @ gives DOVALUE .
 +In some forth implementations this may be problematic.
 +
 +In the code below we assume that
 +  - xt @  of a value is characteristic for values (WORD-TYPE).
 +  - the body of a value contains the data.
 +
 +===== The code =====
 +<code>
 +\ words:  PFX-LINK   PFX   FIND-PFX   PREFIX
 +
 +variable PFX-LINK       \ Linked list for pfx's
 +here 0 , pfx-link !
 +
 +\ Put a pfx in the pfx-list
 +: PFX ( 'pfx <prefix-name> <name-of-data-word> -- ) \ See examples below.
 +    here >r pfx-link @ ,
 +        ' >body @   \ prefix#
 +        ' @         \ word-type
 +        + ,         \ pfx-id ( = word-type + prefix# )
 +        ,           \ xt of pfx-action
 +    r> pfx-link ! ;
 +\ An element in the pfx-list consists of three cells: | link | pfx-id | 'pfx |
 +
 +: FIND-PFX ( pfx-id -- link )   \ pfx-id = word-type + prefix#
 +    pfx-link
 +    begin dup @             \ continue if not end of list
 +    while 2dup cell+ @ <>   \ continue while not found
 +    while @                 \ next element in the list
 +    repeat then
 +    nip ;
 +
 +\ Define a (global) prefix
 +: PREFIX ( n <name> -- )
 +    create ,  immediate     ( prefix# <prefix-name> -- )
 +    does>                   ( <name-of-a-data-word> -- )
 +    @ >r                    \ prefix#
 +    ' dup >body swap        \ data-address 'data-word
 +    @                       \ word-type
 +    r> +                    \ pfx-id ( = word-type + prefix# )
 +    find-pfx
 +    dup @ 0= abort" Prefix not allowed "
 +    cell+ cell+ @           \ jump over link and pfx-id and get xt of pfx
 +    execute ;
 +</code>
 +
 +===== The two user words =====
 +
 +  PREFIX ( n <name> -- )
 +This word is used to define a global prefix. It takes a (very small) number
 +and a name as input. The number serves as the identifier for the prefix.
 +The name is the symbolic name that will be used in your forth code. The word
 +PREFIX creates an immediate word with the provided name that, when invoked,
 +searches for the appropriate pfx action in the pfx-list based on the
 +combination of the prefix number and the word type of the next word in
 +the input stream.
 +  PFX ( 'pfx <prefix-name> <name-of-data-word> -- )
 +This word is used to add a new entry to the pfx-list. It takes as input:
 +the pfx action execution token, the symbolic (global) prefix name and
 +the name of a data word (an instance of the word type which must be made
 +accessible through the prefix).
 +
 +===== Applying PREFIX and PFX =====
 +<code>
 +\ ----- Defining global prefixes -----
 +0 prefix TO
 +1 prefix +TO
 +2 prefix ADR
 +\ etc.
 +
 +\ ----- value -----
 +: VALUE ( x name -- ) create , does> @ ;
 +
 +\ pfx's for VALUE (internal words)
 +: TO.V  ( x -- ) state @ if postpone literal postpone ! exit then ! ;
 +: +TO.V ( x -- ) state @ if postpone literal postpone +! exit then +! ;
 +: ADR.V ( -- x ) state @ if postpone literal then ;
 +
 +\ Put the pfx's for VALUE in pfx-list. We have to create a value to achieve this.
 +7 value AMSTERDAM
 +' to-v  pfx   to amsterdam
 +' +to.v pfx  +to amsterdam
 +' adr.v pfx  adr amsterdam
 +
 +\ Better: define !() in assembler (msp430 example)
 +\ code !() ( x -- )  \ store x in inline following address
 +\    ip )+ day mov   \ read inline address
 +\    tos day ) mov   \ store x in that address
 +\    sp )+ tos mov
 +\    next end-code
 +\ Then          postpone literal postpone !
 +\ becomes       postpone !() ,
 +
 +\ ----- 2value -----
 +: 2VALUE ( dx name -- ) create , , does> 2@ ;
 +: TO.2V  ( x -- ) state @ if postpone literal postpone 2! exit then 2! ;
 +
 +\ Put pfx's for 2VALUE in pfx-list
 +77777. 2value ROTTERDAM
 +' to.2v pfx    to rotterdam
 +' adr.v pfx   adr rotterdam    \ Same action as for VALUE
 +</code>
 +===== Testing =====
 +<code>
 +\ ----- value test -----
 +amsterdam                 .
 +1 to amsterdam  amsterdam .
 +1 +to amsterdam amsterdam .
 +adr amsterdam           .
 +
 +10 value OSLO        oslo .
 +: T1 1  to oslo ; t1 oslo .
 +: T2 1 +to oslo ; t2 oslo .
 +: T3 adr oslo ;      t3 @ .
 +
 +\ ----- 2value test -----
 +rotterdam                      d.
 +11111. to rotterdam  rotterdam d.
 +adr rotterdam 2@               d.
 +
 +: T4 to rotterdam ;
 +22222. t4            rotterdam d.
 +: T5 adr rotterdam 2@ ;     t5 d.
 +55555. +to rotterdam    ( this should cause an error )
 +\ <><>
 +</code>
 +<html><h2 style="background-color:yellow">Alternative Implementations</h2></html>