git @ Cat's Eye Technologies Befunge-93 / master historic / bef-1.0rc2 / bef.c
master

Tree @master (Download .tar.gz)

bef.c @masterraw · history · blame

/*

   bef.c
   Befunge Interpreter - v1.0, Sept 1993, Chris Pressey

   usage :

   bef <befunge-source>

   compilation :

   Amiga : dcc bef.c -o bef
   Unix  : acc bef.c -o bef

 */

/********************************************************* #INCLUDE'S */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include <catseye.h>

/********************************************************** #DEFINE'S */

#define LINEWIDTH  80		/* 0 .. 79 */
#define PAGEHEIGHT 25		/* 0 .. 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 stringmode = 0;		/* flag : are we in string mode? */

/********************************************************* PROTOTYPES */

void push (signed long val);
signed long pop ();

/******************************************************* MAIN PROGRAM */

main (argc, argv)
     int argc;
     char **argv;
{
  FILE *f;
  srand (time (0));

  if (argc < 2)
    {
      printf ("USAGE : %s <befunge-source>\n", argv[0]);
      exit (0);
    }
  if (f = fopen (argv[1], "r"))			      /*** Input Phase */
    {
      int x = 0, y = 0;
      while (!feof (f))
	{
	  cur = fgetc (f);
	  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", argv[1]);
      exit (0);
    }

  while (cur != '@')				/*** Intepreting Phase */
    {
      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 */
	     push (-1 * (pop () - pop ()));
	     break;
	   case '*':		/* Multiply */
	     push (pop () * pop ());
	     break;
	   case '/':		/* Integer Divide */
	     {
	       int a = pop ();
	       int b = pop ();
	       push (b / a);
	     }
	     break;
	   case '%':		/* Modulo */
	     {
	       int a = pop ();
	       int b = pop ();
	       push (b % a);
	     }
	     break;
	   case '\\':		/* Swap */
	     {
	       int a = pop ();
	       int b = pop ();
	       push (a);
	       push (b);
	     }
	     break;
	   case '.':		/* Pop Out Integer */
	     printf ("%ld ", pop ());
	     fflush (stdout);
	     break;
	   case ',':		/* Pop Out ASCII */
	     printf ("%c", pop ());
	     fflush (stdout);
	     break;
	   case '"':		/* Toggle String Mode */
	     stringmode = !stringmode;
	     break;
	   case ':':		/* Duplicate */
	     {
	       int a = pop ();
	       push (a);
	       push (a);
	     }
	     break;
	   case '!':		/* Negate */
	     push (!pop ());
	     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;
	       fscanf (stdin, "%ld", &b);
	       push (b);
	     }
	     break;
	   case '~':		/* Input ASCII */
	     {
	       char c = fgetc (stdin);
	       push (c);
	     }
	     break;
	   case 'g':		/* Get Value */
	     {
	       int y = pop (), x = pop ();
	       push (cur);
	     }
	     break;
	   case 'p':		/* Put Value */
	     {
	       int y = pop (), x = pop ();
	       cur = pop ();
	     }
	     break;
	   default:
	     break;
	   }
      x += dx;
      y += dy;
    }
  exit (0);
}

/*
 * pushes a value onto the stack.
 */
void
  push (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;
    }
}