996
|
1 /*
|
|
2 An interpreter for the 1L_a language.
|
|
3
|
|
4 This program is hereby placed in the public domain. It may be used,
|
|
5 modified, copied, distributed, sold, and otherwise exploited without
|
|
6 restriction.
|
|
7
|
|
8 graue@oceanbase.org
|
|
9 http://www.oceanbase.org/graue/
|
|
10 */
|
|
11
|
|
12 #include <stdio.h>
|
|
13 #include <stdlib.h>
|
|
14 #include <string.h>
|
|
15 #include <assert.h>
|
|
16
|
|
17 static /*@null@*/ char *read_arbitrary_length_string(FILE *fp);
|
|
18 static void run(char **code, int lines, int maxline);
|
|
19
|
|
20 int main(int argc, char *argv[])
|
|
21 {
|
|
22 char **code;
|
|
23 FILE *src;
|
|
24 int codespace, codelines = 0, maxline = 0;
|
|
25
|
|
26 if (argc != 2)
|
|
27 {
|
|
28 fprintf(stderr, "Incorrect invocation\n");
|
|
29 return 1;
|
|
30 }
|
|
31
|
|
32 src = fopen(argv[1], "r");
|
|
33 if (src == NULL)
|
|
34 {
|
|
35 fprintf(stderr, "Unreadable file\n");
|
|
36 return 2;
|
|
37 }
|
|
38
|
|
39 codespace = 10;
|
|
40 code = malloc(codespace * sizeof(char*));
|
|
41 if (code == NULL)
|
|
42 return 3;
|
|
43
|
|
44 for (;;)
|
|
45 {
|
|
46 int len;
|
|
47 if (codelines == codespace)
|
|
48 {
|
|
49 codespace *= 2;
|
|
50 code = realloc(code, codespace * sizeof(char*));
|
|
51 if (!code)
|
|
52 return 4;
|
|
53 }
|
|
54 code[codelines] = read_arbitrary_length_string(src);
|
|
55 if (code[codelines] == NULL)
|
|
56 break;
|
|
57 len = (int) strlen(code[codelines]);
|
|
58 if (len > maxline)
|
|
59 maxline = len;
|
|
60 codelines++;
|
|
61 }
|
|
62 (void) fclose(src);
|
|
63
|
|
64 run(code, codelines, maxline);
|
|
65 free(code);
|
|
66 return 0;
|
|
67 }
|
|
68
|
|
69 static char *addmem(/*@null@*/ char *mem, int cursize, int newsize)
|
|
70 {
|
|
71 mem = realloc(mem, (size_t) newsize);
|
|
72 if (!mem)
|
|
73 {
|
|
74 fprintf(stderr, "Out of memory\n");
|
|
75 exit(EXIT_FAILURE);
|
|
76 }
|
|
77 memset(&mem[cursize], 0, (size_t) (newsize - cursize));
|
|
78 return mem;
|
|
79 }
|
|
80
|
|
81 int inbit(void)
|
|
82 {
|
|
83 static int pos = 0;
|
|
84 static int byte;
|
|
85 int rd;
|
|
86
|
|
87 if (pos == 0)
|
|
88 {
|
|
89 rd = getchar();
|
|
90 if (rd == EOF)
|
|
91 return 0;
|
|
92 pos = 8;
|
|
93 byte = rd;
|
|
94 }
|
|
95 return byte & (1<<--pos);
|
|
96 }
|
|
97
|
|
98 void outbit(int bit)
|
|
99 {
|
|
100 static int pos = 8;
|
|
101 static int byte = 0;
|
|
102 assert(bit == 0 || bit == 1);
|
|
103
|
|
104 byte |= (bit<<--pos);
|
|
105 if (pos == 0)
|
|
106 {
|
|
107 pos = 8;
|
|
108 putchar(byte);
|
|
109 byte = 0;
|
|
110 }
|
|
111 }
|
|
112
|
|
113 #define UP 31337
|
|
114 #define DOWN 666
|
|
115 #define LEFT 420
|
|
116 #define RIGHT 69
|
|
117
|
|
118 static void run(char **code, int lines, int maxline)
|
|
119 {
|
|
120 char *mem = NULL;
|
|
121 int memsize = 10, cell, bcell, dir = DOWN, codex, codey;
|
|
122 int i, *lengths;
|
|
123
|
|
124 if (lines < 1)
|
|
125 {
|
|
126 /* if the IP starts out of code space, the result is undefined,
|
|
127 but we handle it gracefully here */
|
|
128 fprintf(stderr, "In 1L_a, the null program is not a quine.\n");
|
|
129 return;
|
|
130 }
|
|
131
|
|
132 mem = addmem(mem, 0, memsize);
|
|
133 bcell = 0, cell = 2; /* TL0 and TL1 are special */
|
|
134 codex = 0;
|
|
135 codey = 0;
|
|
136
|
|
137 lengths = malloc(sizeof(int) * lines);
|
|
138
|
|
139 if (lengths == NULL)
|
|
140 exit(EXIT_FAILURE);
|
|
141
|
|
142 for (i = 0; i < lines; i++)
|
|
143 lengths[i] = (int) strlen(code[i]);
|
|
144
|
|
145 for (;;)
|
|
146 {
|
|
147 char c;
|
|
148 if (codex >= lengths[codey])
|
|
149 c = ' ';
|
|
150 else
|
|
151 c = code[codey][codex];
|
|
152
|
|
153 if (c != ' ') /* conditional turn */
|
|
154 {
|
|
155 /* first back up one */
|
|
156 if (dir == UP) codey++;
|
|
157 else if (dir == DOWN) codey--;
|
|
158 else if (dir == LEFT) codex++;
|
|
159 else /* RIGHT */ codex--;
|
|
160
|
|
161 if ((mem[bcell] & (1<<cell)) != 0) /* turn right */
|
|
162 {
|
|
163 if (dir == UP) dir = RIGHT;
|
|
164 else if (dir == RIGHT) dir = DOWN;
|
|
165 else if (dir == DOWN) dir = LEFT;
|
|
166 else /* LEFT */ dir = UP;
|
|
167 }
|
|
168 else /* turn left */
|
|
169 {
|
|
170 if (dir == DOWN) dir = RIGHT;
|
|
171 else if (dir == RIGHT) dir = UP;
|
|
172 else if (dir == UP) dir = LEFT;
|
|
173 else /* LEFT */ dir = DOWN;
|
|
174 }
|
|
175 }
|
|
176 else if (dir == UP) /* move the pointer to the right */
|
|
177 {
|
|
178 cell++;
|
|
179 if (cell == 8)
|
|
180 {
|
|
181 cell = 0;
|
|
182 bcell++;
|
|
183 if (bcell == memsize)
|
|
184 {
|
|
185 mem = addmem(mem, memsize, memsize*2);
|
|
186 memsize *= 2;
|
|
187 }
|
|
188 }
|
|
189 }
|
|
190 else if (dir == LEFT) /* move pointer left and flip bit */
|
|
191 {
|
|
192 cell--;
|
|
193 if (cell == -1)
|
|
194 {
|
|
195 cell = 7;
|
|
196 bcell--;
|
|
197 if (bcell == -1)
|
|
198 {
|
|
199 fprintf(stderr, "Underflow error at "
|
|
200 "%d, %d\n",
|
|
201 codex, codey);
|
|
202 exit(EXIT_FAILURE);
|
|
203 }
|
|
204 }
|
|
205 mem[bcell] ^= (1<<cell);
|
|
206 if (bcell == 0 && cell == 0) /* this is TL0 */
|
|
207 {
|
|
208 if (mem[0] & (1<<1)) /* TL1 is on; output */
|
|
209 outbit(!!(mem[0] & (1<<2)));
|
|
210 else /* TL1 is off; input to TL2 */
|
|
211 {
|
|
212 mem[0] &= ~(1<<2); /* zero TL2 */
|
|
213 mem[0] |= (inbit()<<2); /* fill TL2 */
|
|
214 }
|
|
215 }
|
|
216 }
|
|
217
|
|
218 if (dir == RIGHT)
|
|
219 {
|
|
220 if (++codex == maxline)
|
|
221 break;
|
|
222 }
|
|
223 else if (dir == LEFT)
|
|
224 {
|
|
225 if (codex-- == 0)
|
|
226 break;
|
|
227 }
|
|
228 else if (dir == DOWN)
|
|
229 {
|
|
230 if (++codey == lines)
|
|
231 break;
|
|
232 }
|
|
233 else
|
|
234 {
|
|
235 assert(dir == UP);
|
|
236 if (codey-- == 0)
|
|
237 break;
|
|
238 }
|
|
239 }
|
|
240
|
|
241 free(lengths);
|
|
242 free(mem);
|
|
243 }
|
|
244
|
|
245 static /*@null@*/ char *read_arbitrary_length_string(FILE *fp)
|
|
246 {
|
|
247 char *p = NULL, *p2, *q;
|
|
248 int size = 50;
|
|
249
|
|
250 if ((p = malloc((size_t) size)) == NULL)
|
|
251 return NULL;
|
|
252 if (fgets(p, size, fp) == NULL)
|
|
253 return NULL;
|
|
254
|
|
255 while ((q = strchr(p, '\n')) == NULL)
|
|
256 {
|
|
257 size *= 2;
|
|
258 if ((p2 = realloc(p, (size_t) size)) == NULL)
|
|
259 {
|
|
260 free(p);
|
|
261 return NULL;
|
|
262 }
|
|
263 p = p2;
|
|
264 if (fgets(&p[size/2-1], size/2+1, fp) == NULL)
|
|
265 return NULL; /* invalid; file must end with newline */
|
|
266 }
|
|
267
|
|
268 *q = '\0';
|
|
269 return p;
|
|
270 }
|