diff interps/c-intercal/pit/explib/ecto_b98.c @ 996:859f9b4339e6

<Gregor> tar xf egobot.tar.xz
author HackBot
date Sun, 09 Dec 2012 19:30:08 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interps/c-intercal/pit/explib/ecto_b98.c	Sun Dec 09 19:30:08 2012 +0000
@@ -0,0 +1,281 @@
+/***************************************************************************
+
+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;
+};
+
+/* This is called from IFFI. Remember to keep matching
+   extern over there in sync. */
+void ick_interpreter_main_loop(void);
+
+/* This is just a forward decl. */
+void ick_iffi_handle_control(void);
+
+/* These are implemented in IFFI. */
+extern void ick_interpreter_run(void);
+extern void ick_iffi_interpreter_one_iteration(void);
+extern void ick_save_ip_pos_delta(struct ick_ipposdeltatype*);
+extern void ick_restore_ip_pos_delta(const 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 unsigned char* ick_iffi_befungeString;
+extern long long ick_iffi_markerposns[][2];
+extern int ick_iffi_markercount;
+
+ICK_EC_FUNC_START(ick_interpreter_main_loop)
+{
+  ick_startup( {ick_interpreter_run();} ); /* 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_save_ip_pos_delta(&ippd);
+      ick_iffi_sucking = 0;
+      ick_checksuckpoint(ick_iffi_linelabel); /* may not return */
+      ick_restore_ip_pos_delta(&ippd);
+    }
+  }
+
+ick_iffi_iml_rerun:
+
+  ick_iffi_breakloop=0;
+  while(!ick_iffi_breakloop)
+  {
+    ick_iffi_interpreter_one_iteration();
+    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_save_ip_pos_delta(&ippd);
+    ick_iffi_nexting = 0;
+    ick_next(ick_iffi_linelabel); /* may not return */
+    ick_restore_ip_pos_delta(&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_save_ip_pos_delta(&ippd);
+    ick_iffi_sucking = 0;
+    ick_checksuckpoint(ick_iffi_linelabel); /* may not return */
+    ick_restore_ip_pos_delta(&ippd);
+    goto ick_iffi_iml_rerun; /* continue the main loop if we got here */
+  }
+}
+ICK_EC_FUNC_END
+
+ICK_EC_FUNC_START(ick_iffi_handle_control)
+{
+  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_save_ip_pos_delta(&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_restore_ip_pos_delta(&tippd);
+      ick_iffi_inmarkmode = 1;
+      ick_local_checkmode = ick_global_checkmode;
+      ick_global_checkmode = 0;
+      ick_interpreter_main_loop();
+      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_save_ip_pos_delta(&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_save_ip_pos_delta(&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_restore_ip_pos_delta(&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