diff interps/1l/1l_a.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/1l/1l_a.c	Sun Dec 09 19:30:08 2012 +0000
@@ -0,0 +1,270 @@
+/*
+An interpreter for the 1L_a language.
+
+This program is hereby placed in the public domain. It may be used,
+modified, copied, distributed, sold, and otherwise exploited without
+restriction.
+
+graue@oceanbase.org
+http://www.oceanbase.org/graue/
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+static /*@null@*/ char *read_arbitrary_length_string(FILE *fp);
+static void run(char **code, int lines, int maxline);
+
+int main(int argc, char *argv[])
+{
+	char **code;
+	FILE *src;
+	int codespace, codelines = 0, maxline = 0;
+
+	if (argc != 2)
+	{
+		fprintf(stderr, "Incorrect invocation\n");
+		return 1;
+	}
+
+	src = fopen(argv[1], "r");
+	if (src == NULL)
+	{
+		fprintf(stderr, "Unreadable file\n");
+		return 2;
+	}
+
+	codespace = 10;
+	code = malloc(codespace * sizeof(char*));
+	if (code == NULL)
+		return 3;
+
+	for (;;)
+	{
+		int len;
+		if (codelines == codespace)
+		{
+			codespace *= 2;
+			code = realloc(code, codespace * sizeof(char*));
+			if (!code)
+				return 4;
+		}
+		code[codelines] = read_arbitrary_length_string(src);
+		if (code[codelines] == NULL)
+			break;
+		len = (int) strlen(code[codelines]);
+		if (len > maxline)
+			maxline = len;
+		codelines++;
+	}
+	(void) fclose(src);
+
+	run(code, codelines, maxline);
+	free(code);
+	return 0;
+}
+
+static char *addmem(/*@null@*/ char *mem, int cursize, int newsize)
+{
+	mem = realloc(mem, (size_t) newsize);
+	if (!mem)
+	{
+		fprintf(stderr, "Out of memory\n");
+		exit(EXIT_FAILURE);
+	}
+	memset(&mem[cursize], 0, (size_t) (newsize - cursize));
+	return mem;
+}
+
+int inbit(void)
+{
+	static int pos = 0;
+	static int byte;
+	int rd;
+
+	if (pos == 0)
+	{
+		rd = getchar();
+		if (rd == EOF)
+			return 0;
+		pos = 8;
+		byte = rd;
+	}
+	return byte & (1<<--pos);
+}
+
+void outbit(int bit)
+{
+	static int pos = 8;
+	static int byte = 0;
+	assert(bit == 0 || bit == 1);
+
+	byte |= (bit<<--pos);
+	if (pos == 0)
+	{
+		pos = 8;
+		putchar(byte);
+		byte = 0;
+	}
+}
+
+#define UP 31337
+#define DOWN 666
+#define LEFT 420
+#define RIGHT 69
+
+static void run(char **code, int lines, int maxline)
+{
+	char *mem = NULL;
+	int memsize = 10, cell, bcell, dir = DOWN, codex, codey;
+	int i, *lengths;
+
+	if (lines < 1)
+	{
+		/* if the IP starts out of code space, the result is undefined,
+		   but we handle it gracefully here */
+		fprintf(stderr, "In 1L_a, the null program is not a quine.\n");
+		return;
+	}
+
+	mem = addmem(mem, 0, memsize);
+	bcell = 0, cell = 2; /* TL0 and TL1 are special */
+	codex = 0;
+	codey = 0;
+
+	lengths = malloc(sizeof(int) * lines);
+
+	if (lengths == NULL)
+		exit(EXIT_FAILURE);
+
+	for (i = 0; i < lines; i++)
+		lengths[i] = (int) strlen(code[i]);
+
+	for (;;)
+	{
+		char c;
+		if (codex >= lengths[codey])
+			c = ' ';
+		else
+			c = code[codey][codex];
+
+		if (c != ' ') /* conditional turn */
+		{
+			/* first back up one */
+			     if (dir == UP)   codey++;
+			else if (dir == DOWN) codey--;
+			else if (dir == LEFT) codex++;
+			else /* RIGHT */      codex--;
+
+			if ((mem[bcell] & (1<<cell)) != 0) /* turn right */
+			{
+				     if (dir == UP)    dir = RIGHT;
+				else if (dir == RIGHT) dir = DOWN;
+				else if (dir == DOWN)  dir = LEFT;
+				else /* LEFT */        dir = UP;
+			}
+			else /* turn left */
+			{
+				     if (dir == DOWN)  dir = RIGHT;
+				else if (dir == RIGHT) dir = UP;
+				else if (dir == UP)    dir = LEFT;
+				else /* LEFT */        dir = DOWN;
+			}
+		}
+		else if (dir == UP) /* move the pointer to the right */
+		{
+			cell++;
+			if (cell == 8)
+			{
+				cell = 0;
+				bcell++;
+				if (bcell == memsize)
+				{
+					mem = addmem(mem, memsize, memsize*2);
+					memsize *= 2;
+				}
+			}
+		}
+		else if (dir == LEFT) /* move pointer left and flip bit */
+		{
+			cell--;
+			if (cell == -1)
+			{
+				cell = 7;
+				bcell--;
+				if (bcell == -1)
+				{
+					fprintf(stderr, "Underflow error at "
+						"%d, %d\n",
+						codex, codey);
+					exit(EXIT_FAILURE);
+				}
+			}
+			mem[bcell] ^= (1<<cell);
+			if (bcell == 0 && cell == 0) /* this is TL0 */
+			{
+				if (mem[0] & (1<<1)) /* TL1 is on; output */
+					outbit(!!(mem[0] & (1<<2)));
+				else /* TL1 is off; input to TL2 */
+				{
+					mem[0] &= ~(1<<2); /* zero TL2 */
+					mem[0] |= (inbit()<<2); /* fill TL2 */
+				}
+			}
+		}
+
+		if (dir == RIGHT)
+		{
+			if (++codex == maxline)
+				break;
+		}
+		else if (dir == LEFT)
+		{
+			if (codex-- == 0)
+				break;
+		}
+		else if (dir == DOWN)
+		{
+			if (++codey == lines)
+				break;
+		}
+		else
+		{
+			assert(dir == UP);
+			if (codey-- == 0)
+				break;
+		}
+	}
+
+	free(lengths);
+	free(mem);
+}
+
+static /*@null@*/ char *read_arbitrary_length_string(FILE *fp)
+{
+	char *p = NULL, *p2, *q;
+	int size = 50;
+
+	if ((p = malloc((size_t) size)) == NULL)
+		return NULL;
+	if (fgets(p, size, fp) == NULL)
+		return NULL;
+
+	while ((q = strchr(p, '\n')) == NULL)
+	{
+		size *= 2;
+		if ((p2 = realloc(p, (size_t) size)) == NULL)
+		{
+			free(p);
+			return NULL;
+		}
+		p = p2;
+		if (fgets(&p[size/2-1], size/2+1, fp) == NULL)
+			return NULL; /* invalid; file must end with newline */
+	}
+
+	*q = '\0';
+	return p;
+}