/* fbbi.c v0.98 Flaming Bovine Befunge-98 Interpreter in ANSI C - Main Unit v0.98 Oct 1 1998 Chris Pressey v0.98a Mar 26 2003 Chris Pressey Copyright (c)1998, 2001, 2003, Cat's Eye Technologies. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of Cat's Eye Technologies nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* FBBI's web pages: http://www.catseye.mb.ca/projects/fbbi-+ Usage: fbbi [-f] [-w] [-t] [-s] [-u] [-93] [-mc n] [-ms n] sourcefile [funge-prog-args] -f: fast: more speed, at the cost of locking up if an infinite loop occurs. Only effective on systems that check for a BREAK only during I/O. -w: warn: like Perl's -w switch. If an unimplimented instruction is executed, the user is warned. Used in conjunction with -93 or -u, alerts user to behaviour not in the Befunge-93 or Unefunge idioms, as appropriate. -t: trace: display debug info & samples of source during execution, with interactive prompt -s: script: begin execution on the first line that does not begin with a comment (#) symbol -u: unefunge: disables Befunge and Trefunge-specific (>1D) instructions and uses single-scalar vectors -93: disables Funge-98 instructions, changes stringmode and in conjunction with -w tells the user about it -mc: maxcells: specify the maximum number of cells on each stack, default 1024. -ms: maxstacks: specify the maximum number of stacks on the stack stack, default 256. sourcefile: name of file to load and treat as a Befunge source funge-prog-args: made available to Befunge program through y ------------------------------------------------------------- If you find any bugs or any places where the implementation does not live up to the spec, please, please, *please* post them to the ESOLANG mailing list. The Final Specification can be found at: http://www.catseye.mb.ca/projects/funge98-+ ------------------------------------------------------------- v0.98a, Mar 26 2003, Chris Pressey. * relicensed under BSD license * made minor changes to Makefile and docs * values.h is no longer included under FreeBSD v0.98, Oct 1 1998, Chris Pressey. * Negative argument to { pushes |n| 0s onto the SOSS * Negative argument to } destroys top |n| values on the SOSS. * } reflects when stack-stack would be about to underflow * y instruction now pushes args and env as per spec - fixed greatest point bug in y's behaviour + f98stack.c module generalized for stacks of any type + Added trace ViewStackPlayfieldMoveDeltaOffset commands. + Unefunge compatibility [-u] (not well tested though). v0.94, Sep 15 1998, Chris Pressey. [Unreleased] * . and , reflect if stdout fails for whatever reason. * { reflects when no more stacks are available * & sucks and discards all leading non-digit characters - worked around EOL (CR, LF or CRLF) bug (binary mode.) + added _FILE_H_ define checking on all included headers. v0.93, Aug 3 1998, Chris Pressey. * y pushes vectors and path seperators * i and o both take a flags argument now * ~ and & instructions act like r on EOF in stdin * space and ; "instructions" are never executed (though they do have meaning in stringmode) * k instruction takes argument from space - fixed off-by-one error in stack_push_string - fixed ss_push_offset and ss_pop_offset - made stack_push, ss_push_stack safer - explicitly externs environ in main() - changed time() code in y to more idiomatic use - = instruction now really pushes return code onto stack - upped default stack and stack stack sizes + added a gcc Makefile (-ansi -pedantic now doesn't complain) + added config.h so end user can recompile with own options + minimal build now knows no fingerprints (more minimal) + added gnuesque --long-name command line options (doesn't accept equals signs like --max-cells=1024 yet) + added Befunge-93 compatibility mode (not thoroughly tested) v0.92, Jul 20 1998, Chris Pressey. Brought into line with the changes to spec, which were: * added k Iterate and s Store Character instructions * i and o both now pop the filename first * i pushes results appropriate for input to o * sizes of stacks now pushed before command line in y * environment is now pushed after command line in y * Null fingerprint is now fingerprint number 0x0 * Negative args to { or } now treated as zeros Also fixed the following bugs: - CRLF sequence indicates single EOL in bfspace_read - now (almost) cleans up y after taking a non-zero argument - wrapping with ';' instruction uses Lahey-wrap correctly Also made minor fbbi-only improvements, namely: + added size & script switches & longnames to command line + prettied up the source; made ip a struct, etc + modularized; everything in it's own object file + added 'mini' build, shaves 3K off the executable v0.91, Jul 8 1998, Chris Pressey. Added fingerprint mechanism and NULL and ROMA fingerprints. v0.90, Jul 6-8 1998, Chris Pressey. Did some critical tying up relative to the new spec. Added command line, final instructions {i=you}(). v0.84, Mar 24 1998, Chris Pressey. Added the bulk of vanilla Funge-98 instructions, and file I/O functions for big Befunge-Space. v0.83, Mar 1998, Chris Pressey. Derived from ssbf93 v0.83. */ /*-- #INCLUDE'S */ /*---- C libraries */ #include #include #include #include #include #ifndef FBBI_ANSI #ifdef __MSDOS__ #include #endif #endif extern char ** environ; /*---- FBBI modules */ #include "config.h" #include "fbbi.h" #include "bf98spc.h" #include "f98ip.h" #include "f98i.h" #include "f98fp.h" /*-- GLOBALS */ char ** global_argv; /* set to argv in main() */ int global_argc; /* set to argc in main() */ int fungeprog_arg; /* set to funge prog's arg in main() */ #ifndef FBBI_MINIMAL flag fast=0; flag warn=0; flag trace=0; flag script=0; flag b93=0; flag une=0; flag bpt=0; cell bx=0; cell by=0; #endif /*-- TRACE */ #ifndef FBBI_MINIMAL void perform_trace(ip * i) { char c[9]; cell s[4]; int j=0; int k=0; cell l=0; cell tx, ty; c[0] = PRINT(bfspace_fetch(i->bs, i->x-1, i->y-1)); c[1] = PRINT(bfspace_fetch(i->bs, i->x, i->y-1)); c[2] = PRINT(bfspace_fetch(i->bs, i->x+1, i->y-1)); c[3] = PRINT(bfspace_fetch(i->bs, i->x-1, i->y)); c[4] = PRINT(bfspace_fetch(i->bs, i->x, i->y)); c[5] = PRINT(bfspace_fetch(i->bs, i->x+1, i->y)); c[6] = PRINT(bfspace_fetch(i->bs, i->x-1, i->y+1)); c[7] = PRINT(bfspace_fetch(i->bs, i->x, i->y+1)); c[8] = PRINT(bfspace_fetch(i->bs, i->x+1, i->y+1)); for(k=0;k<=3;k++) { if (ip_stack_measure(i) > k) s[k] = ip_stack_peek_peek(i, 0, k); else s[k] = 0; } printf("+---+ position : (%06ld, %06ld) stack size: %d cell(s) # of stacks: %d\n", i->x, i->y, ip_stack_measure(i), ip_stacks_measure(i)); printf("|%c%c%c| delta : (%06ld, %06ld) 0x%08lx 0x%08lx 0x%08lx 0x%08lx\n", c[0], c[1], c[2], i->dx, i->dy, s[0], s[1], s[2], s[3]); printf("|%c%c%c| offset : (%06ld, %06ld) decimal (%ld %ld %ld %ld) ascii (%c%c%c%c)\n", c[3], c[4], c[5], i->sx, i->sy, s[0],s[1],s[2],s[3], PRINT(s[0]), PRINT(s[1]), PRINT(s[2]), PRINT(s[3])); printf("|%c%c%c| instruction: 0x%08lx ('%c')\n", c[6], c[7], c[8], i->ir, PRINT(i->ir)); printf("+---+ stringmode : %s\n", i->sm ? "on" : "off"); k=0; while(!k) { printf("S)tep R)un B)reakpoint V)iewStack P)layfield M)ove D)elta O)ffset Q)uit: "); fflush(stdin); fflush(stdout); scanf("%s", c); fflush(stdin); fflush(stdout); if ((c[0] == 'r') || (c[0] == 'R')) { trace=0; k=1; } if ((c[0] == 'q') || (c[0] == 'Q')) { i->hm=1; k=1; } if ((c[0] == 's') || (c[0] == 'S')) { k=1; } if ((c[0] == 'v') || (c[0] == 'V')) { printf("%d stacks:\n", ip_stacks_measure(i)); for(j=0;jbs, stdout, tx, ty, 79, 22, 0); k=0; fflush(stdout); } if ((c[0] == 'm') || (c[0] == 'M')) { printf("Enter x and y coordinates seperated by whitespace:"); fflush(stdin); fflush(stdout); scanf("%ld %ld", &i->x, &i->y); fflush(stdin); fflush(stdout); k=0; } if ((c[0] == 'd') || (c[0] == 'D')) { printf("Enter dx and dy values seperated by whitespace:"); fflush(stdin); fflush(stdout); scanf("%ld %ld", &i->dx, &i->dy); fflush(stdin); fflush(stdout); k=0; } if ((c[0] == 'o') || (c[0] == 'O')) { printf("Enter x and y storage offsets seperated by whitespace:"); fflush(stdin); fflush(stdout); scanf("%ld %ld", &i->sx, &i->sy); fflush(stdin); fflush(stdout); k=0; } if ((c[0] == 'b') || (c[0] == 'B')) { if(!bpt) { printf("Enter x and y coordinates of breakpoint, seperated by whitespace:"); fflush(stdin); fflush(stdout); scanf("%ld %ld", &bx, &by); fflush(stdin); fflush(stdout); bpt=1; } else { printf("Breakpoint deactivated."); fflush(stdout); bpt=0; } k=0; } } } #endif /*-- MAIN PROGRAM */ int main(int argc, char **argv) { int k, ec=0; FILE *f=NULL; bfspace *p=NULL; ip *i=NULL; cell w,h; int ssize = DEFAULT_STACK_SIZE; int sssize = DEFAULT_STACKSTACK_SIZE; global_argv = argv; global_argc = argc; if (argc < 2) { printf("fbbi - flaming bovine befunge-98 interpreter v%1d.%2d", FBBI_VERSION_MAJOR, FBBI_VERSION_MINOR); #ifdef FBBI_ANSI printf(" in ANSI C"); #endif #ifdef FBBI_MINIMAL printf(" - mini"); #endif printf("\n Copyright (c)1998-2003 Cat's Eye Technologies, http://www.catseye.mb.ca/" "\n Released under BSD license, see source code for more information.\n"); printf("usage: fbbi "); #ifndef FBBI_MINIMAL printf("[-f] [-w] [-t] [-s] [-u] [-93]\n [-mc n] [-ms n] "); #endif printf("sourcefile [funge-prog-args]\n"); #ifndef FBBI_MINIMAL printf(" -f[ast]: go fast at the cost of locking up in infinite loops\n"); printf(" -w[arn]: issue warnings on unimplemented instructions\n"); printf(" -t[race]: trace source execution during run\n"); printf(" -s[cript]: begin execution on first non-# line of source\n"); printf(" -u[nefunge]: work in one dimension only (Unefunge) mode\n"); printf(" -[befunge]93: work in Befunge-93 compatibility mode\n"); printf(" -m[ax]c[ells]: specify number of elements allocated for each stack, def. %d\n", ssize); printf(" -m[ax]s[tacks]: specify number of stacks allocated on stack stack, def. %d\n", sssize); #endif exit(1); } for(k=1;kbs, f, 0, 0, &w, &h, 0)) { fclose(f); #ifndef FBBI_MINIMAL if ((w > 79) || (h > 24)) { if(b93 && warn) fprintf(stderr, "fbbi warning: " "source too large for Befunge-93-Space (%ld x %ld)\n", w+1, h+1); } if (h >= 1) { if(une && warn) fprintf(stderr, "fbbi warning: " "source too large for Unefunge-98-Space (%ld x %ld)\n", w+1, h+1); } if (script) { while (bfspace_fetch(i->bs, 0, i->y) == ((long)0 | (long)'#')) i->y++; } #endif DEBUG("* Begin Interpret *"); while (!i->hm) { DEBUG("Moving IP"); ip_move(i); #ifndef FBBI_MINIMAL if(bpt && i->x == bx && i->y == by) trace=1; #endif DEBUG("Getting Instruction"); i->ir = bfspace_fetch(i->bs, i->x, i->y); #ifndef FBBI_MINIMAL if (b93 && ((i->x < 0) || (i->y < 0) || (i->x > 79) || (i->y > 24)) ) { if(warn) fprintf(stderr, "fbbi warning: " "beyond Befunge-93-Space at (%ld,%ld)\n", i->x, i->y); } if (trace) { perform_trace(i); if (i->hm) break; } #endif DEBUG("Executing Instruction"); if (i->sm && ((char)i->ir != '"')) { ip_push(i, i->ir); } else { if ((i->ir < 32) || (i->ir > 126)) { fi_unimp(i); } else { #ifndef FBBI_MINIMAL if(b93) b93instable[(char)i->ir-32](i); else #endif instable[(char)i->ir-32](i); } } } DEBUG("* End Interpret *"); ec = (int)i->ec; DEBUG("Freeing IP"); ip_free(i); DEBUG("Freeing Funge-Space"); bfspace_free(p); } else { DEBUG("Freeing IP"); ip_free(i); DEBUG("Freeing Funge-Space"); bfspace_free(p); fclose(f); #ifndef FBBI_MINIMAL fprintf(stderr, "fbbi error: can't load file\n"); #endif exit(1); } } else { DEBUG("Freeing IP"); ip_free(i); DEBUG("Freeing Funge-Space"); bfspace_free(p); #ifndef FBBI_MINIMAL fprintf(stderr, "fbbi error: can't open file\n"); #endif exit(1); } } else { DEBUG("Freeing Funge-Space"); bfspace_free(p); #ifndef FBBI_MINIMAL fprintf(stderr, "fbbi error: can't allocate ip\n"); #endif exit(1); } } else { #ifndef FBBI_MINIMAL fprintf(stderr, "fbbi error: can't allocate befunge-space\n"); #endif exit(1); } return ec; }