Mercurial > repo
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 } |