Dynamic fingerprint spec V 1.2  Jeffrey Lee, 24/7/03
------------------------------

This system is based around the mini-funge fingerprint systems used by 
Paul Mahon's PJSF interpreter at <a 
href="http://dufflebank.iwarp.com/JSFunge/">http://dufflebank.iwarp.com/JSFunge/</a>, 
Mike Riley's RC/Funge-98, and Zinx Verituse's zfunge. With a few 
alterations, fingerprints written for their systems should be useable with 
the one described here. Note that the PJSF specification for pick (K) and 
roll (O) are the wrong way round; pick should duplicate the item, while 
roll should move it.

Dynamic fingerprint files are essentially the same as normal funge code 
files. However only Befunge (i.e. 2 dimensions) are allowed. When the 
fingerprint is first used by a program, the entire file will be loaded 
into a fungespace seperate from the program which is using it. This copy 
of the file will persist until execution of the program is complete, 
allowing variables to be stored in fingerprint fungespace. Apart from 
trefunge and concurrency instructions, every Funge-98 instruction 
supported by your interpreter should be supported by its dynamic 
fingerprint system, and those instructions should affect the fingerprint 
fungespace as opposed to the callee's fungespace. Note that the dynamic 
fingerprint may inherit some of the constraints of the callee's 
environment, such as limited fungespace/stack size or lack of file access 
commands. The y instruction should be used to query these if needed. 
Dynamic fingerprint files can be given two names: Either the ASCII version 
of the fingerprint they represent (e.g. 'NULL') or the hex version (e.g. 
'0x4e554c4c'). Your interpreter should provide a central place to store 
these files so they can be searched for and loaded as necessary. File type 
extensions can be used if your OS supports them (e.g. '.df'), as well as 
removing the '0x' prefix if only 8 character file names are available. 
Compatability with minifunge funge-lib files could also be provided, 
allowing the two formats to be used side-by-side. Information about this 
should be provided in your interpreters documentation.

In a dynamic fingerprint file, a line of the form '=X' marks the start of 
a semantic definition. The fingerprint IP will be started on the following 
line, heading east. E.g.:

=S
>:#,_$@

would define S to output a string.

When the program executes a fingerprint instruction, a new IP is created 
inside the corresponding fingerprint space, at the corresponding location. 
The IP will have a storage offset of (0,0). The callee's stackstack will 
be transplanted to act as the fingerprint IP's stackstack; when the 
fingeprint IP dies, the stackstack will be transferred back to the callee 
(known as the 'haunted' IP), and so interaction with the haunted IP's 
stack is possible.

The fingerprint IP will have a special, invisible fingerprint loaded, 
which is impossible to remove (but can be overloaded as normal). This 
fingerprint should have no name, and so is impossible to load or remove 
any other way apart from creating a fingerprint IP. This invisible 
fingerprint defines the following semantics:

B       Haunted Back            Move haunted IP back one step
D       Haunted Delta           Pull a vector off the stack and assign the
                                haunted IP's delta to it
E       Haunted Stacksize       Push the size of the TOSS
F       Haunted Forward         Move haunted IP forwards one step
G       Haunted Get             Works the same as g, but it reads from the
                                callee's fungespace (using their storage
                                offset) instead of the fingerprint 
fungespace.
K       Stack pick              Pop a number 'n', and copy the nth element 
of
                                the stack to the top. Offsets are relative 
to
                                the top of stack after n has been popped. 
If n
                                points outside the stack, a zero will be 
pushed.
                                Reflects if n<0
L       Haunted Location        Pop a vector v and set the haunted IP's 
location
                                to it, such that when the fingerprint 
exits the
                                IP will execute the instruction at v. This 
means
                                that the location will actually be set to
                                v - delta.
M       Haunted IP modes        Pushes a scalar onto the stack, containing
                                details of the processor modes the haunted 
IP
                                is in:
                                        0x01    Stringmode
                                        0x02    Hovermode  ( Parts of the
                                        0x04    Invertmode    0x4d4f4445
                                        0x08    Queuemode        MODE
                                        0x10    Switchmode   fingerprint  
)
                                Note that when a fingerprint IP is 
created, it
                                does not inherit any of the parent IPs 
modes.
O       Stack roll              Pop a number 'n', and move the nth element 
of
                                the stack to the top. If n points outside 
the
                                stack, a zero will be pushed and no 
shuffling
                                will occur. Offsets are relative to the 
top of
                                stack after n has been popped. Reflects if 
n<0.
                                If your interpreter supports the 
0x4d4f4445 MODE
                                fingerprint, the operation should be as 
follows:
                                1. Temporarily set the invertmode flag to 
the
                                   same value as the queuemode flag
                                2. Pick the value out of the stack and 
shuffle
                                   the displaced items down
                                3. Restore the invertmode flag
                                4. Push the rolled item onto the stack
                                I.e. n54321Q1K,,,,, should output 53214
P       Haunted Put             Works the same as p, but it writes to the
                                callee's fungespace (using their offset)
                                instead of the fingerprint fungespace.
R       Haunted reflect         Reflects the delta of the haunted IP
S       Haunted storage offset  Pop a vector off the stack and assign the
                                haunted IP's storage offset to it
Y       Haunted Y               Acts the same as y, but information is 
returned
                                about the callee's fungspace (and the 
currently
                                haunted IP). Consequently, the stackstack 
will
                                be temporarily transferred back for this. 
The
                                data will be placed on the stack according 
to
                                the fingerprint IP's invertmode and 
queuemode
                                status.

Note that D, G, L, P and S will all pop vectors with a size corresponding 
to the callee's fungespace, not the fingerprints fungespace.


The only two normal instructions with modified meanings are:

@       Exit fingerprint        Causes the stackstack to be transferred 
back to
                                the haunted IP, and the fingerprint IP to 
be
                                killed. Execution of the haunted IP will 
then
                                resume as normal.
y       Kill haunted            Causes the haunted IP (and its ghost) to 
be
                                killed.


As well as the A-Z semantic instructions, you can also define code for the 
following:

=t      IP split notification   Called whenever an IP successfully 
executes a
                                't'. The haunted IP will be the new IP 
(i.e. the
                                reversed one), and the ID of the source IP 
will
                                have been pushed on the stack. This allows 
you
                                to duplicate any IP specific data the
                                fingerprint might hold. The IP id must be
                                removed from the stack on exit, otherwise 
it
                                will be left in place and confuse the 
callee.
=@      IP death notification   The haunted IP will be an IP which is 
about to
                                die (e.g. by executing '@'). This allows 
you to
                                delete any IP specific data the 
fingerprint
                                might hold.

Note that in some implementations =@ may not be called if q is executed. 
Using fingerprint-q will cause =@ to be executed.


Depending on the implementation, dynamic fingerprints may or may not 
execute in one tick of the callee's time. This may also affect executing a 
dynamic fingerprint by k.


Concurrency is disabled in dynamic fingnerprints because determining which 
IP should get haunting rights requires several expensive law suits.


Dynamic fingerprints which add instructions to themselves or modify their 
entry points are possible, but not officially supported due to the stress 
they place on the fingerprint system (e.g. loading a dynamic fingerprint, 
triggering it to add a new instruction, then unloading it may result in 
removal of an instruction which didn't exist when the fingerprint was 
loaded. Add to this concurrency and an IP may end up destroying 
instructions which it didn't mean to). Because of this, avoid writing any 
'='s to the 1st column of fungespace.


Nesting of dynamic fingerprints should be possible. Each sub fingerprint 
will have its fungespace reloaded from disc, in order to keep it from 
seeing the data stored in the parent version of itself.

Changelog
---------

V1.2

* Finally tracked down copies of RC/Funge-98 and zfunge. It seems they 
both use fingerprint systems similar to PJSF, meaning that this new one is 
going against the grain a bit. Doh.
* Swapped K and O so they are the right way round. I blame the PJSF specs.
* Added R, taken from RC/Funge-98's Mini-Funge specification