head	1.7;
access;
symbols;
locks
	hmaon:1.7; strict;
comment	@ * @;


1.7
date	2002.01.28.16.46.37;	author hmaon;	state Exp;
branches;
next	1.6;

1.6
date	2002.01.28.15.44.38;	author hmaon;	state Exp;
branches;
next	1.5;

1.5
date	2001.02.02.17.04.24;	author hmaon;	state Exp;
branches;
next	1.4;

1.4
date	99.10.10.00.59.02;	author gvelicha;	state Exp;
branches;
next	1.3;

1.3
date	99.10.10.00.57.24;	author gvelicha;	state Exp;
branches;
next	1.2;

1.2
date	99.10.09.00.03.19;	author gvelicha;	state Exp;
branches;
next	1.1;

1.1
date	99.10.08.23.55.05;	author gvelicha;	state Exp;
branches;
next	;


desc
@hbefunge interpreter, by hmaon
@


1.7
log
@The 'p' opcode now clamps to a signed byte for Befunge-93 code.
This allows chess to run :)
@
text
@/* copyright 1999 Greg Velichansky */
/* This work is publically displayed for your personal amusement.
   Use of this work for any commercial or otherwise for-profit purposes without
   permission of the autor is prohibited. Inclusion of this work in any non-GPL 
   projects without the author's permission is prohibited. */
/* this program is guaranteed not to be suitable for any particular purpose */
/* talk to me. hmaon@@bumba.net */
/* greets to building and badzen. keep the flame alive. */

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

#ifndef PLEASECOMPILE
#error Not in the mood to compile right now.
#endif

#include "befunge.h"


int tick = 0, noptick = 0, stringtick = 0, btrace = 0;


void strepl (stackt *i, int n) {
	i -> stack [i -> sp] = n;
}

void breplace (bef_interp *i, int n) {
	strepl (i -> stack, n);
}
	
void stpush (stackt *i, int n) {
	static int overflow = 0;
	if (i -> sp < i -> stacksize - 1) {
		i -> sp ++;
	} else {
		if (!overflow) {
			fprintf (stderr, "stack overflow (only reported once)\n");
			overflow = -1;
		}
	}
	i -> stack [i -> sp] = n;
}


void push (bef_interp *i, int n) {
	stpush (i -> stack, n);
}


int stpeek (stackt *i) {
	return (i -> stack) [i -> sp];
}

int bpeek (bef_interp *i) {
	return stpeek (i -> stack);
}

int stpop (stackt *i) {
	register int n;
	n = (i -> stack) [i -> sp];
	if (i -> sp > 0) {
		if (btrace) printf ("i -> sp == %d, dec pending.\n", i -> sp);
		i -> sp --;
	}
	return n;
}

int pop (bef_interp *i) {
	return stpop (i -> stack);
}

int stdig (stackt *i, int depth) {
	static int underflow = 0;
	int from;

	from = i -> sp - depth;
	if (from < 0 || from > i -> stacksize - 1) {
		if (!underflow) {
			fprintf (stderr, "stdig() stack underflow (only reported once)");
			underflow = -1;
		}
		return stpeek (i);
	}
	return (i -> stack) [from];
}



void bef_checkpc (bef_interp *i) {
	if (i -> ip .x >= i -> size .x) i -> ip .x = 0;
	if (i -> ip .y >= i -> size .y) i -> ip .y = 0;

	if (i -> ip .x < 0) i -> ip .x = i -> size .x - 1;
	if (i -> ip .y < 0) i -> ip .y = i -> size .y - 1;
}


void bef_walk (bef_interp *i) {
	i -> ip .x += i -> delta .x;
	i -> ip .y += i -> delta .y;

	if (i -> ip .x >= i -> size .x) i -> ip .x = 0;
	if (i -> ip .y >= i -> size .y) i -> ip .y = 0;

	if (i -> ip .x < 0) i -> ip .x = i -> size .x - 1;
	if (i -> ip .y < 0) i -> ip .y = i -> size .y - 1;
}

void bef_do (bef_interp *i, char c) {
	int n, m, o;
	char *tmp;
	char t;
	char numtemp[2] = "0";
	stackt *tmpstack;


	if (isxdigit ((int) c)) {
		numtemp[0] = c;
		o = strtoul (numtemp, NULL, 16);
		push (i, o);
		return;
	}
		
		

	switch (c) {
	case ' ':
		++noptick;
		break;

	case '+':
		n = pop (i);
		m = pop (i);
		push (i, m + n);
		break;

	case '-':
		n = pop (i);
		m = pop (i);
		push (i, m - n);
		break;

	case '*':
		n = pop (i);
		m = pop (i);
		push (i, m * n);
		break;

	case '/':
		n = pop (i);
		m = pop (i);
		push (i, m / n);
		break;

	case '%':
		n = pop (i);
		m = pop (i);
		push (i, m % n);
		break;

	case '!':
		if (pop (i)) {
			push (i, 0);
		} else  push (i, 1);
		break;

	case '`':
		n = pop (i);
		m = pop (i);
		if (m > n) {
			push (i, 1);
		} else  push (i, 0);
		break;

	case '>':
		i -> delta .x = 1;
		i -> delta .y = 0;
		break;

	case '<':
		i -> delta .x = -1;
		i -> delta .y = 0;
		break;

	case '^':
		i -> delta .x = 0;
		i -> delta .y = -1;
		break;

	case 'v':
		i -> delta .x = 0;
		i -> delta .y = 1;
		break;

	case '?':
		n = random () % 4;
		tmp = "<>^v";
		t = tmp[n];
		bef_do (i, t); 
		break;

	case '_':
		if (pop (i)) {
			i -> delta .x = -1;
		} else  i -> delta .x = 1;
		i -> delta .y = 0;
		break;

	case '|':
		if (pop (i)) {
			i -> delta .y = -1;
		} else  i -> delta .y = 1;
		i -> delta .x = 0;
		break;

	case '"':
		i -> mode = i -> mode ^ mSTRING;
		if (btrace) puts ("mode change mSTRING");
		break;

	case ':':
		if (!btrace ) {
			push (i, bpeek (i));
		} else {
			o = bpeek (i);
			printf ("dup: %c  (%d)\n", o, o);
			push (i, o);
		}
		break;

	case '\\':
		n = pop (i);
		m = pop (i);
		push (i, n);
		push (i, m);
		break;

	case '$':
		m = pop (i);
		break;

	case '.':
		printf ("%d ", pop (i));
		fflush (stdout);
		break;

	case ',':
		o = pop (i);
		o = o ? o : ' ';
		printf ("%c", o);
		/*fflush (stdout);*/
		break;

	case '#':
		bef_walk (i);
		break;

	case 'g':
		n = pop (i); /* y */
		m = pop (i); /* x */
		if (n < 0 || n >= i -> size .y || m < 0 || m >= i -> size .x) {
			printf ("%d, %d out of bounds at %d, %d\n", m, n, i -> ip .x, i -> ip .y);
			o = 0;
		} else  o = i -> mem [n][m];
		push (i, o);
		break;

	case 'p':
		n = pop (i);
		m = pop (i);
		o = pop (i);
		if (btrace) printf("%d -> %d,%d", o, m, n);
		if (n < 0 || n >= i -> size .y || m < 0 || m >= i -> size .x) {
			printf ("%d, %d out of bounds at %d, %d\n", m, n, i -> ip .x, i -> ip .y);
		} else {
			signed char co = o;
			i -> mem[n][m] = (i -> mode && m93) ? co : o;
		}
		break;

	case '&':
		/*scanf ("%i%*1[\n]", &o);*/
		scanf ("%i", &o);
		push (i, o);
		break;

	case '~':
		/*fflush (stdin);*/
		o = getchar ();
		if (o == EOF) puts ("EOF on getchar()");
		push (i, o);
		break;

	case '@@':
		i -> mode |= mTERM;
		break;

#ifndef STRICTBEF93
	
	case 'j':
		n = pop (i);
		m = pop (i);
		if (btrace) printf ("from (%d,%d) to (%d,%d)\n", i -> ip.x, i -> ip.y, m, n);
		i -> ip .x = m;
		i -> ip .y = n;
		bef_checkpc (i);
		i -> teleport = -1;
		break;

	case 'J':
		n = pop (i);
		m = pop (i);
		i -> ip .x = m;	
		i -> ip .y = n;
		bef_checkpc (i);
		n = pop (i);
		m = pop (i);
		i -> delta .x = m;
		i -> delta .y = n;
		i -> teleport = -1;
		break;

	case '[':
		o = i -> delta .x * (-1);
		i -> delta .x = i -> delta .y;	
		i -> delta .y = o;
		break;

	case ']':
		o = i -> delta .y * (-1);
		i -> delta .y = i -> delta .x;
		i -> delta .x = o;
		break;

	case '{':
		o = pop (i) - 1;
		push (i, o);
		if (o < 0) bef_do (i, '[');
		break;

	case '}':
		o = pop (i) - 1;
		push (i, o);
		if (o < 0) bef_do (i, ']');
		break;

	case 'o':
		o = pop (i) - 1;
		push (i, o);
		if (o < 0) bef_do (i, '#');
		break;

	case 's':
		n = pop (i);
		m = pop (i);
		if (btrace) printf ("from (%d,%d) to (%d,%d)\n", i -> ip.x, i -> ip.y, m, n);
		stpush (i -> call, i -> delta .x);
		stpush (i -> call, i -> delta .y);
		stpush (i -> call, i -> ip .x);
		stpush (i -> call, i -> ip .y);
		i -> ip .x = m;
		i -> ip .y = n;
		bef_checkpc (i);
		i -> teleport = -1;
		break;

	case 'S':
		n = pop (i);
		m = pop (i);
		if (btrace) printf ("from (%d,%d) to (%d,%d)\n", i -> ip.x, i -> ip.y, m, n);
		stpush (i -> call, i -> delta .x);
		stpush (i -> call, i -> delta .y);
		stpush (i -> call, i -> ip .x);
		stpush (i -> call, i -> ip .y);
		i -> ip .x = m + stdig (i -> CTX, 1);
		i -> ip .y = n + stpeek (i -> CTX);
		bef_checkpc (i);
		i -> teleport = -1;
		break;

	case 'r':
		n = stpop (i -> call);
		m = stpop (i -> call);
		if (btrace) printf ("from (%d,%d) to (%d,%d)\n", i -> ip.x, i -> ip.y, m, n);
		i -> ip .x = m;
		i -> ip .y = n;
		i -> delta .y = stpop (i -> call);
		i -> delta .x = stpop (i -> call);
		bef_checkpc (i);
		if (!(i -> delta .y) && !(i -> delta .x)) {
			fprintf (stderr, "Damn! PC frozen by 'r'.\n");
			exit (99);
		}
		/* i -> teleport = -1; ACK! NO! BAD Cut&Paste! :) */
		break;

	case 'x':
		stpush (i -> CTX, i -> ip .x);
		stpush (i -> CTX, i -> ip .y);
		break;

	case 'X':
		stpop (i -> CTX);
		stpop (i -> CTX);
		break;

	case ';':
		pop (i);
		break;

	case 'm':
		tmpstack = i -> stack;
		i -> stack = i -> call;
		i -> call = i -> CTX;
		i -> CTX = tmpstack;
		break;

		
#endif



	default:
		printf ("unknown opcode %c (%d) at %d, %d\n", c, c, i -> ip .x, i -> ip .y);
	}
}

stackt *alloc_stackt (int stacksize) {
	stackt *i;

	i = malloc (sizeof (stackt));

	if (i == NULL) return NULL;

	i -> stack = malloc (stacksize * sizeof (int));
	if (i -> stack == NULL) {
		free (i);
		return NULL;
	}

	i -> stacksize = stacksize;
	i -> sp = 0;
	strepl (i, 0);

	return i;
}


bef_interp *bef_allocinterp (int stack, int w, int h) {
	bef_interp *i;
	int n;

	srandom (time (NULL));

	i = malloc (sizeof (bef_interp));

	if (i == NULL) return NULL;

	if ((i -> stack = alloc_stackt (stack)) == NULL) return NULL; /* MEM LEAK */
	if ((i -> CTX = alloc_stackt (stack)) == NULL) return NULL; /* MEM LEAK */
	if ((i -> call = alloc_stackt (stack)) == NULL) return NULL; /* MEM LEAK */

	i -> befungespace = malloc (w * h * sizeof (int));
	if (i -> befungespace == NULL) {
		free (i -> stack);
		free (i);
		return NULL;
	}

	for (n = 0; n < w * h; ++n) {
		i -> befungespace[n] = ' ';
	}

	i -> mem = malloc (h * sizeof (int *));
	if (i == NULL) {
		free (i -> stack);
		free (i -> befungespace);
		free (i);
		return NULL;
	}

	for (n = 0; n < h; ++n) {
		i -> mem[n] = i -> befungespace + (n * w);
	}

	i -> size.x = w;
	i -> size.y = h;

	bef_reset(i);

	return i;
}

int bef_step (bef_interp *i) {
	int c;

	/* get current instruction */
	c = i -> mem[i -> ip .y][i -> ip .x];

	if (btrace) {	
		printf (".btrace. op: %c (%d)  at %d,%d   mode %d\n", c, c, i -> ip .x, i -> ip .y, i -> mode);
	}
	
	if (i -> mode & mSTRING && (c != '"' || i -> prevstrchar == '\\')) {
		++stringtick;
		if (i -> prevstrchar == '\\') {
			push (i, c);
			i -> prevstrchar = ' ';
		} else {
			i -> prevstrchar = c;
			if (c == '\\') {
				i -> prevstrchar = c;
			} else {
				push (i, c);
			}
		}
	} else { /* exec */
		bef_do (i, c);
	}

	if (i -> mode & mTERM) {
		if (btrace) puts ("mTERM");
		return pop(i);
	}

	if (! i -> teleport) {
		bef_walk (i);
	} else  i -> teleport = 0;

	return 0;
}


int bef_run (bef_interp *i) {
	int n;

	while (! (i -> mode & mTERM)) n = bef_step (i), ++tick;

	return n;
}

void bef_reset (bef_interp *i) {
	i -> ip.x = 0;
	i -> ip.y = 0;

	i -> delta.x = 1;
	i -> delta.y = 0;

	i -> mode = 0;
}

void bef_free (bef_interp *i) {
	if (i == NULL) return;
	free (i -> stack -> stack);
	free (i -> stack);
	free (i -> call -> stack);
	free (i -> call);
	free (i -> CTX -> stack);
	free (i -> CTX);
	free (i -> befungespace);
	free (i -> mem);
	free (i);
}


int strtoicpy (int *n, char *c) {
	int i;

	i = 0;

	while (c[i] != 0) {
		n[i] = c[i];
		i++;
	}
	return i;
}


int bef_loadcode (bef_interp *i, FILE *f) {
	int x, y;
	int c = 0;

	for (y = 0; y < i -> size .y; ++y) {
		for (x = 0; x < i -> size .x; ++x) {
			c = fgetc (f);
			if (btrace) printf ("%c", c);
			if (c == EOF) return y;
			if (c == '\n') break;
			i -> mem [y][x] = c;
		}
		if (c != '\n') {
			printf ("line extends past edge of charted space. y == %d\n", y);
		}
	}
	return y;
}
			
int bef_load93 (bef_interp *i, char *name) {
	FILE *f;
	char line[90];
	int n, m;
	int y;

	y = 0;

	if (i == NULL) return -1;
	if (i -> mem == NULL) return -1;

	f = fopen (name, "r");
	if (f == NULL) {
		puts ("could not open file.");
		return -1;
	}
	i -> mode |= m93;
	do {
		n = fscanf (f, "%80[^\n]", line);
		m = fscanf (f, "%2[\n]", &(line[85]));
		if (n != 0 && n != EOF) {
			if (btrace) puts (line);
			strtoicpy ((i -> mem)[y], line);
		} else {
			fclose (f);
			return !y;
		}
		++y;
	} while (1);

}

/* load hbef formatted befunge source into new interpreter */
bef_interp *bef_loadh (char *name) {
	FILE *f;
	int n, m = 1024;
	int w = 80, h = 25;
	bef_interp *i = NULL;

	char command[90];

	*command = 0;

	f = fopen (name, "r");
	if (f == NULL) {
		perror ("could not open file");
		return NULL;
	}

	while ((n = fscanf (f, "%80s", command)) != EOF) {
		if (n) {
			if (btrace) printf ("command: %s\n", command);
			if (!strcmp (command, "wid")) {
				fscanf (f, "%d", &w);
				if (btrace) printf ("w == %d\n", w);
			} else if (!strcmp (command, "hei")) {
				fscanf (f, "%d", &h);
				if (btrace) printf ("h == %d\n", h);
			} else if (!strcmp (command, "stack")) {
				fscanf (f, "%d", &m);
				if (btrace) printf ("stack == %d\n", m);
			} else if (!strcmp (command, "hb")) {
				i = bef_allocinterp (m, w, h);
				do { n = fgetc (f); } while (n != '\n' && n != EOF);
				n = bef_loadcode (i, f);
				if (btrace) printf ("bef_loadcode() returned %d\n", n);
				return i;
			}
		}
	}

	printf ("no hb directive encountered... no code in file?\n");
	bef_free (i);
	return NULL;
}





#ifdef SELFTEST

char *sample = "\"!dlrow olleH\",,,,,,,,,,,,@@";

int main (int argc, char **argv) {
	bef_interp *i;
	int r;
	int load93 = 0;
	int report = 0;
	char *file = "test.hbf";

	for (r = 1; r < argc; ++r) {
		if (!strcmp (argv[r], "--btrace")) {
			btrace = -1;
		} else if (!strcmp (argv[r], "--93")) {
			load93 = -1;
		} else if (!strcmp (argv[r], "--report")) {
			report = -1;
		} else {
			file = argv[r];
		}
		
	}
	
	/*printf ("stack test %d %d %d %d\n", pop(i), bpeek(i), pop(i), bpeek(i));*/

	/*bef_do (i, '.');*/

	/* strtoicpy ((i -> mem)[0], sample); */
	if (load93) {
		i = bef_allocinterp (1024, 80, 25);
		if (bef_load93 (i, file)) puts ("error?");
	} else {
		i = bef_loadh (file);
		if (i == NULL) {
			puts ("bef_loadh() returned NULL");
			exit (1);
		}
	}

	/*printf ("%c\n\n", i -> mem[0][4]);*/

	bef_run (i);

	if (report) printf ("\nDONE: %d ops. %d string, %d nop, %d other.\n", tick, stringtick, noptick, ((tick - stringtick) - noptick));

	bef_free (i);
	return 0;
}
#endif
@


1.6
log
@not sure :P
@
text
@d277 4
a280 1
		} else  i -> mem[n][m] = o;
d616 1
d629 1
@


1.5
log
@added 'p' trace
@
text
@d7 1
a7 1
/* talk to me. gvelicha@@wam.umd.edu */
@


1.4
log
@lalalalala
I love writing log messages.
Log messages rule.
This is da bomb-ass log message from da party house.
Straight outta compton wid da muthafuckin' message, yo.
Give it up fo' da log.
@
text
@d22 1
a22 2
int trace = 0;
int tick = 0, noptick = 0, stringtick = 0;
d64 1
a64 1
		if (trace) printf ("i -> sp == %d, dec pending.\n", i -> sp);
d220 1
a220 1
		if (trace) puts ("mode change mSTRING");
d224 1
a224 1
		if (!trace ) {
d274 1
d302 1
a302 1
		if (trace) printf ("from (%d,%d) to (%d,%d)\n", i -> ip.x, i -> ip.y, m, n);
d355 1
a355 1
		if (trace) printf ("from (%d,%d) to (%d,%d)\n", i -> ip.x, i -> ip.y, m, n);
d369 1
a369 1
		if (trace) printf ("from (%d,%d) to (%d,%d)\n", i -> ip.x, i -> ip.y, m, n);
d383 1
a383 1
		if (trace) printf ("from (%d,%d) to (%d,%d)\n", i -> ip.x, i -> ip.y, m, n);
d488 1
a488 7
	i -> ip.x = 0;
	i -> ip.y = 0;

	i -> delta.x = 1;
	i -> delta.y = 0;

	i -> mode = 0;
d499 2
a500 2
	if (trace) {	
		printf (".trace. op: %c (%d)  at %d,%d   mode %d\n", c, c, i -> ip .x, i -> ip .y, i -> mode);
d521 2
a522 2
		if (trace) puts ("mTERM");
		return 1;
d536 1
a536 1
	while (!(n = bef_step (i))) ++tick;
d541 10
d585 1
a585 1
			if (trace) printf ("%c", c);
d617 1
a617 1
			if (trace) puts (line);
d646 1
a646 1
			if (trace) printf ("command: %s\n", command);
d649 1
a649 1
				if (trace) printf ("w == %d\n", w);
d652 1
a652 1
				if (trace) printf ("h == %d\n", h);
d655 1
a655 1
				if (trace) printf ("stack == %d\n", m);
d660 1
a660 1
				if (trace) printf ("bef_loadcode() returned %d\n", n);
d687 2
a688 2
		if (!strcmp (argv[r], "--trace")) {
			trace = -1;
@


1.3
log
@added 'm'.
@
text
@d8 1
@


1.2
log
@revised license.
@
text
@d116 1
d409 7
d714 1
a714 1
	printf ("\nDONE: %d ops. %d string, %d nop, %d other.\n", tick, stringtick, noptick, ((tick - stringtick) - noptick));
@


1.1
log
@Initial revision
@
text
@d2 5
@