comparison 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
comparison
equal deleted inserted replaced
995:6883f5911eb7 996:859f9b4339e6
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 }