From: Alex Smith Date: Sun, 6 Jul 2008 04:24:11 +0000 (-0400) Subject: External calls to Funge-98, part 1 X-Git-Tag: 0.29~207 X-Git-Url: http://thyrsus.com/gitweb/?a=commitdiff_plain;h=e8791ae124bdf891953bd9bf1b7516e97c0650f3;p=intercal.git External calls to Funge-98, part 1 --- diff --git a/MANIFEST.txt b/MANIFEST.txt index d6203d8..0deddd0 100644 --- a/MANIFEST.txt +++ b/MANIFEST.txt @@ -14,9 +14,15 @@ ./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 @@ -130,7 +136,6 @@ ./pit/unlambda.i ./pit/yapp.doc ./pit/yapp.i -./src/autoscan.log ./src/abcess.h ./src/arrgghh.c ./src/atari.bin diff --git a/Makefile.in b/Makefile.in index 0ce5862..b1e8fe4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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* diff --git a/README.txt b/README.txt index 30607df..9515e62 100644 --- a/README.txt +++ b/README.txt @@ -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 index 0000000..d79fb60 --- /dev/null +++ b/etc/IFFI.spec @@ -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 index 0000000..bfc3a1c --- /dev/null +++ b/etc/IFFI/IFFI.c @@ -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 + * 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 . + */ + +#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 index 0000000..36e2606 --- /dev/null +++ b/etc/IFFI/IFFI.h @@ -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 + * 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 . + */ + +#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 index 0000000..c1dbfc3 --- /dev/null +++ b/etc/cftoec.sh @@ -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 index 0000000..ef2f513 --- /dev/null +++ b/etc/cfunge.patch @@ -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. + diff --git a/pit/CATALOG b/pit/CATALOG index 7873d9a..f1990a4 100644 --- a/pit/CATALOG +++ b/pit/CATALOG @@ -132,6 +132,7 @@ by Alex Smith tests/testcreate.i A test for the CREATE statement explib/syslibc.c The INTERCAL base 2 syslib, optimised version in C explib/compunex.c An example flow-control routine (computed NEXT) + explib/ecto_b98.c A library that links INTERCAL and Funge-98 code sort.i An insertion-sort program testing computed ABSTAIN continuation.i A continuation library and example program continuation.doc About usage and internals of the continuation library diff --git a/pit/explib/ecto_b98.c b/pit/explib/ecto_b98.c new file mode 100644 index 0000000..b8e4866 --- /dev/null +++ b/pit/explib/ecto_b98.c @@ -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 +#include +#include + +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 diff --git a/src/perpet.c b/src/perpet.c index 8b439b3..804d536 100644 --- a/src/perpet.c +++ b/src/perpet.c @@ -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':' ',