]> thyrsus.com Git - intercal.git/commitdiff
External calls to Funge-98, part 1
authorAlex Smith <ais523@bham.ac.uk>
Sun, 6 Jul 2008 04:24:11 +0000 (00:24 -0400)
committerEric S. Raymond <esr@thyrsus.com>
Thu, 26 Aug 2010 00:35:07 +0000 (20:35 -0400)
MANIFEST.txt
Makefile.in
README.txt
etc/IFFI.spec [new file with mode: 0644]
etc/IFFI/IFFI.c [new file with mode: 0644]
etc/IFFI/IFFI.h [new file with mode: 0644]
etc/cftoec.sh [new file with mode: 0644]
etc/cfunge.patch [new file with mode: 0644]
pit/CATALOG
pit/explib/ecto_b98.c [new file with mode: 0644]
src/perpet.c

index d6203d8cea989dbd58dbca71caa8203a23a19f5a..0deddd0e264fd8f33b770982574378913347f288 100644 (file)
 ./doc/ick.info-1
 ./doc/ick.info-2
 ./doc/ick.txt
+./etc/cfunge.patch
+./etc/cftoec.sh
+./etc/IFFI.spec
+./etc/IFFI/IFFI.h
+./etc/IFFI/IFFI.c
 ./etc/ctrlmfix.bat
 ./etc/ctrlmfix.sh
 ./etc/intercal.el
+./pit/explib/ecto_b98.c
 ./pit/explib/syslibc.doc
 ./pit/explib/compunex.c
 ./pit/explib/syslibc.c
 ./pit/unlambda.i
 ./pit/yapp.doc
 ./pit/yapp.i
-./src/autoscan.log
 ./src/abcess.h
 ./src/arrgghh.c
 ./src/atari.bin
index 0ce5862061346105fe577f32569e25dfbcbe4fce..b1e8fe43ee1a2a3cf8a684550034c025440ddc3c 100644 (file)
@@ -55,7 +55,7 @@ SOURCES = $(CSOURCES) $(ISOURCES) $(YSOURCES) $(HEADERS) $(BUILD) $(MISC) $(DOCS
 
 all: bin/ick@EXEEXT@ bin/convickt@EXEEXT@ lib/libick.a lib/libickmt.a lib/libyuk.a lib/libickec.a ial
 
-ial: include/ick_ec.h include/fiddle.h include/abcess.h include/ick_lose.h include/yuk.h include/syslib.i include/syslib.3i include/syslib.4i include/syslib.5i include/syslib.6i include/syslib.7i lib/ick-wrap.c lib/pickwrap.c lib/coopt.sh lib/COPYING.txt lib/syslibc.c lib/compunex.c include/atari.bin include/baudot.bin include/ebcdic.bin include/latin1.bin
+ial: include/ick_ec.h include/fiddle.h include/abcess.h include/ick_lose.h include/yuk.h include/syslib.i include/syslib.3i include/syslib.4i include/syslib.5i include/syslib.6i include/syslib.7i lib/ick-wrap.c lib/pickwrap.c lib/coopt.sh lib/COPYING.txt lib/syslibc.c lib/compunex.c lib/ecto_b98.c include/atari.bin include/baudot.bin include/ebcdic.bin include/latin1.bin
 
 include/ick_ec.h: src/ick_ec.h
        -cp src/ick_ec.h include/ick_ec.h
@@ -97,6 +97,8 @@ lib/syslibc.c:pit/explib/syslibc.c
        -cp pit/explib/syslibc.c lib/syslibc.c
 lib/compunex.c:pit/explib/compunex.c
        -cp pit/explib/compunex.c lib/compunex.c
+lib/ecto_b98.c:pit/explib/ecto_b98.c
+       -cp pit/explib/ecto_b98.c lib/ecto_b98.c
 
 include/atari.bin:src/atari.bin
        -cp src/atari.bin include/atari.bin
@@ -217,6 +219,7 @@ install-common: all
        cp lib/libickmt.a $(DESTDIR)$(libdir)
        cp lib/libickec.a $(DESTDIR)$(libdir)
        cp lib/libyuk.a $(DESTDIR)$(libdir)
+       sh -c 'cp lib/libick_ecto_b98.a $(DESTDIR)$(libdir) || true'
        -mkdir -p $(DESTDIR)$(incdir)
        cp src/ick_lose.h src/abcess.h src/fiddle.h src/yuk.h $(DESTDIR)$(incdir)
        cp src/ick_ec.h $(DESTDIR)$(incdir)
@@ -267,6 +270,7 @@ uninstall:
        rm -f $(DESTDIR)$(bindir)/ick@EXEEXT@ $(DESTDIR)$(libdir)/libick.a
        rm -f $(DESTDIR)$(bindir)/convickt@EXEEXT@
        rm -f $(DESTDIR)$(libdir)/libickmt.a $(DESTDIR)$(libdir)/libyuk.a
+       rm -f $(DESTDIR)$(libdir)/libickec.a $(DESTDIR)$(libdir)/libick_ecto_*.a
        rm -f ${DESTDIR}${infodir}/ick.i*
        rm -f $(DESTDIR)$(mandir)/man1/ick.1*
        rm -f $(DESTDIR)$(mandir)/man1/convickt.1*
index 30607dfaa624ed4a8d07b0621fef3049dd26c5d1..9515e62bf8ff9dfcf6664cdac2d9b2ad794f5b03 100644 (file)
@@ -90,6 +90,11 @@ districk.sh             --|the same as above, but in sh format
 cleanick.sh             --|(use .bat under command.com/cmd, and .sh under bash)
 etc/ctrlmfix.sh         --/
 
+etc/cftoec.sh          -- script to convert cfunge to a library (see below)
+etc/IFFI*               -- input to that script
+etc/cfunge.patch        -- more input to that script
+etc/temp                -- temporary directory used by that script
+
 config.sh               -- GNU Autoconf script that generates a makefile
                            from Makefile.in
 ickspec.in              -- Input to config.sh
@@ -102,6 +107,8 @@ include/*               -- Directory that holds header files after the build
 lib/*                   -- Directory that holds library files after the build
 
 pit/*                   -- sample INTERCAL code; see pit/CATALOG
+pit/explib/*            -- source code for expansion libraries
+pit/lib/syslib.*i       -- source code for the system libraries
 
                               HOW TO GET STARTED
 
@@ -291,6 +298,30 @@ your compiler can find them, and pick1.h will need to be modified to contain
 compiler-specific data (like the names of data types and the syntax for
 specifying the device type, fuses, and various commands).
 
+           NOTES ON THE C-INTERCAL / CFUNGE EXTERNAL CALLS SYSTEM
+
+Code is provided to allow linking of Funge-98 programs to INTERCAL programs;
+however, this requires a Funge-98 interpreter, which is not present in this
+distribution. Therefore, in order to do this, a Funge-98 interpreter must
+first be downloaded and prepared for use with C-INTERCAL. At present, code is
+only available for linking with 'cfunge', a Funge-98 interpreter written in
+C. You can get the latest sources for that interpreter from the Internet via
+the bzr version-control system by running this command:
+
+bzr branch http://rage.kuonet.org/~anmaster/bzr/cfunge
+
+Once you have the source code to cfunge, you can compile it into a library
+suitable for use by C-INTERCAL by changing to the /etc directory of the
+C-INTERCAL distribution, and running the cftoec.sh shell script in that
+directory with the path to the cfunge distribution as an argument. The script
+will make a copy of cfunge, modify it as required, and then place the
+resulting library (libick_ecto_b98.a) in the /lib directory of the C-INTERCAL
+distribution; installing (or reinstalling) C-INTERCAL after that will copy
+that library into the correct location in your filesystem.
+
+For information on actually using this system once you've set it up, consult
+the Revamped Manual.
+
                                    LICENSING
 
 C-INTERCAL is now distributed under the General Public License, except for the
diff --git a/etc/IFFI.spec b/etc/IFFI.spec
new file mode 100644 (file)
index 0000000..d79fb60
--- /dev/null
@@ -0,0 +1,15 @@
+%fingerprint-spec 1.1
+%fprint:IFFI
+%url:http://example.com
+%desc:INTERCAL-like Foreign Function Interface
+%safe:false
+%begin-instrs
+#I     name    desc
+C      comeFrom        In markmode COME FROM the top of stack
+F      forget  FORGET NEXT stack entries equal to top of stack
+L      label   Use top of stack as a line label for this point
+M      marker  Marks points where the code can be entered from outside
+N      next    Try to NEXT to the line labelled with the top of stack
+R      resume  RESUME to the top-of-stackth NEXT stack entry
+X      nextFrom        In markmode NEXT FROM the top of stack
+%end
diff --git a/etc/IFFI/IFFI.c b/etc/IFFI/IFFI.c
new file mode 100644 (file)
index 0000000..bfc3a1c
--- /dev/null
@@ -0,0 +1,211 @@
+/* -*- mode: C; coding: utf-8; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
+ *
+ * cfunge - a conformant Befunge93/98/08 interpreter in C.
+ * Copyright (C) 2008 Arvid Norlander <anmaster AT tele2 DOT se>
+ * Copyright (C) 2008 Alex Smith
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at the proxy's option) any later version. Arvid Norlander is a
+ * proxy who can decide which future versions of the GNU General Public
+ * License can be used.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "IFFI.h"
+#include "../../stack.h"
+#include "../../settings.h"
+#include "../../interpreter.h"
+
+static instructionPointer *iffiIP = NULL;
+
+// Communication functions with the ecto_b98 expansion library
+void ick_SaveIPPosDelta(struct ick_ipposdeltatype* ippd)
+{
+       ippd->ix = iffiIP->position.x;
+       ippd->iy = iffiIP->position.y;
+       ippd->dx = iffiIP->delta.x;
+       ippd->dy = iffiIP->delta.y;
+}
+
+void ick_RestoreIPPosDelta(struct ick_ipposdeltatype* ippd)
+{
+       iffiIP->position.x = ippd->ix;
+       iffiIP->position.y = ippd->iy;
+       iffiIP->delta.x = ippd->dx;
+       iffiIP->delta.y = ippd->dy;
+}
+
+void ick_InterpreterRun(void)
+{
+       if (!FungeSpaceCreate()) {
+               perror("Couldn't create funge space!?");
+               exit(EXIT_FAILURE);
+       }
+       FungeSpaceLoadString(ick_iffi_befungeString);
+       iffiIP = ipCreate();
+       if (iffiIP == NULL) {
+               perror("Couldn't create instruction pointer!?");
+               exit(EXIT_FAILURE);
+       }
+       {
+               struct timeval tv;
+               if (gettimeofday(&tv, NULL)) {
+                       perror("Couldn't get time of day?!");
+                       exit(EXIT_FAILURE);
+               }
+               /* Set up randomness */
+               srandom(tv.tv_usec);
+       }
+       if(ick_printflow) SettingTraceLevel=9;
+       ick_InterpreterMainLoop();
+}
+
+void ick_iffi_InterpreterOneIteration(void)
+{
+       FUNGEDATATYPE opcode;
+       opcode = FungeSpaceGet(&iffiIP->position);
+
+       if (SettingTraceLevel > 8) {
+               fprintf(stderr, "x=%" FUNGEVECTORPRI " y=%" FUNGEVECTORPRI
+                               ": %c (%" FUNGEDATAPRI ")\n",
+                               iffiIP->position.x, iffiIP->position.y, (char)opcode, opcode);
+               PrintStackTop(iffiIP->stack);
+       } else if (SettingTraceLevel > 3) {
+               fprintf(stderr, "x=%" FUNGEVECTORPRI " y=%" FUNGEVECTORPRI
+                               ": %c (%" FUNGEDATAPRI ")\n",
+                               iffiIP->position.x, iffiIP->position.y, (char)opcode, opcode);
+       } else if (SettingTraceLevel > 2)
+               fprintf(stderr, "%c", (char)opcode);
+
+       ExecuteInstruction(opcode, iffiIP);
+       if (iffiIP->needMove)
+               ipForward(iffiIP, 1);
+       else
+               iffiIP->needMove = true;
+}
+
+// C - In markmode COME FROM the top of stack
+static void FingerIFFIcomeFrom(instructionPointer * ip)
+{
+       FUNGEDATATYPE l;
+
+       l = StackPop(ip->stack);
+
+       if (ick_iffi_inmarkmode) {
+               ick_iffi_breakloop = 1;
+               ick_iffi_linelabel = l;
+               ick_iffi_comingfrom = 1;
+       }
+}
+
+// F - FORGET NEXT stack entries equal to top of stack
+static void FingerIFFIforget(instructionPointer * ip)
+{
+       FUNGEDATATYPE f;
+
+       if (ick_iffi_inmarkmode) { /* this is an error in the user's code */
+               ipReverse(ip);
+               return;
+       }
+
+       f = StackPop(ip->stack);
+
+       if (f > 81 || f < 0) f = 81;
+
+       ick_iffi_forgetcount = f;
+}
+
+// L - Use top of stack as a line label for this point
+static void FingerIFFIlabel(instructionPointer * ip)
+{
+       FUNGEDATATYPE l;
+
+       l = StackPop(ip->stack);
+
+       ick_iffi_breakloop = 1;
+       ick_iffi_linelabel = l;
+       ick_iffi_sucking = 1;
+}
+
+// M - Marks points where the code can be entered from outside
+static void FingerIFFImarker(instructionPointer * ip)
+{
+       (void) ip;
+       ick_iffi_breakloop = ick_iffi_inmarkmode;
+}
+
+// N - Try to NEXT to the line labelled with the top of stack
+static void FingerIFFInext(instructionPointer * ip)
+{
+       FUNGEDATATYPE l;
+
+       if (ick_iffi_inmarkmode) { /* this is an error in the user's code */
+               ipReverse(ip);
+               return;
+       }
+
+       l = StackPop(ip->stack);
+
+       ick_iffi_breakloop = 1;
+       ick_iffi_linelabel = l;
+       ick_iffi_nexting = 1;
+}
+
+// R - RESUME to the top-of-stackth NEXT stack entry
+static void FingerIFFIresume(instructionPointer * ip)
+{
+       FUNGEDATATYPE f;
+
+       if (ick_iffi_inmarkmode) { /* this is an error in the user's code */
+               ipReverse(ip);
+               return;
+       }
+
+       f = StackPop(ip->stack);
+
+       if (f > 81 || f < 0) f = 81;
+
+       ick_iffi_forgetcount = f;
+
+       ick_iffi_resuming = 1;
+
+       ick_iffi_breakloop = 1;
+}
+
+// X - In markmode NEXT FROM the top of stack
+static void FingerIFFInextFrom(instructionPointer * ip)
+{
+       FUNGEDATATYPE l;
+
+       l = StackPop(ip->stack);
+
+       if (ick_iffi_inmarkmode) {
+               ick_iffi_breakloop = 1;
+               ick_iffi_linelabel = l;
+               ick_iffi_nextingfrom = 1;
+       }
+}
+
+bool FingerIFFIload(instructionPointer * ip)
+{
+       static int firstload = 1;
+       ick_iffi_breakloop = firstload;
+       firstload = 0;
+       ManagerAddOpcode(IFFI,  'C', comeFrom)
+       ManagerAddOpcode(IFFI,  'F', forget)
+       ManagerAddOpcode(IFFI,  'L', label)
+       ManagerAddOpcode(IFFI,  'M', marker)
+       ManagerAddOpcode(IFFI,  'N', next)
+       ManagerAddOpcode(IFFI,  'R', resume)
+       ManagerAddOpcode(IFFI,  'X', nextFrom)
+       return true;
+}
diff --git a/etc/IFFI/IFFI.h b/etc/IFFI/IFFI.h
new file mode 100644 (file)
index 0000000..36e2606
--- /dev/null
@@ -0,0 +1,55 @@
+/* -*- mode: C; coding: utf-8; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*-
+ *
+ * cfunge - a conformant Befunge93/98/08 interpreter in C.
+ * Copyright (C) 2008 Arvid Norlander <anmaster AT tele2 DOT se>
+ * Copyright (C) 2008 Alex Smith
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at the proxy's option) any later version. Arvid Norlander is a
+ * proxy who can decide which future versions of the GNU General Public
+ * License can be used.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _HAD_SRC_FINGERPRINTS_IFFI_H
+#define _HAD_SRC_FINGERPRINTS_IFFI_H
+
+#include "../../global.h"
+#include "../manager.h"
+
+#ifdef CONCURRENT_FUNGE
+#error The C-INTERCAL/cfunge external calls interface cannot be used concurrently
+#endif
+
+struct ick_ipposdeltatype
+{
+  long long ix, iy, dx, dy;
+};
+
+bool FingerIFFIload(instructionPointer * ip);
+
+void ick_InterpreterMainLoop(void);
+
+extern unsigned short ick_iffi_forgetcount;
+extern int ick_iffi_nexting;
+extern int ick_iffi_comingfrom;
+extern int ick_iffi_nextingfrom;
+extern int ick_iffi_sucking;
+extern int ick_iffi_resuming;
+extern uint32_t ick_iffi_linelabel;
+extern int ick_iffi_breakloop;
+extern int ick_iffi_inmarkmode;
+
+extern const char * ick_iffi_befungeString;
+extern int ick_printflow;
+
+#endif
diff --git a/etc/cftoec.sh b/etc/cftoec.sh
new file mode 100644 (file)
index 0000000..c1dbfc3
--- /dev/null
@@ -0,0 +1,68 @@
+#! /bin/sh
+# This shell-script takes one argument, the path to a source
+# distribution of cfunge, and compiles that source distribution into a
+# library (libick_ecto_b98.a) suitable for linking to C-INTERCAL
+# programs.
+
+test x$1 != x || (
+    echo Please give the path to the root of a cfunge source
+    echo distribution as an argument to this script.
+    exit 1
+) || exit 1
+
+CFUNGEPATH=`realpath $1` || (
+    echo Please give the path to the root of a cfunge source
+    echo distribution as an argument to this script\; the directory
+    echo or file you gave does not exist.
+    exit 1
+) || exit 1
+
+test -f $CFUNGEPATH/src/interpreter.c || (
+    echo Please give the path to the root of a cfunge source
+    echo distribution as an argument to this script.
+    echo You gave $CFUNGEPATH, but it does not appear to be a cfunge
+    echo source distribution.
+    exit 1
+) || exit 1
+
+test -f IFFI.spec || (
+    echo Please run this script in the /etc directory of your
+    echo C-INTERCAL distribution.
+    exit 1
+) || exit 1
+
+echo Compiling cfunge into a library suitable for use with C-INTERCAL:
+
+cd temp
+
+CFLAGS="--std=c99 -DUSE32 -DDISABLE_GC -DFUNGE_EXTERNAL_LIBRARY -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED -DFUNGEHANDPRINT=0x43464649"
+
+echo "   " Duplicating cfunge source tree so that it can be modified...
+cp -r $CFUNGEPATH/src $CFUNGEPATH/lib .
+
+echo "   " Patching cfunge source tree for use with C-INTERCAL...
+patch -p0 < ../cfunge.patch
+
+echo "   " Adding the IFFI fingerprint...
+cp -r ../IFFI ../IFFI.spec src/fingerprints
+
+echo "   " Regenerating fingerprint lists...
+$CFUNGEPATH/tools/gen_fprint_list.sh > /dev/null
+
+# Trust the filenames that are in the cfunge directory tree; if the user's
+# trying to trick themselves into running this on something that looks like
+# the cfunge directory tree but which has spaces or quotes in the filenames,
+# I really can't be bothered to save them from themself. Dump all the resulting
+# object files in this temp directory.
+echo "   " Compiling source...
+find . -name '*.c' -printf "gcc $CFLAGS -c %p -o %f.o\n" | sh
+
+echo "   " Creating library...
+ar cr ../../lib/libick_ecto_b98.a *.o
+ranlib ../../lib/libick_ecto_b98.a
+
+echo "   " Cleaning up...
+rm -rf *
+cd ..
+
+echo Finished, unless there were errors.
diff --git a/etc/cfunge.patch b/etc/cfunge.patch
new file mode 100644 (file)
index 0000000..ef2f513
--- /dev/null
@@ -0,0 +1,15 @@
+=== modified file 'src/global.h'
+--- src/global.h       2008-06-30 15:54:08 +0000
++++ src/global.h       2008-07-05 17:14:43 +0000
+@@ -158,7 +158,9 @@
+ 
+ 
+ /// Handprint: CFUN
+-#define FUNGEHANDPRINT 0x4346554e
++#ifndef FUNGEHANDPRINT
++#  define FUNGEHANDPRINT 0x4346554e
++#endif
+ /// Version, for -V.
+ #define APPVERSION  "0.2.1-pre2"
+ /// For y instruction.
+
index 7873d9a77265b0b1375a930722f2efc3d38c0da1..f1990a428a3e8b2b9635c00e7b26fcfe60730d37 100644 (file)
@@ -132,6 +132,7 @@ by Alex Smith
   tests/testcreate.i  A test for the CREATE statement\r
   explib/syslibc.c    The INTERCAL base 2 syslib, optimised version in C\r
   explib/compunex.c   An example flow-control routine (computed NEXT)\r
+  explib/ecto_b98.c   A library that links INTERCAL and Funge-98 code\r
   sort.i              An insertion-sort program testing computed ABSTAIN\r
   continuation.i      A continuation library and example program\r
   continuation.doc    About usage and internals of the continuation library\r
diff --git a/pit/explib/ecto_b98.c b/pit/explib/ecto_b98.c
new file mode 100644 (file)
index 0000000..b8e4866
--- /dev/null
@@ -0,0 +1,275 @@
+/***************************************************************************
+
+NAME
+    ecto_b98.c - glue code for linking .b98 files with .i files
+
+LICENSE TERMS
+    Copyright (C) 2008 Alex Smith
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+    Note that this code is designed to be linked against a GPLv3 library
+    (producing a GPLv3 output), and therefore it is recommended that
+    modifications to this code are compatible with GPLv3, although this
+    is not a legal requirement.
+
+***************************************************************************/
+
+/* This is an expansion library designed to link with the Funge-98 interpreter
+   cfunge (when compiled as a library); this is glue code which hooks into the
+   INTERCAL control structure, and uses functions in glue code which hooks
+   into the Funge control structure in cfunge. The Befunge program itself that
+   is interpreted is stored in yet another .cio file, and accessed via the
+   extern variables ick_iffi_befungeString, ick_iffi_markerposns, and
+   ick_iffi_markercount. The name ecto_b98 is magical, and causes this library
+   to be included when a .b98 files is encountered on the command line (as
+   well as the cfunge library itself, which has the magical name
+   libick_ecto_b98.a).
+
+   The library itself works by using label names that have a special meaning
+   to ick, along with ICK_EC_FUNCs, to cause a compiled C-INTERCAL program to
+   also search in the Befunge program for line labels, COME FROMs, and NEXT
+   FROMs, as well as in the INTERCAL program itself. It also allows the
+   Befunge program to use INTERCAL control flow structures (even to itself),
+   by monitoring flags set in a Funge-98 fingerprint (IFFI, which accounts
+   for most of the variable names) and simulating the required structure
+   (such as FORGET or NEXT) somewhere where cfunge itself will be unaffected
+   and unaware of what is going on.
+
+   In general, INTERCAL control flow structures affect only the position and
+   delta of the IP in the Befunge program, not anything else. (In particular,
+   the Befunge stack is unaffected.)
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#include <ick_ec.h>
+
+extern int ick_printflow;
+
+struct ick_ipposdeltatype
+{
+  long long ix, iy, dx, dy;
+};
+
+void ick_InterpreterMainLoop(void);
+void ick_InterpreterRun(void);
+void ick_iffi_InterpreterOneIteration(void);
+void ick_iffi_HandleControl(void);
+void ick_SaveIPPosDelta(struct ick_ipposdeltatype*);
+void ick_RestoreIPPosDelta(struct ick_ipposdeltatype*);
+
+unsigned short ick_iffi_forgetcount=0;
+int ick_iffi_nexting=0;
+int ick_iffi_comingfrom=0;
+int ick_iffi_nextingfrom=0;
+int ick_iffi_sucking=0;
+int ick_iffi_resuming=0;
+uint32_t ick_iffi_linelabel=0;
+int ick_iffi_breakloop=0; /* becomes 1 when IFFI's loaded or mark-mode ends */
+int ick_iffi_inmarkmode=0;
+
+extern const char* ick_iffi_befungeString;
+extern long long ick_iffi_markerposns[][2];
+extern int ick_iffi_markercount;
+
+ICK_EC_FUNC_START(ick_InterpreterMainLoop)
+{
+  ick_startup( {ick_InterpreterRun();} ); /* could be put anywhere, is put here
+                                            for convenience */
+
+  /* we enter here when running at startup code and continue until IFFI is loaded */
+
+  if(0)
+  {
+  ick_l2_ICK_EC_PP_2: /* this will be automatically replaced with a valid label,
+                        as will the next occurence of it, by ick when it does
+                        linking (i.e. this is not an infinite loop). */
+    if(ick_global_linelabel != 0x70001ff1 &&
+       ick_global_linelabel != 0x70001ff2)
+      goto ick_l2_ICK_EC_PP_2;
+    /* If control reaches this point, a COME FROM or NEXT has just completed,
+       and the IP already in the correct place. Continue, outside markmode. */
+    ick_iffi_nexting = 0;
+    ick_iffi_comingfrom = 0;
+    ick_iffi_nextingfrom = 0;
+    ick_iffi_sucking = 0;
+    ick_iffi_inmarkmode = 0;
+    ick_global_checkmode = 0;
+    /* If a NEXT has just completed, do a suckpoint-check on that line label
+       (in case someone COMEs FROM the target of the NEXT). */
+    if(ick_global_linelabel == 0x70001ff2)
+    {
+      auto struct ick_ipposdeltatype ippd;
+      ick_SaveIPPosDelta(&ippd);
+      ick_iffi_sucking = 0;
+      ick_checksuckpoint(ick_iffi_linelabel); /* may not return */
+      ick_RestoreIPPosDelta(&ippd);
+    }
+  }
+
+ick_iffi_iml_rerun:
+
+  ick_iffi_breakloop=0;
+  while(!ick_iffi_breakloop)
+  {
+    ick_iffi_InterpreterOneIteration();
+    if (ick_iffi_forgetcount && !ick_iffi_breakloop)
+    {
+      ick_forget(ick_iffi_forgetcount);
+      ick_iffi_forgetcount = 0;
+    }
+  }
+  /* There are several reasons why we could reach this point. Most of them,
+     we just fall off the end of the function and whatever called us handles
+     the program flow from there. However, if the loop broke due to a RESUME,
+     line label or NEXT, we need to handle it. */
+  if(ick_iffi_resuming)
+  {
+    unsigned short iifctemp = ick_iffi_forgetcount;
+    ick_iffi_resuming = 0;
+    ick_iffi_forgetcount = 0;
+    ick_resume(iifctemp); /* never returns */
+  }
+  if(ick_iffi_nexting)
+  {
+    /* To handle a NEXT, we need to save the relevant IP information (position
+       and delta, which are the only things saved/restored on the NEXT stack)
+       onto the C stack. This is done in a struct ick_ipposdatatype, using the
+       functions available for such save/restore. */
+    auto struct ick_ipposdeltatype ippd;
+    ick_SaveIPPosDelta(&ippd);
+    ick_iffi_nexting = 0;
+    ick_next(ick_iffi_linelabel); /* may not return */
+    ick_RestoreIPPosDelta(&ippd);
+    goto ick_iffi_iml_rerun; /* continue the main loop if we got here */
+  }
+  if(ick_iffi_sucking && ! ick_iffi_inmarkmode)
+  {
+    /* Handle a line-label encountered in normal execution. */
+    auto struct ick_ipposdeltatype ippd;
+    ick_SaveIPPosDelta(&ippd);
+    ick_iffi_sucking = 0;
+    ick_checksuckpoint(ick_iffi_linelabel); /* may not return */
+    ick_RestoreIPPosDelta(&ippd);
+    goto ick_iffi_iml_rerun; /* continue the main loop if we got here */
+  }
+}
+ICK_EC_FUNC_END
+
+ICK_EC_FUNC_START(ick_iffi_HandleControl)
+{
+  static int recursing=0;
+  int markerno, dirno, nextcheck;
+  struct ick_ipposdeltatype ippd;
+
+  /* The label names here are magical internal identifiers. That means that this
+     is not in fact an infinite loop, but is instead a handler for sucking in
+     from line labels. The 0x70001ff1 is a magic number used specifically by
+     this code. */
+  if(0)
+  {
+  ick_l1_ICK_EC_PP_1:
+    if(ick_global_linelabel > 65535)
+      goto skipsearch; /* there can't be a match, don't check to avoid recursion */
+    nextcheck = 0;
+    if(ick_printflow)
+      fprintf(stderr,"[cfcheck:%d]\n",(int)ick_global_linelabel);
+  }
+
+  if(0)
+  {
+  ick_l2_ICK_EC_PP_2:
+    if(ick_global_linelabel > 65535)
+      goto skipsearch; /* there can't be a match, don't check to avoid recursion */
+    nextcheck = 1;
+    if(ick_printflow)
+      fprintf(stderr,"[llcheck:%d]\n",(int)ick_global_linelabel);
+  }
+
+  assert(!recursing);
+
+  recursing=1;
+
+  ick_SaveIPPosDelta(&ippd);
+
+  markerno=ick_iffi_markercount;
+  while(markerno--)
+  {
+    dirno=4;
+    while(dirno--)
+    {
+      struct ick_ipposdeltatype tippd;
+      tippd.ix=ick_iffi_markerposns[markerno][0];
+      tippd.iy=ick_iffi_markerposns[markerno][1];
+      tippd.dx=(dirno == 3 ? -1 : dirno == 1 ? 1 : 0);
+      tippd.dy=(dirno == 0 ? -1 : dirno == 2 ? 1 : 0);
+      if(ick_printflow)
+       fprintf(stderr, "Checking for %s at (%lld, %lld) going %c...\n",
+               nextcheck ? "line label" : "COME FROM/NEXT FROM",
+               tippd.ix, tippd.iy, dirno["^>v<"]);
+      tippd.ix += tippd.dx;
+      tippd.iy += tippd.dy;
+      ick_RestoreIPPosDelta(&tippd);
+      ick_iffi_inmarkmode = 1;
+      ick_local_checkmode = ick_global_checkmode;
+      ick_global_checkmode = 0;
+      ick_InterpreterMainLoop();
+      ick_global_checkmode = ick_local_checkmode;
+      ick_iffi_inmarkmode = 0;
+      if((ick_iffi_nextingfrom||ick_iffi_comingfrom) &&
+       ick_iffi_linelabel == ick_global_linelabel && !nextcheck)
+      {
+       if(ick_printflow)
+         fprintf(stderr,"%s FROM found!\n",ick_iffi_comingfrom?"COME":"NEXT");
+       /* Error out on multiple COME FROM/NEXT FROM with the same target. */
+       if(ick_global_goto) ick_lose(ICK_IE555, -1, (char*)0);
+       ick_global_goto=0x70001FF1; /* we found a suckpoint */
+       if(ick_iffi_nextingfrom) ick_global_checkmode = 3; /* do a next from */
+       /* if it's a come-from, the checkmode is already correct */
+       ick_SaveIPPosDelta(&ippd);
+      }
+      if(ick_iffi_sucking && ick_iffi_linelabel == ick_global_linelabel &&
+        nextcheck)
+      {
+       if(ick_printflow)
+         fprintf(stderr,"Line label found!\n");
+       /* Another part of the code is NEXTing to this line label. */
+       ick_SaveIPPosDelta(&ippd);
+       nextcheck = 2; /* when this loop ends, goto the main loop */
+      }
+      ick_iffi_nextingfrom = 0;
+      ick_iffi_comingfrom = 0;
+      ick_iffi_sucking = 0;
+    }
+  }
+
+  if(ick_printflow) fprintf(stderr,"Checks finished.\n");
+
+  /* Set the IP to what we want it to be on resume, or otherwise return it to
+     its original value. (Returning it to its original value is unneccesary
+     but harmless.) */
+  ick_RestoreIPPosDelta(&ippd);
+  recursing=0;
+  ick_iffi_linelabel = ick_global_linelabel;
+  if(nextcheck == 2)
+    ick_dogoto(0x70001FF2,-1,0);
+skipsearch:
+  if(nextcheck)
+    goto ick_l2_ICK_EC_PP_2;
+  else
+    goto ick_l1_ICK_EC_PP_1;
+}
+ICK_EC_FUNC_END
index 8b439b3d313ec4740262633bcd0382a74cfe4959..804d5365b0c448f97c9dbb3dc69a62ac737d1fc2 100644 (file)
@@ -1553,9 +1553,11 @@ int main(int argc, char *argv[])
 #else
       (void) snprintf(buf2, sizeof buf2,
 #endif
-                     "%s --std=c%d -E -I%s -I%s -I%s/../include "
+                     "%s --std=c%d -E -DICK_HAVE_STDINT_H=%d "
+                     "-I%s -I%s -I%s/../include "
                      "-x c %s.c%c%c > %s.cio",
                      compiler, argv[optind][strlen(argv[optind])+2]=='9'?99:89,
+                     ICK_HAVE_STDINT_H+1-1,
                      includedir, path, path, argv[optind],
                      argv[optind][strlen(argv[optind])+2]=='9'?
                      (needc99=1),'9':' ',