TITLE
Parrot Forth
Introduction
This document assumes that you're familiar with Forth. If you aren't, more help can be found at http://www.forth.org.
Parrot Forth is based on the ANS Forth standard, with some GForth extensions, as well as some local extensions specifically for interfacing with the underlying Parrot engine and interacting with other Parrot code.
Caveats
Please be aware that Parrot Forth is a work in progress and, as such, isn't yet done. Not all of the ANS core and core-ext words are in, and bits and pieces of other sections of the ANS extension word set (such as some of the floating-point words) are in place.
Parrot forth will eventually provide at least all the core and core-ext words, with the behaviour caveats as noted later on in this document.
Parrot Extensions
This section details the spots where Parrot Forth differs from ANS forth.
Parrot variants of standard structures
Internally Parrot is very different from most forths, in part because of its VM nature and in part through a desire to make it easy for Parrot Forth to interact with other Parrot languages. This has resulted in a number of decisions that are, for the most part, legitimate interpretations of the standard (such as using a combined data stack) but unusual.
Some, like the lack of double words and single-precision floats, may break programs that expect to be able to manipulate parts of values. (As, once you push a doubleword on to the stack you can treat each half as a separate single-cell value, albeit very machine-dependently) That should be reasonably unusual, so just don't do that.
- Combined data stack
-
Parrot uses a single stack to hold integers, floats, strings, PMCs, execution tokens, and whatnot. Each element takes a single cell on the stack.
- Full PMC usage
-
All values on the Forth stack are, in fact, PMCs rather than plain integers, floats, or whatever. All integers are stored in Integer PMCs, floats in Float PMCs, and parrot strings in PerlString PMCs.
This has a number of unfortunate efficiency issues, but it makes the implementation much easier.
This also means that Parrot Forth will do autocoercion on data elements. The following:
1.2 1.6 + .
will print
2
, since+
is defined as integer addition. Note that this will not invoke the addition vtable methods on the two operands, but instead invokes the get_integer method for them. To use the vtable methods use the p variants of the operands. (p+
,p-
and their friends) - No doublewords
-
Parrot integers are 32 bits. The words that act on doubles behave identically to their single-word variants.
- No single/double float distinction
-
All floats are whatever Parrot was compiled with originally, generally 64-bit doubleword floats. All float words that act on single or double words will act identically.
- Unsignedness is ignored
-
Generally all math operations act on integers as if they were signed, and the engine acts accordingly. Unsigned variants of words act identically to their signed counterparts, including returning signed values where they might occur.
- Fake memory store
-
Parrot forth doesn't provide direct access to actual RAM. Memory access is instead simuated with an array, with each cell in the array holding a single value.
The array is initially set to hold 64K cells. Each cell may hold a single value (PMC, integer, float, Parrot String) so this is generally sufficient.
- Extended Constants
-
The
constant
word associates the following word with the value on the stack, regardless of its type.constant
s, then, can be integers, Parrot strings, floats, or PMCs provided by external code. - Forth Strings
-
The forth standard only mandates that strings, as used in counted string things, can hold up to 255 characters.
Words that differ from ANS forth
Extra Parrot words
The following conventions are in effect
v
is a stack value
n
is a number
s
is a parrot string
- p"
-
This word puts a parrot string on the stack. Parrot strings take up a single stack cell.
- ireg (v n -- )
-
Puts the integer value of V into the register indicated by N.
Note that since this allows direct manipulation of Parrot's registers it can be dangerous to forth at runtime, as forth makes use of parrot's registers as it runs. Generally it's wise to stay in the range 0-15, which are the registers used in parrot's calling conventions.
- preg (v n -- )
-
Puts the PMC V into the register indicated by N.
Note that since this allows direct manipulation of Parrot's registers it can be dangerous to forth at runtime, as forth makes use of parrot's registers as it runs. Generally it's wise to stay in the range 0-15, which are the registers used in parrot's calling conventions.
- nreg (v n -- )
-
Puts the float value of V into the register indicated by N.
Note that since this allows direct manipulation of Parrot's registers it can be dangerous to forth at runtime, as forth makes use of parrot's registers as it runs. Generally it's wise to stay in the range 0-15, which are the registers used in parrot's calling conventions.
- sreg (v n -- )
-
Puts the string value of V into the register indicated by N.
Note that since this allows direct manipulation of Parrot's registers it can be dangerous to forth at runtime, as forth makes use of parrot's registers as it runs. Generally it's wise to stay in the range 0-15, which are the registers used in parrot's calling conventions.
- invoke ( -- )
-
Call a Parrot sub. Registers had better be in the correct setup, or things are likely to die a horrible death.
- findglobal ( s -- p )
-
Takes the parrot string S and looks it up in the global table, putting the corresponding PMC for the symbol on the top of the stack.
- loadpasm ( s -- )
-
Load and run the assembly file S. Useful for loading in libraries of subroutines or interfaces.
- loadpir ( s -- )
-
Load and run the PIR file S. Useful for loading in libraries of subroutines or interfaces.
- resultP ( -- v )
-
Take the value in register P5 and put it on the top of the stack
- resultI ( -- v )
-
Take the value in register I5 and put it on the top of the stack
- resultS ( -- v )
-
Take the value in register S5 and put it on the top of the stack
- resultN ( -- v )
-
Take the value in register N5 and put it on the top of the stack
- s2p ( c-addr u -- s )
-
Take the cell address and count off the stack and construct a Parrot ASCII string from it, putting that string on the stack
- p2s ( s -- c-addr u )
-
Take the parrot string off the stack and turn it into a Forth counted string, putting the cell address of the resulting data and the length on the stack.
- substr (s n1 n2 -- s )
-
Extract a substring from parrot string S, from offset N1 for N2 characters, and put the resulting parrot string back on the stack.
- concat (s s -- s )
-
Concatenate the two strings on top of the stack and create a new string, putting the new string on the stack.
- getparams ( -- v*x n v*x n v*x n v*x n )
-
Unpack the parameters, as passed in via parrot's calling conventions, from registers to the Forth stack. The results will be the parameters topped by a count for each set of parameter types. The registers will be taken in numeric, string, integer, and PMC order. (So the top word on the stack is the number of PMC parameters passed)
- decode-by-sig ( s -- v*x n )
-
Take the signature S, a parrot string with the function signature, and pull the parameters out of the registers based on that signature, properly handling the potential for the parameters to come in without prototyping. The top word on the stack is the parameter count.
- export ( xt s -- )
-
Export execution token XT as name S, in the global parrot namespace. S should be a parrot string, and fully qualified. This word will be called with registers set as per Parrot's calling conventions, so should decode the registers as need be to get its parameters in a Forth-like state.
CREDITS
Original Implementation: Jeff Goff
Vicious and Brutal extending: Dan Sugalski