Skip to content

Instantly share code, notes, and snippets.

@dxsmiley
Last active April 16, 2017 06:30
Show Gist options
  • Select an option

  • Save dxsmiley/35416396d2cde813fa43b2bc5e85b5a8 to your computer and use it in GitHub Desktop.

Select an option

Save dxsmiley/35416396d2cde813fa43b2bc5e85b5a8 to your computer and use it in GitHub Desktop.
Befunge interpreter in one c file.
/*
Befunge interpereter, in one large file.
Code taken from this repo: https://github.com/programble/befungeec
It's been smooshed into one file and modified somewhat.
Improvements:
- Shows a special symbols for unprintable characters in debug mode.
- Shows a help message when run with no arguments, rather than crashing.
- Found `atoi(&c)` being used to convert a single `char` to an integer. Never again.
- More compact debugger output: lines are trimmed and extranious lines are not printed.
- Compile flag (-DLARGE_BOARD) to change board size.
- Protections against get / set of out-of-bounds board indexes.
*/
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
/*
* stack.h
*
* Copyright 2010 Curtis (Programble) <programble@gmail.com>
* Licensed under the GNU GPLv3
*/
typedef struct stack_item
{
struct stack_item *next;
char value;
} stack_item;
typedef struct stack
{
stack_item *top;
} stack;
stack *stack_new();
void stack_push(stack*, char);
char stack_pop(stack*);
char stack_peek(stack*);
int stack_length(stack*);
int stack_empty(stack*);
/*
* pointer.h
*
* Copyright 2010 Curtis (Programble) <programble@gmail.com>
* Licensed under the GNU GPLv3
*/
typedef struct pointer
{
int x;
int y;
int dx;
int dy;
stack *stack;
int strmode;
} pointer;
pointer *pointer_new();
void pointer_move(pointer*);
/*
* board.h
*
* Copyright 2010 Curtis (Programble) <programble@gmail.com>
* Licensed under the GNU GPLv3
*/
#ifdef LARGE_BOARD
#define BOARD_WIDTH 100
#define BOARD_HEIGHT 100
#else
#define BOARD_WIDTH 30
#define BOARD_HEIGHT 30
#endif
typedef struct board
{
char data[BOARD_HEIGHT][BOARD_WIDTH];
pointer *pointer;
} board;
board *board_new();
char board_get(board*, int, int);
void board_put(board*, int, int, char);
/*
* stack.c
*
* Copyright 2010 Curtis (Programble) <programble@gmail.com>
* Licensed under the GNU GPLv3
*/
stack *stack_new()
{
stack *s = malloc(sizeof(stack));
s->top = NULL;
return s;
}
void stack_push(stack *s, char value)
{
stack_item *item = malloc(sizeof(stack_item));
if (s->top)
{
item->value = value;
item->next = s->top;
s->top = item;
}
else
{
item->value = value;
item->next = NULL;
s->top = item;
}
}
char stack_pop(stack *s)
{
if (s->top)
{
stack_item *item = s->top;
s->top = item->next;
char value = item->value;
free(item);
return value;
}
else
{
return 0x0;
}
}
char stack_peek(stack *s)
{
if (s->top)
{
stack_item *item = s->top;
return item->value;
}
else
{
return 0x0;
}
}
int stack_length(stack *s)
{
stack_item *item = s->top;
int i = 0;
while (item)
{
i++;
item = item->next;
}
return i;
}
int stack_empty(stack *s)
{
return (!s->top);
}
/*
* pointer.c
*
* Copyright 2010 Curtis (Programble) <programble@gmail.com>
* Licensed under the GNU GPLv3
*/
pointer *pointer_new()
{
pointer *p = malloc(sizeof(pointer));
p->x = 0;
p->y = 0;
p->dx = 1;
p->dy = 0;
p->stack = stack_new();
p->strmode = 0;
return p;
}
void pointer_move(pointer* p)
{
p->x += p->dx;
p->y += p->dy;
}
/*
* board.c
*
* Copyright 2010 Curtis (Programble) <programble@gmail.com>
* Licensed under the GNU GPLv3
*/
board *board_new()
{
board *b = malloc(sizeof(board));
b->pointer = pointer_new();
int y, x;
for (y = 0; y < BOARD_HEIGHT; y++)
{
for (x = 0; x < BOARD_WIDTH; x++)
{
b->data[y][x] = ' ';
}
}
return b;
}
char board_get(board *b, int x, int y)
{
if (x < 0 || y < 0 || x >= BOARD_WIDTH || y >= BOARD_HEIGHT) return 0;
return b->data[y][x];
}
void board_put(board *b, int x, int y, char value)
{
if (x >= 0 && y >= 0 && x < BOARD_WIDTH && y < BOARD_HEIGHT) b->data[y][x] = value;
}
/*
* main.c
*
* Copyright 2010 Curtis (Programble) <programble@gmail.com>
* Licensed under the GNU GPLv3
*/
int debugflag = 0;
FILE *debugstream;
void debug(board *board)
{
int height = 0;
for (int y = 0; y < BOARD_HEIGHT; y++)
{
for (int x = 0; x < BOARD_WIDTH; ++x) {
if (board_get(board, x, y) != ' ') {
height = y + 1;
}
}
}
printf("\x1b[H\x1b[2J");
char direction;
if (board -> pointer -> dx == 1)
direction = '>';
else if (board -> pointer -> dx == -1)
direction = '<';
else if (board -> pointer -> dy == 1)
direction = 'v';
else if (board -> pointer -> dy == -1)
direction = '^';
printf("Pointer: %d,%d %c %s\n", board->pointer->x, board->pointer->y, direction, (board->pointer->strmode)?"string mode":"");
printf("Board:\n");
int y, x;
for (y = 0; y < height; y++)
{
int width = 0;
for (x = 0; x < BOARD_WIDTH; ++x) {
if (board_get(board, x, y) != ' ') width = x + 1;
}
for (x = 0; x < width; x++)
{
int value = board_get(board, x, y);
if (x == board->pointer->x && y == board->pointer->y) {
if (value < 32 || value > 126) {
printf("\033[41m\033[35m?\033[0m");
// printf("\033[41m%c\033[0m", value);
} else {
printf("\033[41m%c\033[0m", value);
}
} else {
// If it's an unprintable character, show it.
if (value < 32 || value > 126) {
// printf("?");
printf("\033[35m?\033[0m");
} else {
printf("%c", value);
}
}
// printf("%s%c\033[0m", (x == board->pointer->x && y == board->pointer->y)?"\033[41m":"", board_get(board, x, y));
}
printf("\n");
}
printf("Stack:\n");
stack_item *item = board->pointer->stack->top;
while (item)
{
switch (item -> value) {
case '\0':
printf("(0 \033[35mnull\033[0m) "); break;
case '\n':
printf("(10 \033[35mnewline\033[0m) "); break;
default:
if (item -> value >= 32 && item -> value <= 126) {
printf("(%d '%c') ", item -> value, item -> value); break;
} else {
printf("(%d \033[35munknown\033[0m) ", item -> value); break;
}
}
item = item->next;
}
printf("\n");
printf("Output:\n");
fseek(debugstream, 0, SEEK_SET);
char c;
while ((c = fgetc(debugstream)) != EOF)
{
printf("%c", c);
}
getchar();
}
void process(board *board)
{
FILE *out;
if (debugflag)
out = debugstream;
else
out = stdout;
while (1)
{
char c = board_get(board, board->pointer->x, board->pointer->y);
if (board->pointer->strmode && c != '"')
{
stack_push(board->pointer->stack, c);
}
else
{
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
stack_push(board->pointer->stack, c - '0');
break;
case '+':
{
char a = stack_pop(board->pointer->stack);
char b = stack_pop(board->pointer->stack);
stack_push(board->pointer->stack, a + b);
break;
}
case '-':
{
char a = stack_pop(board->pointer->stack);
char b = stack_pop(board->pointer->stack);
stack_push(board->pointer->stack, b - a);
break;
}
case '*':
{
char a = stack_pop(board->pointer->stack);
char b = stack_pop(board->pointer->stack);
stack_push(board->pointer->stack, a * b);
break;
}
case '/':
{
char a = stack_pop(board->pointer->stack);
char b = stack_pop(board->pointer->stack);
stack_push(board->pointer->stack, b / a);
break;
}
case '%':
{
char a = stack_pop(board->pointer->stack);
char b = stack_pop(board->pointer->stack);
stack_push(board->pointer->stack, b % a);
break;
}
case '!':
stack_push(board->pointer->stack, !stack_pop(board->pointer->stack));
break;
case '`':
{
char a = stack_pop(board->pointer->stack);
char b = stack_pop(board->pointer->stack);
stack_push(board->pointer->stack, (b > a));
break;
}
case '>':
board->pointer->dx = 1;
board->pointer->dy = 0;
break;
case '<':
board->pointer->dx = -1;
board->pointer->dy = 0;
break;
case '^':
board->pointer->dx = 0;
board->pointer->dy = -1;
break;
case 'v':
board->pointer->dx = 0;
board->pointer->dy = 1;
break;
case '?':
{
srand((unsigned)time(NULL));
int r = rand() % 4;
switch (r)
{
case 0:
board->pointer->dx = 1;
board->pointer->dy = 0;
break;
case 1:
board->pointer->dx = -1;
board->pointer->dy = 0;
break;
case 2:
board->pointer->dx = 0;
board->pointer->dy = -1;
break;
case 3:
board->pointer->dx = 0;
board->pointer->dy = 1;
break;
}
break;
}
case '_':
{
char x = stack_pop(board->pointer->stack);
if (x == 0)
{
board->pointer->dx = 1;
board->pointer->dy = 0;
}
else
{
board->pointer->dx = -1;
board->pointer->dy = 0;
}
break;
}
case '|':
{
char x = stack_pop(board->pointer->stack);
if (x == 0)
{
board->pointer->dx = 0;
board->pointer->dy = 1;
}
else
{
board->pointer->dx = 0;
board->pointer->dy = -1;
}
break;
}
case '"':
board->pointer->strmode = !board->pointer->strmode;
break;
case ':':
stack_push(board->pointer->stack, stack_peek(board->pointer->stack));
break;
case '\\':
{
char a = stack_pop(board->pointer->stack);
char b = stack_pop(board->pointer->stack);
stack_push(board->pointer->stack, a);
stack_push(board->pointer->stack, b);
break;
}
case '$':
stack_pop(board->pointer->stack);
break;
case '.':
fprintf(out, "%d ", (unsigned char)stack_pop(board->pointer->stack));
break;
case ',':
fprintf(out, "%c", stack_pop(board->pointer->stack));
break;
case '#':
pointer_move(board->pointer);
break;
case 'p':
{
int y = stack_pop(board->pointer->stack);
int x = stack_pop(board->pointer->stack);
char v = stack_pop(board->pointer->stack);
board_put(board, x, y, v);
break;
}
case 'g':
{
int y = stack_pop(board->pointer->stack);
int x = stack_pop(board->pointer->stack);
stack_push(board->pointer->stack, board_get(board, x, y));
break;
}
case '&':
{
int i;
scanf(" %d", &i);
stack_push(board->pointer->stack, (char) i);
break;
}
case '~':
stack_push(board->pointer->stack, getchar());
break;
case '@':
return;
}
}
pointer_move(board->pointer);
if (board->pointer->x < 0)
{
board->pointer->x += BOARD_WIDTH;
}
if (board->pointer->x >= BOARD_WIDTH)
{
board->pointer->x -= BOARD_WIDTH;
}
if (board->pointer->y < 0)
{
board->pointer->y += BOARD_HEIGHT;
}
if (board->pointer->y >= BOARD_HEIGHT)
{
board->pointer->y -= BOARD_HEIGHT;
}
if (debugflag && board_get(board, board -> pointer -> x, board -> pointer -> y) != ' ')
{
debug(board);
}
}
}
int main(int argc, char **argv)
{
if (argc == 1) {
printf("Usage: befunge [--debug] source\n");
return 0;
}
board *board = board_new();
FILE *f;
if (argc < 2 || strcmp(argv[argc-1], "--") == 0)
{
f = stdin;
}
else
{
f = fopen(argv[argc-1], "r");
if (f == NULL)
{
perror("open");
return 1;
}
}
if (strcmp(argv[1], "-d") == 0 || strcmp(argv[1], "--debug") == 0)
debugflag = 1;
char c;
int x = 0;
int y = 0;
while ((c = fgetc(f)) != EOF)
{
if (c == '\n')
{
y++;
x = 0;
continue;
}
else
{
board_put(board, x, y, c);
}
if (x > BOARD_WIDTH || y > BOARD_HEIGHT)
{
fprintf(stderr, "Error: File too large (%i, %i)", x, y);
return 1;
}
x++;
}
if (f != stdin)
{
fclose(f);
}
if (debugflag)
{
debugstream = tmpfile();
}
process(board);
if (debugflag)
{
fclose(debugstream);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment