]> thyrsus.com Git - intercal.git/commitdiff
Documentation for IFFI, and fixing IFFI to match that documentation
authorAlex Smith <ais523@bham.ac.uk>
Mon, 7 Jul 2008 03:19:57 +0000 (23:19 -0400)
committerEric S. Raymond <esr@thyrsus.com>
Thu, 26 Aug 2010 00:35:11 +0000 (20:35 -0400)
NEWS.txt
doc/ick.txi
etc/IFFI/IFFI.c

index 940c280aa6facdcfdf6cd2739ea50e67521999e5..65051fdbddd71d20907cbb2de2d94ba4d2a502af 100644 (file)
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -132,6 +132,12 @@ Changes by Alex Smith
     a COME FROM in more than one file at a time whilst still having the
     resulting program work reliably.
 
+24. Added support for external calls to Befunge-98 programs; however, this
+    distribution does not ship with a Funge-98 interpreter, so in order to use
+    this feature you will first have to compile a Funge-98 interpreter into a
+    library for use with C-INTERCAL (see README.txt or the Revamped Manual for
+    information on this). Also added a test program for this to the pit.
+
   Release 0.28 (by Alex Smith) 1 Apr 2008
 
 Patches, suggestions and bugs found by Joris Huizer
index dfd9a92cdaa7193d830aa6c9583b81204407e121..8db4bb647d82ed69ffbb4aeb764882dd52cbb717 100644 (file)
@@ -4890,11 +4890,11 @@ before the INTERCAL program starts running.  To do so, it can use the
 @code{ICK_EC_FUNC_START}; the syntax is @code{ick_startup(block)},
 where the argument is an expression, statement, or compound statement
 to run.  The argument itself must not contain any ick_-prefixed macros
-or functions, may have side effects, and must fit the C preprocessor's
-idea of what a macro argument should look like (it's more used to
-parsing expressions than blocks; the general rule is to avoid commas
-except when they're directly or indirectly inside parentheses or
-strings).
+or functions except possibly ick_create, may have side effects, and
+must fit the C preprocessor's idea of what a macro argument should
+look like (it's more used to parsing expressions than blocks; the
+general rule is to avoid commas except when they're directly or
+indirectly inside parentheses or strings).
 
 @node ick_linelabel
 @subsection ick_linelabel
@@ -5166,6 +5166,8 @@ which any two variable names or expressions are separated by at least
 one capital letter.  The compiler will produce a `signature' for the
 unknown command that can be defined.
 
+@cindex signatures
+@cindex CREATE, signatures
 A signature consists of a sequence of characters (and is represented
 as a null-terminated string; the runtime makes a shallow copy of the
 string and keeps it until the end of the program, so arrangements must
@@ -5346,6 +5348,8 @@ flow operations.
 @cindex Funge
 @cindex Befunge
 
+@portability{no, version 0.29+, no, no}
+
 @cic{} supports linking @ical{} programs with Funge-98 programs (to be
 precise, only Befunge-98 programs are currently supported).  However,
 it does not ship with a Funge-98 interpreter, and such an interpreter
@@ -5374,6 +5378,7 @@ interpreter.
 
 @menu
 * Creating the Funge-98 Library:: How to create the Funge-98 library.
+* The IFFI Fingerprint::          External calls from Funge's view.
 @end menu
 
 @node Creating the Funge-98 Library
@@ -5428,12 +5433,246 @@ versions of the sources that you downloaded (and errors definitely
 indicate such problems).
 
 Once the library has been created, it will appear as the new file
-@file{lib/libick_ecto_b98} in the @cic{} distribution (the cfunge
+@file{lib/libick_ecto_b98.a} in the @cic{} distribution (the cfunge
 distribution will be left unchanged); reinstalling @cic{} will install
 this file to its proper location.  (It is also in a valid location to
 be able to be run if you aren't installing @cic{} but instead just
 running it from the distribution's directory.)
 
+@node The IFFI Fingerprint
+@subsection The IFFI Fingerprint
+@cindex IFFI
+@cindex fingerprint
+@cindex external calls, from Funge's view
+@cindex Funge, fingerprint
+@cindex Befunge, fingerprint
+
+@i{This section will not make much sense to a non-Funge programmer;
+therefore, if you are not used to Funge, you probably want to skip it.}
+
+To a Funge program, the external calls interface is accessed via a
+Funge-98 'fingerprint' defined by the interpreter.  The name of the
+fingerprint is 0x49464649, or as text, @samp{IFFI}.
+
+When a program formed by linking @ical{} and Befunge-98 is run, the
+first thing that happens is some internal @ical{} initialisation which
+is not visible to either program, and then initialisation routines
+specified in the Befunge-98 program run (if an initialisation routine
+is also specified in a linked C program using ick_startup, it is
+unspecified whether the C or Befunge-98 initialisation happens first.)
+In the Befunge program, the initialisation routine consists of
+everything that happens until the @samp{Y} command in the @samp{IFFI}
+fingerprint is run; the author of the Funge-98 must load the
+@samp{IFFI} fingerprint themselves during this initialisation to
+access that command.  (This is so that the Befunge program ends up
+complying with the Funge-98 standard; commands not defined in that
+standard cannot be used until a fingerprint is loaded.)  During
+initialisation, no commands from the @samp{IFFI} fingerprint may be
+used except @samp{Y} and @samp{A}.  (If a different command is used,
+@samp{C}, @samp{M}, and @samp{X} remove the arguments they would use
+from the stack (if any) but otherwise do nothing, and the other
+commands in the @samp{IFFI} fingerprint reflect.)
+
+After the @samp{Y} command is called, the @ical{} program starts
+running; in order for the Befunge program to regain control, it has to
+be @code{NEXT}ed to from the @ical{} program, or @code{COME} or
+@code{NEXT FROM} the @ical{} program, or contain the line label to
+which syntax in the @ical{} program was @code{CREATE}d.  (In other
+words, the normal @ical{} ways of transferring information between
+parts of a program.)  In order to do this, therefore, line labels and
+@ical{} control flow statements must be placed into the Befunge
+program.
+
+@cindex marker
+@cindex Funge, marker
+@cindex Befunge, marker
+Code like @code{COME FROM (100)} is a single statement in @ical{}, but
+several statements in Funge-98; therefore, some method of telling the
+interpreter where to start executing to look for @code{COME FROM}s,
+@code{NEXT FROM}s, and line labels is needed.  The method used by
+@cic{} is that of the 'marker'; a marker is represented by character
+0xB7 (a mid-dot in Latin-1) in the input Funge-98 program, but is
+transformed to a capital @samp{M} by @command{ick}.  (The reason for
+using a special character for a marker and transforming it rather than
+just using @samp{M} is to prevent occurences of @samp{M} in comments
+and string literals, etc.@:, having an effect on the control flow of
+the program.)  Whenever a @code{NEXT} or line label is encountered (in
+the @ical{} program, the Funge program or elsewhere), the Funge
+program is executed starting from each marker in each cardinal
+direction to look for line labels or @code{COME}/@code{NEXT FROM}s
+respectively.  Therefore, @code{COME FROM (100)} is written in
+Funge-98 as @code{Maa*C} (where the M is a marker in the source code),
+and likewise the line label @code{(100)} would be written as
+@code{Maa*L}.  (This code can be written in any cardinal direction,
+that is left to right, top to bottom, right to left, or bottom to top,
+but not diagonally or flying.)  There are likely to be unused
+directions from markers, which will be evaluated too; you can (and
+must) close these off by reflecting code execution back into that
+marker, another marker, or a non-marker @code{M}.  Note also that a
+marker remains in Funge-space even if the @code{M} on the same square
+is deleted (the marker itself is not visible to the @code{g} command,
+though).
+
+Here are the commands in the @samp{IFFI} fingerprint:
+@cindex IFFI, commands
+@table @code
+@item A
+@cindex CREATE, in Funge
+This command pops a line number and then an 0"gnirts"-format string
+from the stack; they are used as the line number and signature to
+@code{CREATE} syntax in the @ical{} program; for details of the format
+of the signature, see @ref{ick_create}.  Although using this command
+during speculative execution works, doing so is not recommended; if
+the target line number for @code{CREATE}d syntax is changed during
+speculative execution to find the line that that syntax corresponds
+to, its effect is delayed until after the original line is found and
+execution continues from that point.  (Side effects during speculative
+execution are never recommended, because they might or might not be
+optimised away.)
+@item C
+@cindex COME FROM, in Funge
+During speculative execution to find @code{COME FROM}s and @code{NEXT
+FROM}s, pops a line label off the top of the stack and does a
+@code{COME FROM} that location.  During speculative excution to find
+line labels, pops the top of the stack and ends that particular
+speculative execution as a failure.  When not doing speculative
+execution, pops and discards the top element of the stack.
+@item D
+This command must only be used when the Funge program is executing a
+@code{CREATE}d command, and allows access to the arguments that
+command has.  It pops an integer off the top of the stack, and treats
+it as an argument position (0-based, so 0 refers to the first
+argument, 1 refers to the second, and so on).  Note that providing an
+invalid argument number, or running this command when not implementing
+a @code{CREATE}d command, leads to undefined behaviour (possibly a
+reflection, possibly a segfault, possibly worse).
+
+The command pushes information about the argument chosen onto the
+stack; the following information is pushed from bottom to top:
+@itemize
+@item
+The data type of the argument, in bits (16 if the argument was a
+onespot variable or expression of onespot type, and 32 if the argument
+was a twospot variable or expression of twospot type).  Note that this
+is under the @cic{} typing rules, rather than the @icst{} typing rules
+(that is, select's type is always that of its right argument no matter
+how many bits are actually selected).
+@item
+1 if the argument is an array variable, 0 if it is a scalar value.
+@item
+0 if the argument is not a variable, or the variable's number if it is
+(e.g.@: @code{.123} would push 123 here, but @code{.1~.2} would push
+0).
+@item
+The argument's value at the time that the @code{CREATE}d instruction
+was called.
+@item
+The argument's value now, or alternatively a repeat of the previous
+stack element if @option{-a} (@pxref{-a}) was not used.  (Without
+@option{-a}, the information needed to re-evaluate the expression is
+not available.)
+@end itemize
+@item F
+@cindex FORGET, in Funge
+During speculative execution, this command reflects; otherwise, this
+command pops an integer from the top of stack, and @code{FORGET}s that
+many @code{NEXT} stack entries (or all of them if the argument given
+is negative).
+@item G
+@cindex variables, Funge, accessing
+This command pops an integer from the top of stack.  If it is
+positive, the value of the onespot variable whose name is the popped
+integer is pushed onto the stack; if it is negative, the value of the
+twospot variable whose name is minus the popped integer is pushed onto
+the stack; and if it is zero, the command reflects.  If the referenced
+variable is not in the @ical{} program at all, this causes an @ical{}
+error due to referencing a nonexistent variable.
+@item L
+@cindex line label, in Funge
+During speculative execution to find @code{COME FROM}s and @code{NEXT
+FROM}s, this command pops and discards the top stack element, then
+ends that speculative execution.  During speculative execution to find
+a line label, this command pops an integer from the top of stack and
+succeeds with that integer as the line label (that is, it is possible
+to @code{NEXT} to an @code{L} in the Funge program if a marker,
+followed by code to push the correct line number onto the stack,
+precedes that @code{L}).  When not doing speculative execution, the
+integer on the top of the stack is used as a line label (assuming it
+is in the range 1--65535, otherwise it is popped and discarded), and
+a search is made for @code{COME FROM}s and @code{NEXT FROM}s aiming
+for that line label (including in the @ical{} program and the Befunge
+program itself, as well as programs in any other language which may be
+linked in).  Note that just as in @ical{}, it is possible to
+@code{NEXT} to a line label which has a @code{COME FROM} aiming for
+it, in which case the @code{COME FROM} will come from that line label
+as soon as the @code{NEXT} transfers control to it.
+@item M
+Does nothing if not in speculative execution, or ends the current
+speculative execution with failure.  (This is so that code like
+@example
+ v
+>M5C
+ ^
+@end example
+does exactly the same thing as @code{COME FROM (5)}, even when, for
+instance, it is entered from the left in the Funge program, rather
+than gaining control from the line label @code{(5)}.)
+@item N
+@cindex NEXT, in Funge
+During speculative execution, reflects.  Otherwise, pops the top stack
+element, interprets it as a line label, and @code{NEXT}s to that line
+label (this may start speculative execution to look for line labels,
+but might not if it isn't needed, for instance if the line label in
+question is in the @ical{} program or in a C program linked to the
+Befunge program).
+@item R
+@cindex RESUME, in Funge
+During speculative execution, reflects.  Otherwise, pops the top stack
+element, removes that many items from the @code{NEXT} stack, and
+@code{RESUME}s at the last item removed.  (If the top stack element
+was zero, negative, or too large, this will cause a fatal error in the
+@ical{} program.)
+@item S
+@cindex variables, Funge, setting
+Pops a variable number (interpreted as onespot if positive, or minus
+the number of a twospot variable if negative) and an integer from the
+stack, and sets the referenced variable to the integer.  This reflects
+if an attempt is made to set the nonexistent variable 0, causes a
+fatal error in the @ical{} program if an attempt is made to set a
+variable that doesn't exist there, and does not set read-only
+variables (but pops the stack anyway).  If the integer is too high for
+the variable it is being stored in, only the least significant 16 or
+32 bits from it will be used; and likewise, if it is negative, it will
+be treated as the two's complement of the number given.
+@item V
+Pops a @code{CREATE}d argument index and an integer from the top of
+stack.  (This is undefined behaviour if not in the implementation of a
+@code{CREATE}d statement, or if the referenced argument does not
+exist; as with the @code{D} instruction, 0 refers to the first
+argument, 1 to the second, and so on.)  If the @option{-a} option is
+not used, this command does nothing; otherwise, the value of the
+argument will be set to the integer.  (This involves doing a reverse
+assignment if the argument is a non-variable expression, as usual, and
+causes a fatal error in the @ical{} program if the reverse assignment
+is impossible or an attempt is made to assign a scalar to an array.)
+@item X
+@cindex NEXT FROM, in Funge
+This is identical to @code{C}, except that it does a @code{NEXT FROM}
+rather than a @code{COME FROM}.
+@end table
+
+As with external calls to C, terminating any program involved (whether
+the @ical{} program with @code{GIVE UP}, the Befunge program with
+@code{@@} or @code{q}, or a C program with @code{exit()}) causes all
+programs involved to terminate, and likewise a fatal error will end
+all programs with an error.
+
+One final point which is probably worth mentioning is that flow
+control instructions only record the IP's position and direction,
+nothing else; so for instance, if the stack is modified in one part of
+the code, those modifications will remain even after a @code{RESUME},
+for instance.
+
 @node Miscellaneous External Calls
 @section Miscellaneous External Calls
 @cindex external calls, miscellaneous
index 8c74ce942e9b0ef52bd757eecb0b3fdcb3a760c2..d1e6243827ad2f951e89dc50983982cbd057ae1a 100644 (file)
@@ -27,6 +27,8 @@
 
 static instructionPointer *iffiIP = NULL;
 
+static bool firstload = true;
+
 // Communication functions with the ecto_b98 expansion library
 void ick_SaveIPPosDelta(struct ick_ipposdeltatype* ippd)
 {
@@ -128,6 +130,11 @@ static void FingerIFFIcreateData(instructionPointer * ip)
        // The argument's value now (same as previous if -a was not used)
        FUNGEDATATYPE i;
 
+       if (firstload) {
+               ipReverse(ip);
+               return;
+       }
+
        i = StackPop(ip->stack);
 
        StackPush(ip->stack, ick_c_i_width(i));
@@ -142,6 +149,11 @@ static void FingerIFFIforget(instructionPointer * ip)
 {
        FUNGEDATATYPE f;
 
+       if (firstload) {
+               ipReverse(ip);
+               return;
+       }
+
        if (ick_iffi_inmarkmode) { /* this is an error in the user's code */
                ipReverse(ip);
                return;
@@ -163,6 +175,11 @@ static void FingerIFFIvarGet(instructionPointer * ip)
 
        FUNGEDATATYPE v;
 
+       if (firstload) {
+               ipReverse(ip);
+               return;
+       }
+
        v = StackPop(ip->stack);
 
        if (v == 0) {
@@ -179,6 +196,11 @@ static void FingerIFFIlabel(instructionPointer * ip)
 {
        FUNGEDATATYPE l;
 
+       if (firstload) {
+               ipReverse(ip);
+               return;
+       }
+
        l = StackPop(ip->stack);
 
        ick_iffi_breakloop = 1;
@@ -198,6 +220,11 @@ static void FingerIFFInext(instructionPointer * ip)
 {
        FUNGEDATATYPE l;
 
+       if (firstload) {
+               ipReverse(ip);
+               return;
+       }
+
        if (ick_iffi_inmarkmode) { /* this is an error in the user's code */
                ipReverse(ip);
                return;
@@ -215,6 +242,11 @@ static void FingerIFFIresume(instructionPointer * ip)
 {
        FUNGEDATATYPE f;
 
+       if (firstload) {
+               ipReverse(ip);
+               return;
+       }
+
        if (ick_iffi_inmarkmode) { /* this is an error in the user's code */
                ipReverse(ip);
                return;
@@ -240,6 +272,11 @@ static void FingerIFFIvarSet(instructionPointer * ip)
 
        FUNGEDATATYPE v, d;
 
+       if (firstload) {
+               ipReverse(ip);
+               return;
+       }
+
        v = StackPop(ip->stack);
        d = StackPop(ip->stack);
 
@@ -259,6 +296,11 @@ static void FingerIFFIargSet(instructionPointer * ip)
        // note that this is a NOP unless -a was used when compiling
        FUNGEDATATYPE i, d;
 
+       if (firstload) {
+               ipReverse(ip);
+               return;
+       }
+
        i = StackPop(ip->stack);
        d = StackPop(ip->stack);
 
@@ -282,7 +324,6 @@ static void FingerIFFInextFrom(instructionPointer * ip)
 // Y - Marks the end of initialisation
 static void FingerIFFIyield(instructionPointer * ip)
 {
-       static bool firstload = true;
        ick_iffi_breakloop = firstload;
        if (! firstload)
                ipReverse(ip);