Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.forth > #25452 > unrolled thread
| Started by | JennyB <jennybrien@googlemail.com> |
|---|---|
| First post | 2013-08-28 12:14 -0700 |
| Last post | 2013-08-29 13:35 -0700 |
| Articles | 6 — 4 participants |
Back to article view | Back to comp.lang.forth
A Host of Interpreters (Part 1) JennyB <jennybrien@googlemail.com> - 2013-08-28 12:14 -0700
Re: A Host of Interpreters (Part 1) Lars Brinkhoff <lars.spam@nocrew.org> - 2013-08-29 09:27 +0200
A Host of Interpreters (Part 1) JennyB <jennybrien@googlemail.com> - 2013-08-29 04:00 -0700
Re: A Host of Interpreters (Part 1) anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2013-08-29 13:58 +0000
Re: A Host of Interpreters (Part 1) "Elizabeth D. Rather" <erather@forth.com> - 2013-08-29 07:41 -1000
Re: A Host of Interpreters (Part 1) JennyB <jennybrien@googlemail.com> - 2013-08-29 13:35 -0700
| From | JennyB <jennybrien@googlemail.com> |
|---|---|
| Date | 2013-08-28 12:14 -0700 |
| Subject | A Host of Interpreters (Part 1) |
| Message-ID | <851c246a-73d0-4efd-aa00-d98b93952fca@googlegroups.com> |
Back when ANS was new I wrote a compatibility layer for F83 that implemented a new parasitic outer interpreter. I chose to write it as though headers were separate from code and data space (they aren't in F83) so I could use Alias all the F83 words that were compatible directly into the new wordset.
This needed some (though surprisingly little) internal knowledge of F83. If I were to confine myself to portable Standard code (with no knowledge of header or code space), I could not of course write a full Standard Forth interpreter. Godel knew that. But it is possible to write a Forth-ish one,and the variations are - interesting.
Replacing FIND
There has been long and tedious debate over how to define words that have independent interpretation and compilation semantics, and even they are worth defining. Some Forths implement dual words as two separate definitions, only one of which can be found while interpreting. I will not do that because:
1 It is not possible to FIND the previous version of a definition without knowledge of the dictionary structure.
2 It means that ' or ['] may only find words with interpretation semantics.
3 It makes FIND STATE-dependant, so that to portably FIND compile-only words, FIND has to execute in compilation state even while interpreting.
I want to be able to make STATE obsolete and specify both interpretation and compilation behaviours explicitly. So the new word has to return two cells, and the new header has to store them:
: CFIND \ ensure compilation version of FIND
\ if it is STATE-dependant
STATE @ IF FIND ELSE
] FIND POSTPONE [ THEN ;
: FOUND \ addr -- 1st 2nd | addr 0
CFIND IF >BODY 2@ ELSE FALSE THEN ;
VARIABLE LASTDEF
: HEADER CREATE HERE LASTDEF ! 2 CELLS ALLOT ;
: DEFINED! ( 1st 2nd -- ) LASTDEF @ 2! ;
So if those two cells are sufficient to describe both the interpretation and compilation behaviour of any word, what should they contain? An xt for interpretation, perhaps, and one for compilation. The latter expects the former on the stack, so for default words it is COMPILE, for IMMEDIATE words it is EXECUTE , and for dual words where the compilation behaviour has nothing to do with interpretation it is something beginning with DROP.
: INTERPRETED ( xt ct -- ?? ) DROP EXECUTE ;
: COMPILED ( xt ct -- ?? ) EXECUTE ;
:NONAME COMPILE, ; CONSTANT DO-DEFAULT
' EXECUTE CONSTANT DO-IMMEDIATE
: AKA \ /old name/ /new name/ add an old word to the new interpreter
BL WORD CFIND DUP 0= ABORT" No such word"
1= IF DO-IMMEDIATE ELSE DO-DEFAULT THEN
HEADER DEFINED! ;
THE PROBLEM WITH XTs
At its simplest, an xt is a pointer into native machine code. Using :NONAME we can get an xt for a new colon definition, but we can't do the same for words defined using the new CREATE without more intimate knowledge of the host. Why not? Because these words need not only an xt to describe /what/ they do, but an address in data space to tell them /where/ to do it. The code to which their xt points may have the data address in-line or passed on the return stack of a CALL or…
There is a way round, so long as you only need colon definitions to have EXECUTEable xts:
For colon definitions and words imported from the host,the first cell holds an xt.
For new CONSTANTS, the first cell holds the value.
For all other new words the first cell is a pointer into data space.
In each case the second cell is a pointer to a table that describes how to interpret or compile that type of word.
: INTERPRETED ( 1st 2nd -- ?? ) @ EXECUTE ;
: COMPILED ( 1st 2nd -- ?? )
@ CELL+ @ EXECUTE ;
: WORDCLASS CREATE 2, ;
' EXECUTE
:NONAME COMPILE, ;
WORDCLASS DO-DEFAULT
' EXECUTE
' EXECUTE
WORDCLASS DO-IMMEDIATE
: NOOP ;
' NOOP
:NONAME POSTPONE LITERAL ;
WORDCLASS DO-DATA
' @
:NONAME POSTPONE LITERAL POSTPONE @ ;
WORDCLASS DO-VALUE
DEFINING WORDS
The new defining words will be AKAed by their proper names later.
: _CONSTANT ( n -- )
DO-DATA HEADER DEFINED! ;
: _CREATE HEADER HERE DO-DATA DEFINED! ;
\ not just HERE CONSTANT because building the
\ header alters the value in HERE
: _VARIABLE _CREATE 0 , ;
: _VALUE ( n -- ) HEADER HERE TUCK , DO-VALUE DEFINED! ;
: _IMMEDIATE LASTDEF @ @ DO-IMMEDIATE DEFINED ! ;
\ this only works where the last definition has an xt, but now
\ we can specify the compiling action of a word in other ways.
: DEFINES ( xt -- ) DO-DEFAULT HEADER DEFINED! ;
: _:NONAME 0 :NONAME ;
: _: ['] NOOP DEFINES LASTDEF @ :NONAME ;
: _; POSTPONE ; ?DUP IF \ not a :noname
SWAP ! \ put the xt where it should be
In Standard Forth the current definition cannot compile a reference to itself. This version of : will compile a noop if its own name is found.
RECURSE cannot be replicated portably because the xt laid down by :NONAME is not available until the definition is finished. For any particular host it is fairly simple to discover how deeply it is buried by :NONAME and place a copy into the first cell of the header, so that the definition becomes naturally recursive.
To redefine a word use :NONAME … NAME … ; DEFINES NAME
The slower way round the RECURSE problem is to DEFER a word and later set it to the definition that calls it:
:NONAME @ EXECUTE ;
:NONAME POSTPONE LITERAL POSTPONE @ POSTPONE EXECUTE ;
WORDCLASS DO-DEFER
: _DEFER ['] NOOP DO-DEFER HEADER DEFINED! ;
: _DEFER! ( xt xt -- )
>BODY DUP CELL+ @ DO-DEFER <> ABORT" Not a deferred word"
! ;
e.g. DEFER LATER
: NOW … IF … LATER THEN … ;
' NOW ' LATER DEFER!
CREATING NEW DEFINING WORDS
To get the equivalent of CREATE DOES> we need a completely new syntax:
:NONAME @ DUP CELL+ SWAP @ EXECUTE ;
\ 1st cell points to xt, followed by data
:NONAME @ DUP CELL+ POSTPONE LITERAL @ COMPILE, ;
WORDCLASS DO-DOES
: DEFINER ( xt -- ) HEADER HERE DO-DOES DEFINED! , ;
: defining_word CREATE build DOES> action ;
becomes:
: defining_word ['] action DEFINER build ;
This also works when interpreting for a one-off example:
' action DEFINER word_name build
COMING UP: S" IS ACTION-OF TO Literals and Interpreter Loops
[toc] | [next] | [standalone]
| From | Lars Brinkhoff <lars.spam@nocrew.org> |
|---|---|
| Date | 2013-08-29 09:27 +0200 |
| Message-ID | <85ppsxdki4.fsf@junk.nocrew.org> |
| In reply to | #25452 |
Thank you! Very interesting.
[toc] | [prev] | [next] | [standalone]
| From | JennyB <jennybrien@googlemail.com> |
|---|---|
| Date | 2013-08-29 04:00 -0700 |
| Message-ID | <7dbd9e42-eb7e-426b-b674-b3ad01d41697@googlegroups.com> |
| In reply to | #25452 |
I got a little confused with the definition of DEFER! above: it will only work with the host version of ' .
The new version looks like this:
: _' BL WORD FOUND 0= ABORT" No such word" ;
Which returns the contents of the first cell of the header whether or not it is an xt. That seems fair to me. Mostly if I want an xt to execute later (say by indexing into a table) the word needed is a colon definition - and if not, a suitable xt can be produced by wrapping it in a :NONAME . It's always possible to test whether a particular word produces an executable xt or not:
: '? ( ++ xt true | non-xt false )
BL WORD FOUND @ @ ['] EXECUTE = ;
So the new interpreter doesn't really need a special DEFER! . Since ticking a deferred word returns its data address, it's action can be set by:
' action ' deferred !
[toc] | [prev] | [next] | [standalone]
| From | anton@mips.complang.tuwien.ac.at (Anton Ertl) |
|---|---|
| Date | 2013-08-29 13:58 +0000 |
| Message-ID | <2013Aug29.155822@mips.complang.tuwien.ac.at> |
| In reply to | #25452 |
JennyB <jennybrien@googlemail.com> writes:
>THE PROBLEM WITH XTs
>At its simplest, an xt is a pointer into native machine code. Using :NONAME=
> we can get an xt for a new colon definition, but we can't do the same for =
>words defined using the new CREATE without more intimate knowledge of the h=
>ost. Why not? Because these words need not only an xt to describe /what/ th=
>ey do, but an address in data space to tell them /where/ to do it. The code=
> to which their xt points may have the data address in-line or passed on th=
>e return stack of a CALL or=85=20
>
>There is a way round, so long as you only need colon definitions to have EX=
>ECUTEable xts:
That's quite a big restriction, as the words >BODY, DEFER@ and DEFER!
become pointless: They all work on xts of words that are not colon
definitions.
One way to solve your problem is pretty much the way that traditional
Forth implementations have worked:
The xt is the address of the code field, and the code field contains
the code address of the native code (or, in your meta-interpreter, the
host-xt of a word that implements the behaviour you want.
The cell after the code field (or maybe two cells after, depending on
how you implement DOES>) is the parameter field, which is the body of
a CREATEd word, or may contain other data for CONSTANTs and other
defining words.
Otherwise, nice article.
- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: http://www.forth200x.org/forth200x.html
EuroForth 2013: http://www.euroforth.org/ef13/
[toc] | [prev] | [next] | [standalone]
| From | "Elizabeth D. Rather" <erather@forth.com> |
|---|---|
| Date | 2013-08-29 07:41 -1000 |
| Message-ID | <MLKdnSHAHe0yGoLPnZ2dnUVZ_s-dnZ2d@supernews.com> |
| In reply to | #25463 |
On 8/29/13 3:58 AM, Anton Ertl wrote: > JennyB <jennybrien@googlemail.com> writes: >> THE PROBLEM WITH XTs >> At its simplest, an xt is a pointer into native machine code. Using :NONAME= >> we can get an xt for a new colon definition, but we can't do the same for = >> words defined using the new CREATE without more intimate knowledge of the h= >> ost. Why not? Because these words need not only an xt to describe /what/ th= >> ey do, but an address in data space to tell them /where/ to do it. The code= >> to which their xt points may have the data address in-line or passed on th= >> e return stack of a CALL or=85=20 >> >> There is a way round, so long as you only need colon definitions to have EX= >> ECUTEable xts: > > That's quite a big restriction, as the words >BODY, DEFER@ and DEFER! > become pointless: They all work on xts of words that are not colon > definitions. > > One way to solve your problem is pretty much the way that traditional > Forth implementations have worked: > > The xt is the address of the code field, and the code field contains > the code address of the native code (or, in your meta-interpreter, the > host-xt of a word that implements the behaviour you want. > > The cell after the code field (or maybe two cells after, depending on > how you implement DOES>) is the parameter field, which is the body of > a CREATEd word, or may contain other data for CONSTANTs and other > defining words. Or, better still, the code in question is capable of starting by pushing on the stack the address of the data field of the object wherever it is. You don't need to specify implementation, and you certainly don't have to restrict xt's to colon definitions! Cheers, Elizabeth -- ================================================== Elizabeth D. Rather (US & Canada) 800-55-FORTH FORTH Inc. +1 310.999.6784 5959 West Century Blvd. Suite 700 Los Angeles, CA 90045 http://www.forth.com "Forth-based products and Services for real-time applications since 1973." ==================================================
[toc] | [prev] | [next] | [standalone]
| From | JennyB <jennybrien@googlemail.com> |
|---|---|
| Date | 2013-08-29 13:35 -0700 |
| Message-ID | <5a63d739-a103-4ffc-a1e0-2cfdb950f2b9@googlegroups.com> |
| In reply to | #25465 |
On Thursday, 29 August 2013 18:41:03 UTC+1, Elizabeth D. Rather wrote: > > Or, better still, the code in question is capable of starting by pushing > > on the stack the address of the data field of the object wherever it is. > > You don't need to specify implementation, and you certainly don't have > > to restrict xt's to colon definitions! > Yes, that's what you would do in practice, given sufficient knowledge of host or target. It's not hard. But for a quick-and-dirty working model, accepting the restriction is a /lot/ easier than working a way round it (and documenting it). Sometimes "everything is a ..." is not the simplest metaphor.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.forth
csiph-web