comparison 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
comparison
equal deleted inserted replaced
995:6883f5911eb7 996:859f9b4339e6
1 /* ******************************************************************
2
3 bef.c - The Original Befunge-93 Interpreter/Debugger in ANSI C
4 v2.21 Sep 20 2004 Chris Pressey, Cat's-Eye Technologies
5
6 Copyright (c)1993-2004, Cat's Eye Technologies.
7 All rights reserved.
8
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12
13 Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15
16 Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in
18 the documentation and/or other materials provided with the
19 distribution.
20
21 Neither the name of Cat's Eye Technologies nor the names of its
22 contributors may be used to endorse or promote products derived
23 from this software without specific prior written permission.
24
25 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
26 CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
27 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
30 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
31 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
33 OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
34 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
35 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 POSSIBILITY OF SUCH DAMAGE.
38
39 ******************************************************************
40
41 Usage :
42
43 bef [-d] [-o] [-q] [-i] [-=]
44 [-r input-file] [-w output-file]
45 [-s stack-file] [-y delay] <befunge-source>
46
47 -d: visual ANSI debugging display
48 -o: do not fix off-by-one error (for old sources)
49 -q: produce no output except Befunge program output ('quiet')
50 -i: ignore unsupported instructions
51 -=: use b97-ish = directives
52 -r: redirect input from a specified file instead of stdin
53 -w: redirect output to a specified file instead of stdout
54 -s: write contents of stack to log file
55 -y: specify debugging delay in milliseconds
56
57 Compiles Under:
58
59 Borland C++ v3.1 (16-bit MS-DOS)
60 DJGPP v2.952 (32-bit Protected-Mode MS-DOS)
61 Mingw v2.
62
63 ******************************************************************
64
65 v2.21: Sep 2004, Chris Pressey
66 display correct version number
67 cleanup only, no functional changes
68
69 v2.20, Jul 2000, Chris Pressey
70 prettied up preprocessor directives a bit
71 added defines for Metroworks CodeWarrior
72 so that bef will build on MacOS
73 relicensed under BSD
74
75 v2.12, Mar 1998, Chris Pressey / compiles under Borland C++ v3.1
76 added -i and -= options. You must specify -= if
77 you want to use b97-esque directives or the Un*x-ish
78 # comment thing, or both.
79 automatically appends '.bf' to filenames containing no periods.
80 explicitly pops remaining stack elements at end of execution.
81 compatibility messages are displayed when quiet is not specified.
82 debug mode is much improved, especially I/O under BorlandC.
83 bounds checking on 'p' and 'g' instructions.
84
85 v2.11, Jan 1998, Chris Pressey / compiles under Borland C++ v3.1
86 divide by zero now produces the correct result
87 improved some minor aesthetic features (messages & debug)
88 ANSI is used only if not compiling under Borland C.
89
90 v2.10: Jul 1997, Chris Pressey
91 added -q command line option.
92 added primitive understanding of = directive from b97 spec.
93 any file with a =l directive but without =l b93 is rejected.
94 also understands # as a pre-directive line prefix for
95 Un*x-ish systems.
96
97 v2.02: Jun 1997, Chris Pressey
98 pads playfield with space characters. all unread
99 locations remain spaces.
100
101 v2.01: Jun 1997, Chris Pressey
102 command line switches are not case-insensitive.
103 fixes gcc Segmentation Fault error.
104
105 v2.00: Jun 1997, Chris Pressey
106 combines interpreter and debugger.
107 fixes ANSI error in debugger.
108 v1.02: Feb 1996, Chris Pressey
109 @ now pushes '@' onto the stack in stringmode instead of quitting.
110
111 v1.01: Feb 1996, Chris Pressey
112 fixes off-by-one error.
113
114 v1.00: Sept 1993, Chris Pressey
115 original Befunge-93 distribution.
116
117 ****************************************************************** */
118
119 /********************************************************* #PRAGMA'S */
120
121 /* This switches Borland C++ v3.1 to small memory model */
122 #ifdef __BORLANDC__
123 #pragma option -ms
124 #endif /* __BORLANDC__ */
125
126 /********************************************************* #INCLUDE'S */
127
128 #include <stdio.h>
129 #include <string.h>
130 #include <stdlib.h>
131 #include <ctype.h>
132 #include <time.h>
133 #ifdef __BORLANDC__
134 # include <dos.h>
135 # include <conio.h>
136 # define CONSOLE 1
137 # define CURSORSHAPE 1
138 #endif /* __BORLANDC__ */
139 #ifdef __MWERKS__
140 # include <console.h>
141 # define CONSOLE 1
142 #endif /* __MWERKS__ */
143
144 /********************************************************** #DEFINE'S */
145
146 #define LINEWIDTH 80
147 #define PAGEHEIGHT 25
148
149 #define SCREENWIDTH 79
150 #define SCREENHEIGHT 22
151
152 #define DEBUGROW 24
153 #define cur pg[y * LINEWIDTH + x]
154
155 /********************************************************* STRUCTURES */
156
157 struct stack /* stack structure, for values on stack */
158 {
159 signed long val;
160 struct stack *next;
161 } * head; /* head of stack */
162
163 /*************************************************** GLOBAL VARIABLES */
164
165 char pg[LINEWIDTH * PAGEHEIGHT]; /* befunge 'page' of source */
166 int x = 0, y = 0; /* x and y of the PC */
167 int dx = 1, dy = 0; /* direction of the PC */
168 int debug = 0; /* flag : display ANSI debugging? */
169 int infile = 0, ia; /* flag : use input file, and assoc arg? */
170 int outfile = 0, oa; /* flag : use output file, and assoc arg? */
171 int stackfile = 0, sa; /* flag : use stack log file, & assoc arg? */
172 int stringmode = 0; /* flag : are we in string mode? */
173 int quiet = 0; /* flag : are we quiet? */
174 int v10err_compat = 0; /* flag : emulate v1.0 off-by-one err? */
175 int deldur = 25; /* debugging delay in milliseconds */
176 int ignore_unsupported = 0; /* flag : ignore unsupported instructions? */
177 int use_b97directives = 0; /* flag : use b97-esque directives? */
178
179 /********************************************************* PROTOTYPES */
180
181 void push (signed long val);
182 signed long pop (void);
183
184 /******************************************************* MAIN PROGRAM */
185
186 int main (argc, argv)
187 int argc;
188 char **argv;
189 {
190 FILE *f=NULL;
191 FILE *fi=NULL;
192 FILE *fo=NULL;
193 FILE *fs=NULL;
194 int i;
195 char filename[128];
196
197 #ifdef __MWERKS__
198 argc = ccommand(&argv);
199 #endif /* __MWERKS__ */
200
201 srand((unsigned)time(0));
202
203 if (argc < 2)
204 {
205 printf ("USAGE: bef [-d] [-o] [-q] [-i] [-=]\n");
206 printf (" [-r input] [-w output] [-s stack] [-y delay] foo.bf\n");
207 exit (0);
208 }
209 for (i = 1; i < argc; i++)
210 {
211 if (!strcmp(argv[i], "-o")) { v10err_compat = 1; }
212 if (!strcmp(argv[i], "-d")) { debug = 1; }
213 if (!strcmp(argv[i], "-r")) { infile = 1; ia = i + 1; }
214 if (!strcmp(argv[i], "-w")) { outfile = 1; oa = i + 1; }
215 if (!strcmp(argv[i], "-s")) { stackfile = 1; sa = i + 1; }
216 if (!strcmp(argv[i], "-y")) { deldur = atoi(argv[i + 1]); }
217 if (!strcmp(argv[i], "-q")) { quiet = 1; }
218 if (!strcmp(argv[i], "-i")) { ignore_unsupported = 1; }
219 if (!strcmp(argv[i], "-=")) { use_b97directives = 1; }
220 }
221 if (!quiet)
222 {
223 //printf ("Befunge-93 Interpreter/Debugger v2.21\n");
224 }
225
226 memset(pg, ' ', LINEWIDTH * PAGEHEIGHT);
227
228 strcpy(filename, argv[argc - 1]);
229 if (strchr(filename, '.') == NULL)
230 {
231 strcat(filename, ".bf");
232 }
233
234 if ((f = fopen (filename, "r")) != NULL) /*** Input Phase */
235 {
236 int x = 0, y = 0;
237 char dc = '=', tc = ' ';
238 int tt = 0; char s[80];
239 int accept_pound = 1;
240
241 while (!feof (f))
242 {
243 cur = fgetc (f);
244 if (use_b97directives && (x == 0) && ((cur == dc) || ((accept_pound) && (cur == '#'))))
245 {
246 if (cur != '#') accept_pound = 0;
247 tc = fgetc (f);
248 if (tc == 'l')
249 {
250 while (tc != ' ')
251 {
252 tc = fgetc (f);
253 }
254 while (tc != '\n')
255 {
256 tc = fgetc (f);
257 if (tc != '\n') { s[tt++] = tc; s[tt] = (char)0; }
258 }
259 if (strcmp(s, "b93"))
260 {
261 fprintf(stderr, "Error: only Befunge-93 (not %s) sources are supported by BEF.\n", s);
262 exit(10);
263 }
264 }
265 while (tc != '\n')
266 {
267 tc = fgetc (f);
268 }
269 } else
270 {
271 accept_pound = 0;
272 if (cur == '\n')
273 {
274 cur = ' ';
275 x = 0;
276 y++;
277 if (y >= PAGEHEIGHT) break;
278 } else
279 {
280 x++;
281 if (x >= LINEWIDTH)
282 {
283 x = 0;
284 y++;
285 if (y >= PAGEHEIGHT) break;
286 }
287 }
288 }
289 }
290 fclose (f);
291 } else
292 {
293 printf ("Error: couldn't open '%s' for input.\n", filename);
294 exit (0);
295 }
296
297 if (infile)
298 {
299 if (!(fi = fopen (argv[ia], "r")))
300 {
301 printf ("Error : couldn't open '%s' for input.\n", argv[ia]);
302 exit (0);
303 }
304 }
305
306 if (outfile)
307 {
308 if (!(fo = fopen (argv[oa], "w")))
309 {
310 printf ("Error : couldn't open '%s' for output.\n", argv[oa]);
311 exit (0);
312 }
313 }
314
315 if (stackfile)
316 {
317 if (!(fs = fopen (argv[sa], "w")))
318 {
319 printf ("Error : couldn't open '%s' for output.\n", argv[sa]);
320 exit (0);
321 }
322 }
323
324 if (debug)
325 {
326
327 #ifdef CONSOLE
328 clrscr();
329 # ifdef CURSORSHAPE
330 _setcursortype(_NOCURSOR);
331 # endif /* CURSORSHAPE */
332 #else
333 printf ("%c[1;1H", 27);
334 printf ("%c[2J", 27);
335 #endif /* CONSOLE */
336
337 for(y = 0; y < SCREENHEIGHT; y++)
338 {
339 for(x = 0; x < SCREENWIDTH; x++)
340 {
341 if (isprint(cur))
342 {
343 printf("%c", cur);
344 }
345 }
346 printf("\n");
347 }
348
349 x = y = 0;
350
351 #ifdef CUSRORSHAPE
352 _setcursortype(_SOLIDCURSOR);
353 #endif /* CUSRORSHAPE */
354
355 }
356
357 while ((cur != '@') || (stringmode)) /*** Intepreting Phase */
358 {
359 if (debug)
360 {
361 if ((y < SCREENHEIGHT) && (x < SCREENWIDTH))
362 {
363 #ifdef CONSOLE
364 gotoxy(x+1, y+1);
365 if (kbhit())
366 {
367 char c;
368 /* ideally, pop up a debugging tool. for now, exit. */
369 c = getch();
370 if (c == 0)
371 {
372 c = getch();
373 } else
374 {
375 if (c == 27)
376 {
377 /* pause */
378 c = getch();
379 if (c == 0)
380 {
381 c = getch();
382 } else
383 {
384 if (c == 27)
385 {
386 goto the_end;
387 }
388 }
389 }
390 }
391 }
392 #else
393 printf ("%c[%d;%dH", 27, y+1, x+1);
394 fflush (stdout);
395 #endif /* CONSOLE */
396 }
397 #if __BORLANDC__
398 delay (deldur);
399 #endif /* __BORLANDC __ */
400 }
401 if (stringmode && (cur != '"'))
402 push (cur);
403 else if (isdigit (cur))
404 push (cur - '0');
405 else
406 switch (cur)
407 {
408 case '>': /* PC Right */
409 dx = 1;
410 dy = 0;
411 break;
412 case '<': /* PC Left */
413 dx = -1;
414 dy = 0;
415 break;
416 case '^': /* PC Up */
417 dx = 0;
418 dy = -1;
419 break;
420 case 'v': /* PC Down */
421 dx = 0;
422 dy = 1;
423 break;
424 case '|': /* Vertical 'If' */
425 dx = 0;
426 if (pop ())
427 dy = -1;
428 else
429 dy = 1;
430 break;
431 case '_': /* Horizontal 'If' */
432 dy = 0;
433 if (pop ())
434 dx = -1;
435 else
436 dx = 1;
437 break;
438 case '+': /* Add */
439 push (pop () + pop ());
440 break;
441 case '-': /* Subtract */
442 {
443 long a = pop();
444 long b = pop();
445 push(b - a);
446 }
447 break;
448 case '*': /* Multiply */
449 push (pop () * pop ());
450 break;
451 case '/': /* Integer Divide */
452 {
453 signed long a = pop ();
454 signed long b = pop ();
455 if (a == 0)
456 {
457 if (!outfile)
458 {
459 printf("What do you want %ld/0 to be? ", b);
460 } else
461 {
462 fprintf(fo, "What do you want %ld/0 to be? ", b);
463 }
464 if (infile)
465 {
466 fscanf (fi, "%ld", &b);
467 push (b);
468 } else
469 {
470 if (!debug)
471 {
472 fscanf (stdin, "%ld", &b);
473 push (b);
474 }
475 }
476 } else
477 {
478 push (b / a);
479 }
480 }
481 break;
482 case '%': /* Modulo */
483 {
484 signed long a = pop ();
485 signed long b = pop ();
486 push (b % a);
487 }
488 break;
489 case '\\': /* Swap */
490 {
491 signed long a = pop ();
492 signed long b = pop ();
493 push (a);
494 push (b);
495 }
496 break;
497 case '.': /* Pop Out Integer */
498 {
499 if (outfile)
500 {
501 fprintf (fo, "%ld ", pop ());
502 fflush (fo);
503 } else
504 {
505 if (!debug)
506 {
507 fprintf (stdout, "%ld ", pop ());
508 fflush (stdout);
509 } else
510 {
511 #ifdef CONSOLE
512 int x, y;
513 char s[172], t[172];
514 x = wherex();
515 y = wherey();
516 sprintf(s, "%ld ", pop());
517 gettext(1+strlen(s), DEBUGROW, 80, DEBUGROW, t);
518 puttext(1, DEBUGROW, 80-strlen(s), DEBUGROW, t);
519 gotoxy(81-strlen(s), DEBUGROW);
520 cputs(s);
521 gotoxy(x, y);
522 #endif /* CONSOLE */
523 }
524 }
525 }
526 break;
527 case ',': /* Pop Out ASCII */
528 {
529 if (outfile)
530 {
531 fprintf (fo, "%c", (char)pop ());
532 fflush (fo);
533 } else
534 {
535 if (!debug)
536 {
537 fprintf (stdout, "%c", (char)pop ());
538 fflush (stdout);
539 } else
540 {
541 #ifdef CONSOLE
542 int x, y;
543 long int p = pop();
544 char t[172];
545 x = wherex();
546 y = wherey();
547 gettext(2, DEBUGROW, 80, DEBUGROW, t);
548 puttext(1, DEBUGROW, 79, DEBUGROW, t);
549 gotoxy(80, DEBUGROW);
550 if ((p >= 32) && (p <= 255))
551 {
552 putch((int)p);
553 } else
554 {
555 if (p == 10)
556 {
557 putch(179);
558 } else
559 {
560 putch(168);
561 }
562 }
563 gotoxy(x, y);
564 #endif /* CONSOLE */
565 }
566 }
567 }
568 break;
569 case '"': /* Toggle String Mode */
570 stringmode = !stringmode;
571 break;
572 case ':': /* Duplicate */
573 {
574 signed long a = pop ();
575 push (a);
576 push (a);
577 }
578 break;
579 case '!': /* Negate */
580 if (pop())
581 push(0);
582 else
583 push(1);
584 break;
585 case '`':
586 {
587 signed long b = pop ();
588 signed long a = pop ();
589 push (a > b);
590 }
591 break;
592 case '#': /* Bridge */
593 x += dx;
594 y += dy;
595 break;
596 case '$': /* Pop and Discard */
597 pop ();
598 break;
599 case '?': /* Random Redirect */
600 switch ((rand () / 32) % 4)
601 {
602 case 0:
603 dx = 1;
604 dy = 0;
605 break;
606 case 1:
607 dx = -1;
608 dy = 0;
609 break;
610 case 2:
611 dx = 0;
612 dy = -1;
613 break;
614 case 3:
615 dx = 0;
616 dy = 1;
617 break;
618 }
619 break;
620 case '&': /* Input Integer */
621 {
622 signed long b;
623 if (infile)
624 {
625 fscanf (fi, "%ld", &b);
626 push (b);
627 } else
628 {
629 if (!debug)
630 {
631 fscanf (stdin, "%ld", &b);
632 push (b);
633 } else
634 {
635 #ifdef CONSOLE
636 int x, y;
637 long int p;
638 char t[172];
639 x = wherex();
640 y = wherey();
641 gettext(10, DEBUGROW, 80, DEBUGROW, t);
642 puttext(1, DEBUGROW, 71, DEBUGROW, t);
643 gotoxy(72, DEBUGROW);
644 clreol();
645 cscanf("%ld", &p);
646 push(p);
647 gotoxy(x, y);
648 #endif /* CONSOLE */
649 }
650 }
651 }
652 break;
653 case '~': /* Input ASCII */
654 {
655 char c;
656 if (infile)
657 {
658 c = fgetc (fi);
659 push (c);
660 } else
661 {
662 if (!debug)
663 {
664 c = fgetc (stdin);
665 push (c);
666 } else
667 {
668 #ifdef CONSOLE
669 int x, y;
670 long int p;
671 char t[172];
672 x = wherex();
673 y = wherey();
674 gettext(2, DEBUGROW, 80, DEBUGROW, t);
675 puttext(1, DEBUGROW, 79, DEBUGROW, t);
676 gotoxy(80, DEBUGROW);
677 clreol();
678 p = getche();
679 if (p == '\r')
680 {
681 p = '\n';
682 gotoxy(80, DEBUGROW);
683 putch(179);
684 }
685 push(p);
686 gotoxy(x, y);
687 #endif /* CONSOLE */
688 }
689 }
690 }
691 break;
692 case 'g': /* Get Value */
693 {
694 signed long y = pop (), x = pop ();
695 if ((y < PAGEHEIGHT) && (y >= 0) && (x < LINEWIDTH) && (x >= 0))
696 {
697 push (cur);
698 } else
699 {
700 if (!debug)
701 {
702 if (!quiet)
703 {
704 fprintf(stderr, "g 'Get' instruction out of bounds (%ld,%ld)\n", x, y);
705 }
706 }
707 push (0);
708 }
709 }
710 break;
711 case 'p': /* Put Value */
712 {
713 signed long y = pop (), x = pop ();
714 if ((y < PAGEHEIGHT) && (y >= 0) && (x < LINEWIDTH) && (x >= 0))
715 {
716 cur = pop ();
717 } else
718 {
719 if (!debug)
720 {
721 if (!quiet)
722 {
723 fprintf(stderr, "p 'Put' instruction out of bounds (%ld,%ld)\n", x, y);
724 }
725 }
726 pop();
727 }
728 if ((debug) && (y < SCREENHEIGHT) && (x < SCREENWIDTH))
729 {
730 #ifdef CONSOLE
731 gotoxy(x+1,y+1);
732 #else
733 printf ("%c[%d;%dH", 27, (int)(y+1), (int)(x+1));
734 #endif /* CONSOLE */
735 if (isprint (cur)) printf ("%c", cur); else printf(".");
736 }
737 }
738 break;
739 case ' ':
740 break;
741 default:
742 if ((!debug) && (!ignore_unsupported) && (!quiet))
743 {
744 fprintf(stderr, "Unsupported instruction '%c' (0x%02x) (maybe not Befunge-93?)\n", cur, cur);
745 }
746 break;
747 }
748 x += dx;
749 y += dy;
750 if (x < 0)
751 if (v10err_compat)
752 {
753 x = LINEWIDTH;
754 } else
755 {
756 x = LINEWIDTH - 1;
757 }
758 else
759 x = x % LINEWIDTH;
760 if (y < 0)
761 if (v10err_compat)
762 {
763 y = PAGEHEIGHT;
764 } else
765 {
766 y = PAGEHEIGHT - 1;
767 }
768 else
769 y = y % PAGEHEIGHT;
770 if (stackfile)
771 {
772 struct stack *s;
773 for (s = head; s; s = s->next)
774 fprintf(fs, "%ld ", s->val);
775 fprintf(fs, "\n");
776 fflush(fs);
777 }
778 }
779
780 #ifdef CONSOLE
781 the_end:
782 #endif /* CONSOLE */
783
784 while (head != NULL) { pop(); }
785 if (fi != NULL) fclose (fi);
786 if (fo != NULL) fclose (fo);
787 if (fs != NULL) fclose (fs);
788
789 if (debug)
790 {
791 #ifdef CONSOLE
792 # ifdef CURSORSHAPE
793 _setcursortype(_NORMALCURSOR);
794 # endif /* CURSORSHAPE */
795 gotoxy(1,22);
796 #else
797 printf ("%c[22;1H", 27);
798 #endif /* CONSOLE */
799 }
800
801 exit (0);
802 return 0;
803 }
804
805 /*
806 * pushes a value onto the stack.
807 */
808 void push (val)
809 signed long val;
810 {
811 struct stack *s;
812 s = (struct stack *) malloc (sizeof (struct stack));
813 s->val = val;
814 s->next = head;
815 head = s;
816 }
817
818 /*
819 * pops a value off the stack. returns 0 in case of underflow.
820 */
821 signed long pop ()
822 {
823 signed long v;
824 struct stack *s = head;
825 if (s)
826 {
827 v = head->val;
828 head = head->next;
829 free (s);
830 return v;
831 } else
832 {
833 return 0;
834 }
835 }