en:pfw:prefixes
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revision | |||
| en:pfw:prefixes [2023-09-04 18:17] – gelöscht - Externe Bearbeitung (Unbekanntes Datum) 127.0.0.1 | en: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 | ||
| + | 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 ===== | ||
| + | < | ||
| + | \ words: | ||
| + | |||
| + | variable PFX-LINK | ||
| + | here 0 , pfx-link ! | ||
| + | |||
| + | \ Put a pfx in the pfx-list | ||
| + | : PFX ( 'pfx < | ||
| + | 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+ @ <> | ||
| + | while @ \ next element in the list | ||
| + | repeat then | ||
| + | nip ; | ||
| + | |||
| + | \ Define a (global) prefix | ||
| + | : PREFIX ( n < | ||
| + | create , immediate | ||
| + | does> | ||
| + | @ >r \ prefix# | ||
| + | ' dup >body swap \ data-address ' | ||
| + | @ \ 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 ; | ||
| + | </ | ||
| + | |||
| + | ===== The two user words ===== | ||
| + | |||
| + | PREFIX ( n < | ||
| + | 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 < | ||
| + | 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 ===== | ||
| + | < | ||
| + | \ ----- 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 | ||
| + | |||
| + | \ ----- 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 | ||
| + | </ | ||
| + | ===== Testing ===== | ||
| + | < | ||
| + | \ ----- value test ----- | ||
| + | amsterdam | ||
| + | 1 to 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 | ||
| + | 11111. to rotterdam | ||
| + | adr rotterdam 2@ d. | ||
| + | |||
| + | : T4 to rotterdam ; | ||
| + | 22222. t4 rotterdam d. | ||
| + | : T5 adr rotterdam 2@ ; t5 d. | ||
| + | 55555. +to rotterdam | ||
| + | \ <><> | ||
| + | </ | ||
| + | < | ||