view interps/adjust/adjust.c @ 12518:2d8fe55c6e65 draft default tip

<int-e> learn The password of the month is release incident pilot.
author HackEso <hackeso@esolangs.org>
date Sun, 03 Nov 2024 00:31:02 +0000
parents 859f9b4339e6
children
line wrap: on
line source

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

typedef unsigned char cell;

cell *read_arbitrary_length_string(FILE *fp);
void run(cell **code, int lines, int maxline);

int main(int argc, char *argv[])
{
	cell **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(cell*));
	if (!code)
		return 3;

	for (;;)
	{
		int len;
		if (codelines == codespace)
		{
			codespace *= 2;
			code = realloc(code, codespace * sizeof(cell*));
			if (!code)
				return 4;
		}
		code[codelines] = read_arbitrary_length_string(src);
		if (code[codelines] == NULL)
			break;
		len = strlen(code[codelines]);
		if (len > maxline)
			maxline = len;
		codelines++;
	}
	fclose(src);

	run(code, codelines, maxline);
	free(code);
	return 0;
}

cell *addmem(cell *mem, int cursize, int newsize)
{
	mem = realloc(mem, newsize);
	if (!mem)
	{
		fprintf(stderr, "Out of memory\n");
		exit(-1);
	}
	memset(&mem[cursize], 0, newsize - cursize);
	return mem;
}

/* For 2 <= n <= 126, next[n] = n / gpf[n]. */
cell next[127] =
{
	 0,  0,  1,  1,  2,  1,  2,  1,
	 4,  3,  2,  1,  4,  1,  2,  3,
	 8,  1,  6,  1,  4,  3,  2,  1,
	 8,  5,  2,  9,  4,  1,  6,  1,
	16,  3,  2,  5, 12,  1,  2,  3,
	 8,  1,  6,  1,  4,  9,  2,  1,
	16,  7, 10,  3,  4,  1, 18,  5,
	 8,  3,  2,  1, 12,  1,  2,  9,
	32,  5,  6,  1,  4,  3, 10,  1,
	24,  1,  2, 15,  4,  7,  6,  1,
	16, 27,  2,  1, 12,  5,  2,  3,
	 8,  1, 18,  7,  4,  3,  2,  5,
	32,  1, 14,  9, 20,  1,  6,  1,
	 8, 15,  2,  1, 36,  1, 10,  3,
	16,  1,  6,  5,  4,  9,  2,  7,
	24, 11,  2,  3,  4, 25, 18
};

/* For 2 <= n <= 126, gpf[n] is n's greatest prime factor. */
cell gpf[127] =
{
	  0,   0,   2,   3,   2,   5,   3,   7,
	  2,   3,   5,  11,   3,  13,   7,   5,
	  2,  17,   3,  19,   5,   7,  11,  23,
	  3,   5,  13,   3,   7,  29,   5,  31,
	  2,  11,  17,   7,   3,  37,  19,  13,
	  5,  41,   7,  43,  11,   5,  23,  47,
	  3,   7,   5,  17,  13,  53,   3,  11,
	  7,  19,  29,  59,   5,  61,  31,   7,
	  2,  13,  11,  67,  17,  23,   7,  71,
	  3,  73,  37,   5,  19,  11,  13,  79,
	  5,   3,  41,  83,   7,  17,  43,  29,
	 11,  89,   5,  13,  23,  31,  47,  19,
	  3,  97,   7,  11,   5, 101,  17, 103,
	 13,   7,  53, 107,   3, 109,  11,  37,
	  7, 113,  19,  23,  29,  13,  59,  17,
	  5,  11,  61,  41,  31,   5,   7
};

cell bitsset[256] =
{
	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};

#define       LEFT     0
#define    UP_LEFT     1
#define         UP     2
#define   UP_RIGHT     3
#define      RIGHT     4
#define DOWN_RIGHT     5
#define       DOWN     6
#define  DOWN_LEFT     7

#define RIGHT135(d) ((d) = right135((d)))
#define  RIGHT90(d) ((d) =  right90((d)))
#define  RIGHT45(d) ((d) =  right45((d)))
#define   LEFT45(d) ((d) =   left45((d)))
#define   LEFT90(d) ((d) =   left90((d)))
static inline int right135(int dir) { return (dir+3)%8; }
static inline int  right90(int dir) { return (dir+2)%8; }
static inline int  right45(int dir) { return (dir+1)%8; }
static inline int   left45(int dir) { return (dir-1)%8; }
static inline int   left90(int dir) { return (dir-2)%8; }
static inline void movefwd(int *x, int *y, int dir, int steps)
{
	if (dir == LEFT || dir == UP_LEFT || dir == DOWN_LEFT)
		*x -= steps;
	else if (dir == RIGHT || dir == UP_RIGHT || dir == DOWN_RIGHT)
		*x += steps;
	if (dir == UP || dir == UP_LEFT || dir == UP_RIGHT)
		*y -= steps;
	else if (dir == DOWN || dir == DOWN_LEFT || dir == DOWN_RIGHT)
		*y += steps;
}
#ifdef UNSAFE
static inline void checkmove(int x, int y, int w, int h) {}
#else
static inline void checkmove(int x, int y, int w, int h)
{
	if (x < 0 || y < 0 || x >= w || y >= h)
	{
		fprintf(stderr, "Out of bounds\n");
		exit(-1);
	}
}
#endif
static inline void push(cell val, cell **pstack, int *items, int *space)
{
	if (*items == *space)
	{
		*pstack = addmem(*pstack, *space, 2**space);
		*space *= 2;
	}
	(*pstack)[(*items)++] = val;
}
static inline int pop(cell *stack, int *items)
{
	if (*items == 0)
		return -1;
	return stack[--(*items)];
}
static inline int peek(cell *stack, int items)
{
	if (items == 0)
		return -1;
	return stack[items - 1];
}

void run(cell **code, int lines, int maxline)
{
	cell acc, *stack1 = NULL, *stack2 = NULL;
	int stack1size = 10, stack2size = 10;
	int stack1pos = 0, stack2pos = 0;
	int dir = UP_RIGHT, codex, codey;
	int i, *lengths;

	stack1 = addmem(stack1, 0, stack1size);
	stack2 = addmem(stack2, 0, stack2size);
	acc = 0;
	codex = 0;
	codey = lines - 1;

	lengths = malloc(sizeof(int) * lines);
	for (i = 0; i < lines; i++)
		lengths[i] = strlen(code[i]);

	for (;;)
	{
		cell c;
		if (codex >= lengths[codey])
			c = '!'; /* lines are padded with ! */
		else
		{
			c = code[codey][codex];
#ifndef UNSAFE
			if (c < 32 || c > 126)
			{
				fprintf(stderr, "Invalid character\n");
				exit(-1);
			}
#endif
		}

		/* run the commands */
		for (; c > 1; c = next[(size_t) c]) switch(gpf[(size_t) c])
		{
			case 2:
			{
				cell tmp;
				tmp = (acc & 7) << 5;
				acc >>= 3;
				acc |= tmp;
				break;
			}
			case 3:
			{
				int s1, s2;
				s1 = peek(stack1, stack1pos);
				s2 = peek(stack2, stack2pos);
				if (s2 < s1)
				{
					push(acc, &stack2,
						&stack2pos, &stack2size);
					LEFT45(dir);
					movefwd(&codex, &codey, dir, 1);
					break;
				}
				push(acc, &stack1, &stack1pos, &stack1size);
				if (s2 == s1)
				{
					RIGHT45(dir);
					movefwd(&codex, &codey, dir, 1);
					break;
				}
				if (acc)
					LEFT90(dir);
				else
					RIGHT135(dir);
				movefwd(&codex, &codey, dir, 1);
				break;
			}
			case 5:
			{
				if (acc & 1)
					acc--;
				else
					acc++;
				break;
			}
			case 7:
			{
				movefwd(&codex, &codey, dir,
					bitsset[(size_t) acc]);
				break;
			}
			case 11:
			{
				int s1, s2;
				s1 = peek(stack1, stack1pos);
				s2 = peek(stack2, stack2pos);
				if (s1 > s2)
					acc = pop(stack1, &stack1pos);
				else if (s2 == -1)
					acc = 0;
				else
					acc = pop(stack2, &stack2pos);
				break;
			}
			case 13:
			{
				int s2;
				s2 = pop(stack2, &stack2pos);
				if (s2 != -1)
					putchar(s2);
				break;
			}
			case 17:
			case 19:
			{
				int ch;
				if (gpf[(size_t) c] == 17)
					ch = getchar();
				else
					ch = pop(stack2, &stack2pos);
				if (ch < 0 || ch > 255) /* empty stack/EOF */
				{
					int steps = 0;
					if (acc & (1<<2))
						RIGHT90(dir);
					steps += (acc & (1<<3));
					steps += (acc & (1<<4));
					steps += (acc & (1<<7));
					movefwd(&codex, &codey, dir, steps);
					break;
				}
				push(ch, &stack1, &stack1pos, &stack1size);
				break;
			}
			case 23:
			{
				acc <<= 5;
				break;
			}
			case 29:
			{
				int s1, s2, steps = 2;
				if (acc != 0)
					break;
				LEFT45(dir);
				s1 = peek(stack1, stack1pos);
				s2 = peek(stack2, stack2pos);
				if (s2 < s1)
					steps++;
				movefwd(&codex, &codey, dir, steps);
				RIGHT45(dir);
				break;
			}
			case 31:
			{
				movefwd(&codex, &codey, dir, 1);
				break;
			}
			case 37:
			{
				int s1, s2;
				s1 = peek(stack1, stack1pos);
				s2 = peek(stack2, stack2pos);
				if (s1 == s2)
					break;
				if (s1 < s2)
					push(s1, &stack2, &stack2pos,
						&stack2size);
				else
					push(s2, &stack1, &stack1pos,
						&stack1size);
				break;
			}
			case 41:
			{
				int s1, s2;
				s1 = peek(stack1, stack1pos);
				s2 = peek(stack2, stack2pos);
				if (s1 == s2)
					break;
				if (s1 > s2)
					pop(stack1, &stack1pos);
				else
					pop(stack2, &stack2pos);
				break;
			}
			case 43:
			{
				acc >>= 1;
				if (!acc)
				{
					movefwd(&codex, &codey, dir, 1);
					LEFT90(dir);
				}
				break;
			}
			case 47:
			{
				int s1, s2;
				s1 = peek(stack1, stack1pos);
				s2 = peek(stack2, stack2pos);
				if (s1 == s2)
					break;
				if (s1 < s2)
					acc = pop(stack1, &stack1pos);
				else
					acc = pop(stack2, &stack2pos);
				break;
			}
			case 53:
			{
				int s1, s2;
				s1 = peek(stack1, stack1pos);
				s2 = peek(stack2, stack2pos);
				if (s1 < s2)
				{
					cell tmp;
					tmp = acc & 0xf0;
					if (acc & 1)
						tmp |= 8;
					if (acc & 2)
						tmp |= 4;
					if (acc & 4)
						tmp |= 2;
					if (acc & 8)
						tmp |= 1;
					acc = tmp;
				}
				else
				{
					cell tmp;
					tmp = acc & 0x0f;
					if (acc & 16)
						tmp |= 128;
					if (acc & 32)
						tmp |= 64;
					if (acc & 64)
						tmp |= 32;
					if (acc & 128)
						tmp |= 16;
					acc = tmp;
				}
				break;
			}
			case 59:
			{
				int n;
				n = bitsset[(size_t) acc] % 8;
				while(n--)
					RIGHT45(dir);
				break;
			}
			case 61:
			{
				cell *tmps;
				int tmp;
				tmps = stack1;
				stack1 = stack2;
				stack2 = tmps;
				tmp = stack1size;
				stack1size = stack2size;
				stack2size = tmp;
				tmp = stack1pos;
				stack1pos = stack2pos;
				stack2pos = tmp;
				break;
			}
			case 67:
				goto quit;
			default:
				acc = gpf[(size_t) c];
		}

		movefwd(&codex, &codey, dir, 1);
		checkmove(codex, codey, maxline, lines);
	}

quit:
	free(lengths);
	free(stack1);
	free(stack2);
}

cell *read_arbitrary_length_string(FILE *fp)
{
	cell *p = NULL, *q;
	int size = 50;

	if ((p = malloc(size)) == NULL)
		return NULL;
	if (fgets(p, size, fp) == NULL)
		return NULL;

	while ((q = strchr(p, '\n')) == NULL)
	{
		size *= 2;
		if ((p = realloc(p, size)) == NULL)
			return NULL;
		if (fgets(&p[size/2-1], size/2+1, fp) == NULL)
			return NULL; /* invalid; file must end with newline */
	}

	*q = '\0';
	return p;
}