Mercurial > repo
diff interps/befunge/bef.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/befunge/bef.c Sun Dec 09 19:30:08 2012 +0000 @@ -0,0 +1,835 @@ +/* ****************************************************************** + + bef.c - The Original Befunge-93 Interpreter/Debugger in ANSI C + v2.21 Sep 20 2004 Chris Pressey, Cat's-Eye Technologies + + Copyright (c)1993-2004, 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. + + ****************************************************************** + + Usage : + + bef [-d] [-o] [-q] [-i] [-=] + [-r input-file] [-w output-file] + [-s stack-file] [-y delay] <befunge-source> + + -d: visual ANSI debugging display + -o: do not fix off-by-one error (for old sources) + -q: produce no output except Befunge program output ('quiet') + -i: ignore unsupported instructions + -=: use b97-ish = directives + -r: redirect input from a specified file instead of stdin + -w: redirect output to a specified file instead of stdout + -s: write contents of stack to log file + -y: specify debugging delay in milliseconds + + Compiles Under: + + Borland C++ v3.1 (16-bit MS-DOS) + DJGPP v2.952 (32-bit Protected-Mode MS-DOS) + Mingw v2. + + ****************************************************************** + + v2.21: Sep 2004, Chris Pressey + display correct version number + cleanup only, no functional changes + + v2.20, Jul 2000, Chris Pressey + prettied up preprocessor directives a bit + added defines for Metroworks CodeWarrior + so that bef will build on MacOS + relicensed under BSD + + v2.12, Mar 1998, Chris Pressey / compiles under Borland C++ v3.1 + added -i and -= options. You must specify -= if + you want to use b97-esque directives or the Un*x-ish + # comment thing, or both. + automatically appends '.bf' to filenames containing no periods. + explicitly pops remaining stack elements at end of execution. + compatibility messages are displayed when quiet is not specified. + debug mode is much improved, especially I/O under BorlandC. + bounds checking on 'p' and 'g' instructions. + + v2.11, Jan 1998, Chris Pressey / compiles under Borland C++ v3.1 + divide by zero now produces the correct result + improved some minor aesthetic features (messages & debug) + ANSI is used only if not compiling under Borland C. + + v2.10: Jul 1997, Chris Pressey + added -q command line option. + added primitive understanding of = directive from b97 spec. + any file with a =l directive but without =l b93 is rejected. + also understands # as a pre-directive line prefix for + Un*x-ish systems. + + v2.02: Jun 1997, Chris Pressey + pads playfield with space characters. all unread + locations remain spaces. + + v2.01: Jun 1997, Chris Pressey + command line switches are not case-insensitive. + fixes gcc Segmentation Fault error. + + v2.00: Jun 1997, Chris Pressey + combines interpreter and debugger. + fixes ANSI error in debugger. + v1.02: Feb 1996, Chris Pressey + @ now pushes '@' onto the stack in stringmode instead of quitting. + + v1.01: Feb 1996, Chris Pressey + fixes off-by-one error. + + v1.00: Sept 1993, Chris Pressey + original Befunge-93 distribution. + + ****************************************************************** */ + +/********************************************************* #PRAGMA'S */ + +/* This switches Borland C++ v3.1 to small memory model */ +#ifdef __BORLANDC__ +#pragma option -ms +#endif /* __BORLANDC__ */ + +/********************************************************* #INCLUDE'S */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <time.h> +#ifdef __BORLANDC__ +# include <dos.h> +# include <conio.h> +# define CONSOLE 1 +# define CURSORSHAPE 1 +#endif /* __BORLANDC__ */ +#ifdef __MWERKS__ +# include <console.h> +# define CONSOLE 1 +#endif /* __MWERKS__ */ + +/********************************************************** #DEFINE'S */ + +#define LINEWIDTH 80 +#define PAGEHEIGHT 25 + +#define SCREENWIDTH 79 +#define SCREENHEIGHT 22 + +#define DEBUGROW 24 +#define cur pg[y * LINEWIDTH + x] + +/********************************************************* STRUCTURES */ + +struct stack /* stack structure, for values on stack */ +{ + signed long val; + struct stack *next; +} * head; /* head of stack */ + +/*************************************************** GLOBAL VARIABLES */ + +char pg[LINEWIDTH * PAGEHEIGHT]; /* befunge 'page' of source */ +int x = 0, y = 0; /* x and y of the PC */ +int dx = 1, dy = 0; /* direction of the PC */ +int debug = 0; /* flag : display ANSI debugging? */ +int infile = 0, ia; /* flag : use input file, and assoc arg? */ +int outfile = 0, oa; /* flag : use output file, and assoc arg? */ +int stackfile = 0, sa; /* flag : use stack log file, & assoc arg? */ +int stringmode = 0; /* flag : are we in string mode? */ +int quiet = 0; /* flag : are we quiet? */ +int v10err_compat = 0; /* flag : emulate v1.0 off-by-one err? */ +int deldur = 25; /* debugging delay in milliseconds */ +int ignore_unsupported = 0; /* flag : ignore unsupported instructions? */ +int use_b97directives = 0; /* flag : use b97-esque directives? */ + +/********************************************************* PROTOTYPES */ + +void push (signed long val); +signed long pop (void); + +/******************************************************* MAIN PROGRAM */ + +int main (argc, argv) + int argc; + char **argv; +{ + FILE *f=NULL; + FILE *fi=NULL; + FILE *fo=NULL; + FILE *fs=NULL; + int i; + char filename[128]; + +#ifdef __MWERKS__ + argc = ccommand(&argv); +#endif /* __MWERKS__ */ + + srand((unsigned)time(0)); + + if (argc < 2) + { + printf ("USAGE: bef [-d] [-o] [-q] [-i] [-=]\n"); + printf (" [-r input] [-w output] [-s stack] [-y delay] foo.bf\n"); + exit (0); + } + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-o")) { v10err_compat = 1; } + if (!strcmp(argv[i], "-d")) { debug = 1; } + if (!strcmp(argv[i], "-r")) { infile = 1; ia = i + 1; } + if (!strcmp(argv[i], "-w")) { outfile = 1; oa = i + 1; } + if (!strcmp(argv[i], "-s")) { stackfile = 1; sa = i + 1; } + if (!strcmp(argv[i], "-y")) { deldur = atoi(argv[i + 1]); } + if (!strcmp(argv[i], "-q")) { quiet = 1; } + if (!strcmp(argv[i], "-i")) { ignore_unsupported = 1; } + if (!strcmp(argv[i], "-=")) { use_b97directives = 1; } + } + if (!quiet) + { + //printf ("Befunge-93 Interpreter/Debugger v2.21\n"); + } + + memset(pg, ' ', LINEWIDTH * PAGEHEIGHT); + + strcpy(filename, argv[argc - 1]); + if (strchr(filename, '.') == NULL) + { + strcat(filename, ".bf"); + } + + if ((f = fopen (filename, "r")) != NULL) /*** Input Phase */ + { + int x = 0, y = 0; + char dc = '=', tc = ' '; + int tt = 0; char s[80]; + int accept_pound = 1; + + while (!feof (f)) + { + cur = fgetc (f); + if (use_b97directives && (x == 0) && ((cur == dc) || ((accept_pound) && (cur == '#')))) + { + if (cur != '#') accept_pound = 0; + tc = fgetc (f); + if (tc == 'l') + { + while (tc != ' ') + { + tc = fgetc (f); + } + while (tc != '\n') + { + tc = fgetc (f); + if (tc != '\n') { s[tt++] = tc; s[tt] = (char)0; } + } + if (strcmp(s, "b93")) + { + fprintf(stderr, "Error: only Befunge-93 (not %s) sources are supported by BEF.\n", s); + exit(10); + } + } + while (tc != '\n') + { + tc = fgetc (f); + } + } else + { + accept_pound = 0; + if (cur == '\n') + { + cur = ' '; + x = 0; + y++; + if (y >= PAGEHEIGHT) break; + } else + { + x++; + if (x >= LINEWIDTH) + { + x = 0; + y++; + if (y >= PAGEHEIGHT) break; + } + } + } + } + fclose (f); + } else + { + printf ("Error: couldn't open '%s' for input.\n", filename); + exit (0); + } + + if (infile) + { + if (!(fi = fopen (argv[ia], "r"))) + { + printf ("Error : couldn't open '%s' for input.\n", argv[ia]); + exit (0); + } + } + + if (outfile) + { + if (!(fo = fopen (argv[oa], "w"))) + { + printf ("Error : couldn't open '%s' for output.\n", argv[oa]); + exit (0); + } + } + + if (stackfile) + { + if (!(fs = fopen (argv[sa], "w"))) + { + printf ("Error : couldn't open '%s' for output.\n", argv[sa]); + exit (0); + } + } + + if (debug) + { + +#ifdef CONSOLE + clrscr(); +# ifdef CURSORSHAPE + _setcursortype(_NOCURSOR); +# endif /* CURSORSHAPE */ +#else + printf ("%c[1;1H", 27); + printf ("%c[2J", 27); +#endif /* CONSOLE */ + + for(y = 0; y < SCREENHEIGHT; y++) + { + for(x = 0; x < SCREENWIDTH; x++) + { + if (isprint(cur)) + { + printf("%c", cur); + } + } + printf("\n"); + } + + x = y = 0; + +#ifdef CUSRORSHAPE + _setcursortype(_SOLIDCURSOR); +#endif /* CUSRORSHAPE */ + + } + + while ((cur != '@') || (stringmode)) /*** Intepreting Phase */ + { + if (debug) + { + if ((y < SCREENHEIGHT) && (x < SCREENWIDTH)) + { +#ifdef CONSOLE + gotoxy(x+1, y+1); + if (kbhit()) + { + char c; + /* ideally, pop up a debugging tool. for now, exit. */ + c = getch(); + if (c == 0) + { + c = getch(); + } else + { + if (c == 27) + { + /* pause */ + c = getch(); + if (c == 0) + { + c = getch(); + } else + { + if (c == 27) + { + goto the_end; + } + } + } + } + } +#else + printf ("%c[%d;%dH", 27, y+1, x+1); + fflush (stdout); +#endif /* CONSOLE */ + } +#if __BORLANDC__ + delay (deldur); +#endif /* __BORLANDC __ */ + } + if (stringmode && (cur != '"')) + push (cur); + else if (isdigit (cur)) + push (cur - '0'); + else + switch (cur) + { + case '>': /* PC Right */ + dx = 1; + dy = 0; + break; + case '<': /* PC Left */ + dx = -1; + dy = 0; + break; + case '^': /* PC Up */ + dx = 0; + dy = -1; + break; + case 'v': /* PC Down */ + dx = 0; + dy = 1; + break; + case '|': /* Vertical 'If' */ + dx = 0; + if (pop ()) + dy = -1; + else + dy = 1; + break; + case '_': /* Horizontal 'If' */ + dy = 0; + if (pop ()) + dx = -1; + else + dx = 1; + break; + case '+': /* Add */ + push (pop () + pop ()); + break; + case '-': /* Subtract */ + { + long a = pop(); + long b = pop(); + push(b - a); + } + break; + case '*': /* Multiply */ + push (pop () * pop ()); + break; + case '/': /* Integer Divide */ + { + signed long a = pop (); + signed long b = pop (); + if (a == 0) + { + if (!outfile) + { + printf("What do you want %ld/0 to be? ", b); + } else + { + fprintf(fo, "What do you want %ld/0 to be? ", b); + } + if (infile) + { + fscanf (fi, "%ld", &b); + push (b); + } else + { + if (!debug) + { + fscanf (stdin, "%ld", &b); + push (b); + } + } + } else + { + push (b / a); + } + } + break; + case '%': /* Modulo */ + { + signed long a = pop (); + signed long b = pop (); + push (b % a); + } + break; + case '\\': /* Swap */ + { + signed long a = pop (); + signed long b = pop (); + push (a); + push (b); + } + break; + case '.': /* Pop Out Integer */ + { + if (outfile) + { + fprintf (fo, "%ld ", pop ()); + fflush (fo); + } else + { + if (!debug) + { + fprintf (stdout, "%ld ", pop ()); + fflush (stdout); + } else + { +#ifdef CONSOLE + int x, y; + char s[172], t[172]; + x = wherex(); + y = wherey(); + sprintf(s, "%ld ", pop()); + gettext(1+strlen(s), DEBUGROW, 80, DEBUGROW, t); + puttext(1, DEBUGROW, 80-strlen(s), DEBUGROW, t); + gotoxy(81-strlen(s), DEBUGROW); + cputs(s); + gotoxy(x, y); +#endif /* CONSOLE */ + } + } + } + break; + case ',': /* Pop Out ASCII */ + { + if (outfile) + { + fprintf (fo, "%c", (char)pop ()); + fflush (fo); + } else + { + if (!debug) + { + fprintf (stdout, "%c", (char)pop ()); + fflush (stdout); + } else + { +#ifdef CONSOLE + int x, y; + long int p = pop(); + char t[172]; + x = wherex(); + y = wherey(); + gettext(2, DEBUGROW, 80, DEBUGROW, t); + puttext(1, DEBUGROW, 79, DEBUGROW, t); + gotoxy(80, DEBUGROW); + if ((p >= 32) && (p <= 255)) + { + putch((int)p); + } else + { + if (p == 10) + { + putch(179); + } else + { + putch(168); + } + } + gotoxy(x, y); +#endif /* CONSOLE */ + } + } + } + break; + case '"': /* Toggle String Mode */ + stringmode = !stringmode; + break; + case ':': /* Duplicate */ + { + signed long a = pop (); + push (a); + push (a); + } + break; + case '!': /* Negate */ + if (pop()) + push(0); + else + push(1); + break; + case '`': + { + signed long b = pop (); + signed long a = pop (); + push (a > b); + } + break; + case '#': /* Bridge */ + x += dx; + y += dy; + break; + case '$': /* Pop and Discard */ + pop (); + break; + case '?': /* Random Redirect */ + switch ((rand () / 32) % 4) + { + case 0: + dx = 1; + dy = 0; + break; + case 1: + dx = -1; + dy = 0; + break; + case 2: + dx = 0; + dy = -1; + break; + case 3: + dx = 0; + dy = 1; + break; + } + break; + case '&': /* Input Integer */ + { + signed long b; + if (infile) + { + fscanf (fi, "%ld", &b); + push (b); + } else + { + if (!debug) + { + fscanf (stdin, "%ld", &b); + push (b); + } else + { +#ifdef CONSOLE + int x, y; + long int p; + char t[172]; + x = wherex(); + y = wherey(); + gettext(10, DEBUGROW, 80, DEBUGROW, t); + puttext(1, DEBUGROW, 71, DEBUGROW, t); + gotoxy(72, DEBUGROW); + clreol(); + cscanf("%ld", &p); + push(p); + gotoxy(x, y); +#endif /* CONSOLE */ + } + } + } + break; + case '~': /* Input ASCII */ + { + char c; + if (infile) + { + c = fgetc (fi); + push (c); + } else + { + if (!debug) + { + c = fgetc (stdin); + push (c); + } else + { +#ifdef CONSOLE + int x, y; + long int p; + char t[172]; + x = wherex(); + y = wherey(); + gettext(2, DEBUGROW, 80, DEBUGROW, t); + puttext(1, DEBUGROW, 79, DEBUGROW, t); + gotoxy(80, DEBUGROW); + clreol(); + p = getche(); + if (p == '\r') + { + p = '\n'; + gotoxy(80, DEBUGROW); + putch(179); + } + push(p); + gotoxy(x, y); +#endif /* CONSOLE */ + } + } + } + break; + case 'g': /* Get Value */ + { + signed long y = pop (), x = pop (); + if ((y < PAGEHEIGHT) && (y >= 0) && (x < LINEWIDTH) && (x >= 0)) + { + push (cur); + } else + { + if (!debug) + { + if (!quiet) + { + fprintf(stderr, "g 'Get' instruction out of bounds (%ld,%ld)\n", x, y); + } + } + push (0); + } + } + break; + case 'p': /* Put Value */ + { + signed long y = pop (), x = pop (); + if ((y < PAGEHEIGHT) && (y >= 0) && (x < LINEWIDTH) && (x >= 0)) + { + cur = pop (); + } else + { + if (!debug) + { + if (!quiet) + { + fprintf(stderr, "p 'Put' instruction out of bounds (%ld,%ld)\n", x, y); + } + } + pop(); + } + if ((debug) && (y < SCREENHEIGHT) && (x < SCREENWIDTH)) + { +#ifdef CONSOLE + gotoxy(x+1,y+1); +#else + printf ("%c[%d;%dH", 27, (int)(y+1), (int)(x+1)); +#endif /* CONSOLE */ + if (isprint (cur)) printf ("%c", cur); else printf("."); + } + } + break; + case ' ': + break; + default: + if ((!debug) && (!ignore_unsupported) && (!quiet)) + { + fprintf(stderr, "Unsupported instruction '%c' (0x%02x) (maybe not Befunge-93?)\n", cur, cur); + } + break; + } + x += dx; + y += dy; + if (x < 0) + if (v10err_compat) + { + x = LINEWIDTH; + } else + { + x = LINEWIDTH - 1; + } + else + x = x % LINEWIDTH; + if (y < 0) + if (v10err_compat) + { + y = PAGEHEIGHT; + } else + { + y = PAGEHEIGHT - 1; + } + else + y = y % PAGEHEIGHT; + if (stackfile) + { + struct stack *s; + for (s = head; s; s = s->next) + fprintf(fs, "%ld ", s->val); + fprintf(fs, "\n"); + fflush(fs); + } + } + +#ifdef CONSOLE +the_end: +#endif /* CONSOLE */ + + while (head != NULL) { pop(); } + if (fi != NULL) fclose (fi); + if (fo != NULL) fclose (fo); + if (fs != NULL) fclose (fs); + + if (debug) + { +#ifdef CONSOLE +# ifdef CURSORSHAPE + _setcursortype(_NORMALCURSOR); +# endif /* CURSORSHAPE */ + gotoxy(1,22); +#else + printf ("%c[22;1H", 27); +#endif /* CONSOLE */ + } + + exit (0); + return 0; +} + +/* + * pushes a value onto the stack. + */ +void push (val) + signed long val; +{ + struct stack *s; + s = (struct stack *) malloc (sizeof (struct stack)); + s->val = val; + s->next = head; + head = s; +} + +/* + * pops a value off the stack. returns 0 in case of underflow. + */ +signed long pop () +{ + signed long v; + struct stack *s = head; + if (s) + { + v = head->val; + head = head->next; + free (s); + return v; + } else + { + return 0; + } +}