From: Alex Smith Date: Mon, 7 Jul 2008 03:19:57 +0000 (-0400) Subject: Documentation for IFFI, and fixing IFFI to match that documentation X-Git-Tag: 0.29~202 X-Git-Url: http://thyrsus.com/gitweb/?a=commitdiff_plain;h=0afa3567c59f8dc65ad31b6bb889f3f23e7d8a5c;p=intercal.git Documentation for IFFI, and fixing IFFI to match that documentation --- diff --git a/NEWS.txt b/NEWS.txt index 940c280..65051fd 100644 --- 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 diff --git a/doc/ick.txi b/doc/ick.txi index dfd9a92..8db4bb6 100644 --- a/doc/ick.txi +++ b/doc/ick.txi @@ -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 diff --git a/etc/IFFI/IFFI.c b/etc/IFFI/IFFI.c index 8c74ce9..d1e6243 100644 --- a/etc/IFFI/IFFI.c +++ b/etc/IFFI/IFFI.c @@ -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);