Mercurial > repo
comparison interps/kipple/cipple.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 * cipple the c kipple interpreter | |
3 * version 0.2.1 | |
4 * by Jannis Harder (jix) | |
5 * | |
6 * Usage: cipple [program] | |
7 * if program is omitted, cipple reads from stdin. | |
8 * | |
9 * compile using: gcc -O3 cipple.c -o cipple | |
10 * optional flags: | |
11 * -DNOINLINE disable inlineing | |
12 * -DINCR <int value> sets memory increment for stacks | |
13 * -DDECR <int value> sets memory decrement for stacks (should be a multiply of INCR) | |
14 * -DSTARTS <int value> sets initial stack size (should be less than DECR and a multiply of INCR) | |
15 * -DINSPECT enables instruction dumping (generating kipple code form the internal representation) | |
16 */ | |
17 /* | |
18 * Copyright (c) 2005 Jannis Harder | |
19 * | |
20 * Permission is hereby granted, free of charge, to any person obtaining a copy | |
21 * of this software and associated documentation files (the "Software"), to deal | |
22 * in the Software without restriction, including without limitation the rights | |
23 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
24 * copies of the Software, and to permit persons to whom the Software is | |
25 * furnished to do so, subject to the following conditions: | |
26 * | |
27 * The above copyright notice and this permission notice shall be included in | |
28 * all copies or substantial portions of the Software. | |
29 * | |
30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
31 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
32 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
33 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
34 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
35 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
36 * SOFTWARE. | |
37 */ | |
38 | |
39 #include <stdlib.h> | |
40 #include <stdio.h> | |
41 #include <string.h> | |
42 | |
43 | |
44 #ifndef INCR | |
45 #define INCR 262144 | |
46 #endif | |
47 #ifndef DECR | |
48 #define DECR (INCR*4) | |
49 #endif | |
50 | |
51 #ifndef STARTS | |
52 #define STARTS (INCR*2) | |
53 #endif | |
54 | |
55 | |
56 | |
57 | |
58 #ifdef NOINLINE | |
59 #define ILINE /*ignore*/ | |
60 #else | |
61 #define ILINE inline | |
62 #endif | |
63 | |
64 | |
65 | |
66 | |
67 enum { | |
68 PuNone = 0, | |
69 PuItoa | |
70 }; | |
71 | |
72 enum { | |
73 PoNone = 0, | |
74 }; | |
75 | |
76 | |
77 typedef struct { | |
78 int *data; | |
79 int usize; | |
80 int msize; | |
81 int puspecial; | |
82 /*int pospecial; | |
83 int clrspecial;*/ | |
84 } stack; | |
85 | |
86 ILINE void push(stack *cstack,int value) { | |
87 char temp[13]; | |
88 int ccount, i; | |
89 if(cstack->puspecial) { | |
90 ccount = sprintf(temp,"%i",value); | |
91 if(cstack->usize+ccount+1 > cstack->msize){ | |
92 cstack->msize+=INCR; | |
93 cstack->data = realloc(cstack->data, cstack->msize*sizeof(int)); | |
94 } | |
95 for(i=0;i<ccount;i++) | |
96 cstack->data[++(cstack->usize)]=temp[i]; | |
97 } | |
98 else { | |
99 | |
100 if(cstack->usize+1 == cstack->msize){ | |
101 cstack->msize+=INCR; | |
102 cstack->data = realloc(cstack->data, cstack->msize*sizeof(int)); | |
103 } | |
104 cstack->data[++(cstack->usize)]=value; | |
105 } | |
106 | |
107 } | |
108 | |
109 ILINE int pop(stack *cstack) { | |
110 int rv; | |
111 /*switch(cstack->pospecial) { | |
112 case 0:*/ | |
113 if(cstack->usize == 0) | |
114 return 0; | |
115 rv = cstack->data[cstack->usize--]; | |
116 if(cstack->usize < cstack->msize-DECR){ | |
117 cstack->msize-=DECR; | |
118 cstack->data = realloc(cstack->data, cstack->msize*sizeof(int)); | |
119 } | |
120 /* break; | |
121 }*/ | |
122 return rv; | |
123 } | |
124 | |
125 ILINE void clear(stack *cstack) { | |
126 /*if(!cstack->clrspecial){*/ | |
127 /*free(cstack->data); | |
128 cstack->data = malloc(STARTS*sizeof(int));*/ | |
129 cstack->usize = 0; | |
130 /*cstack->msize = STARTS;*/ | |
131 /*}*/ | |
132 } | |
133 | |
134 ILINE void init(stack *cstack) { | |
135 cstack->data = malloc(STARTS*sizeof(int)+1); | |
136 cstack->usize = 0; | |
137 cstack->msize = STARTS; | |
138 cstack->puspecial = 0; | |
139 /*cstack->pospecial = 0; | |
140 cstack->clrspecial = 0;*/ | |
141 } | |
142 | |
143 ILINE void freestack(stack *cstack) { | |
144 free(cstack->data); | |
145 free(cstack); | |
146 } | |
147 | |
148 ILINE int empty(stack *cstack) { | |
149 return cstack->usize == 0; | |
150 } | |
151 | |
152 ILINE int last(stack *cstack) { | |
153 return cstack->data[cstack->usize]; | |
154 } | |
155 | |
156 enum { | |
157 Inoop = 0, | |
158 Ipush, | |
159 Imove, | |
160 Iaddv, | |
161 Iadds, | |
162 Isubv, | |
163 Isubs, | |
164 Izclr, | |
165 Iloop, | |
166 }; | |
167 | |
168 typedef struct s_ins { | |
169 int instruction; | |
170 union { | |
171 stack* s; | |
172 int i; | |
173 } op_a; | |
174 union { | |
175 stack* s; | |
176 int i; | |
177 struct s_ins *p; | |
178 } op_b; | |
179 struct s_ins *next; | |
180 } instruction; | |
181 | |
182 void freeprog (instruction *program) { | |
183 instruction *cins = program; | |
184 instruction *tins; | |
185 while(cins){ | |
186 if(cins->instruction == Iloop) | |
187 freeprog(cins->op_b.p); | |
188 tins = cins; | |
189 cins = cins->next; | |
190 free(tins); | |
191 } | |
192 } | |
193 | |
194 void run (instruction *program) { | |
195 instruction *cins = program; | |
196 while(cins) { | |
197 switch(cins->instruction){ | |
198 case Inoop: | |
199 break; | |
200 case Ipush: | |
201 push(cins->op_a.s,cins->op_b.i); | |
202 break; | |
203 case Imove: | |
204 push(cins->op_a.s,pop(cins->op_b.s)); | |
205 break; | |
206 case Iaddv: | |
207 push(cins->op_a.s,last(cins->op_a.s)+cins->op_b.i); | |
208 break; | |
209 case Iadds: | |
210 push(cins->op_a.s,last(cins->op_a.s)+pop(cins->op_b.s)); | |
211 break; | |
212 case Isubv: | |
213 push(cins->op_a.s,last(cins->op_a.s)-cins->op_b.i); | |
214 break; | |
215 case Isubs: | |
216 push(cins->op_a.s,last(cins->op_a.s)-pop(cins->op_b.s)); | |
217 break; | |
218 case Izclr: | |
219 if(!last(cins->op_a.s)) | |
220 clear(cins->op_a.s); | |
221 break; | |
222 case Iloop: | |
223 while(!empty(cins->op_a.s)) | |
224 run(cins->op_b.p); | |
225 break; | |
226 } | |
227 cins = cins->next; | |
228 } | |
229 } | |
230 | |
231 | |
232 | |
233 | |
234 | |
235 #define UCASE(X) (((X)>96)?((X)-32):(X)) | |
236 #define CRANGE(X) ((X)>63 && (X)<91) | |
237 #define NRANGE(X) ((X)>47 && (X)<58) | |
238 | |
239 #define MALLOCI nins = malloc(sizeof(instruction)); \ | |
240 nins->next = NULL;\ | |
241 if(!first) first = nins; \ | |
242 if(current) current->next = nins; \ | |
243 current = nins; | |
244 | |
245 | |
246 | |
247 instruction * iparse(stack *stacks,int length, char *ldata) { | |
248 instruction *first = NULL; | |
249 instruction *current = NULL; | |
250 instruction *nins = NULL; | |
251 int isstring = 0; | |
252 | |
253 char *lchr = ldata; | |
254 char *mchr = ldata+length; | |
255 int i1,i2,i3,i4; | |
256 | |
257 /* search for instructions */ | |
258 isstring = 0; | |
259 for(lchr=ldata;lchr<mchr;lchr++) { | |
260 if((*lchr) == '"'){ | |
261 isstring = !isstring; | |
262 } | |
263 else if(!isstring){ | |
264 switch(*lchr){ | |
265 case '+': | |
266 if(lchr==ldata || lchr==mchr-1) break; | |
267 i1 = UCASE(*(lchr-1)); | |
268 i2 = UCASE(*(lchr+1)); | |
269 if(!(CRANGE(i1) && (CRANGE(i2) || NRANGE(i2)))) | |
270 break; | |
271 MALLOCI; | |
272 current->op_a.s = &stacks[i1-'@']; | |
273 if(CRANGE(i2)){ | |
274 current->instruction = Iadds; | |
275 current->op_b.s = &stacks[i2-'@']; | |
276 } | |
277 else { | |
278 current->instruction = Iaddv; | |
279 current->op_b.i = 0; | |
280 for(i3=1;lchr+i3<mchr && NRANGE(lchr[i3]);i3++){ | |
281 current->op_b.i*=10; | |
282 current->op_b.i+=lchr[i3]-'0'; | |
283 } | |
284 } | |
285 break; | |
286 case '-': | |
287 if(lchr==ldata || lchr==mchr-1) break; | |
288 i1 = UCASE(*(lchr-1)); | |
289 i2 = UCASE(*(lchr+1)); | |
290 if(!(CRANGE(i1) && (CRANGE(i2) || NRANGE(i2)))) | |
291 break; | |
292 MALLOCI; | |
293 current->op_a.s = &stacks[i1-'@']; | |
294 if(CRANGE(i2)){ | |
295 current->instruction = Isubs; | |
296 current->op_b.s = &stacks[i2-'@']; | |
297 } | |
298 else { | |
299 current->instruction = Isubv; | |
300 current->op_b.i = 0; | |
301 for(i3=1;lchr+i3<mchr && NRANGE(lchr[i3]);i3++){ | |
302 current->op_b.i*=10; | |
303 current->op_b.i+=lchr[i3]-'0'; | |
304 } | |
305 } | |
306 break; | |
307 case '?': | |
308 if(lchr==ldata) break; | |
309 i1 = UCASE(*(lchr-1)); | |
310 if(!CRANGE(i1)) | |
311 break; | |
312 MALLOCI; | |
313 current->instruction = Izclr; | |
314 current->op_a.s = &stacks[i1-'@']; | |
315 break; | |
316 case '<': | |
317 if(lchr==ldata || lchr==mchr-1) break; | |
318 i1 = UCASE(*(lchr-1)); | |
319 i2 = UCASE(*(lchr+1)); | |
320 if(!CRANGE(i1)) | |
321 break; | |
322 if(CRANGE(i2)){ | |
323 MALLOCI; | |
324 current->instruction = Imove; | |
325 current->op_a.s = &stacks[i1-'@']; | |
326 current->op_b.s = &stacks[i2-'@']; | |
327 } | |
328 else if(NRANGE(i2)){ | |
329 MALLOCI; | |
330 current->instruction = Ipush; | |
331 current->op_a.s = &stacks[i1-'@']; | |
332 current->op_b.i = 0; | |
333 for(i3=1;lchr+i3<mchr && NRANGE(lchr[i3]);i3++){ | |
334 current->op_b.i*=10; | |
335 current->op_b.i+=lchr[i3]-'0'; | |
336 } | |
337 } | |
338 else if(i2=='"'){ | |
339 for(i3=2;lchr+i3<mchr && (lchr[i3]!='"');i3++){ | |
340 MALLOCI; | |
341 current->instruction = Ipush; | |
342 current->op_a.s = &stacks[i1-'@']; | |
343 current->op_b.i = lchr[i3]; | |
344 } | |
345 } | |
346 break; | |
347 case '>': | |
348 if(lchr==ldata || lchr==mchr-1) break; | |
349 i1 = UCASE(*(lchr-1)); | |
350 i2 = UCASE(*(lchr+1)); | |
351 if(!CRANGE(i2)) | |
352 break; | |
353 if(CRANGE(i1)){ | |
354 MALLOCI; | |
355 current->instruction = Imove; | |
356 current->op_a.s = &stacks[i2-'@']; | |
357 current->op_b.s = &stacks[i1-'@']; | |
358 } | |
359 else if(NRANGE(i1)){ | |
360 MALLOCI; | |
361 current->instruction = Ipush; | |
362 current->op_a.s = &stacks[i2-'@']; | |
363 current->op_b.i = 0; | |
364 i4=1; | |
365 for(i3=-1;lchr+i3>=ldata && NRANGE(lchr[i3]);i3--){ | |
366 current->op_b.i+= i4 * (lchr[i3]-'0'); | |
367 i4*=10; | |
368 } | |
369 } | |
370 else if(i1=='"'){ | |
371 for(i3=-2;lchr+i3>=ldata && (lchr[i3]!='"');i3--){ | |
372 MALLOCI; | |
373 current->instruction = Ipush; | |
374 current->op_a.s = &stacks[i2-'@']; | |
375 current->op_b.i = lchr[i3]; | |
376 } | |
377 } | |
378 break; | |
379 case '(': | |
380 if(lchr==mchr-1) break; | |
381 i1 = UCASE(*(lchr+1)); | |
382 if(!CRANGE(i1)) | |
383 break; | |
384 i3=0; | |
385 i4=1; | |
386 for(i2=1;lchr+i2<mchr && i4 > 0;i2++){ | |
387 if(lchr[i2]=='"') | |
388 i3=!i3; | |
389 if(!i3){ | |
390 if(lchr[i2]=='(') | |
391 i4++; | |
392 else if(lchr[i2]==')') | |
393 i4--; | |
394 } | |
395 } | |
396 MALLOCI; | |
397 current->instruction = Iloop; | |
398 current->op_a.s = &stacks[i1-'@']; | |
399 current->op_b.p = iparse(stacks,i2-1,lchr+1); | |
400 lchr+=i2-1; | |
401 break; | |
402 } | |
403 } | |
404 } | |
405 return first; | |
406 } | |
407 | |
408 | |
409 instruction * parse(stack *stacks,int length, char *data) { | |
410 char *ldata = malloc(length); | |
411 instruction *rv; | |
412 char *lchr = ldata; | |
413 char *mchr = ldata+length; | |
414 | |
415 int isstring = 0; | |
416 int comment = 0; | |
417 memcpy(ldata,data,length); | |
418 /* clear comments */ | |
419 for(;lchr<mchr;lchr++) { | |
420 if(isstring && *lchr == '"') | |
421 isstring = 0; | |
422 else if((!comment) && *lchr == '"') | |
423 isstring = 1; | |
424 else if(comment && *lchr == '\n') | |
425 comment = 0; | |
426 else if((!isstring) && *lchr == '#') | |
427 comment = 1; | |
428 if(comment) | |
429 *lchr = ' '; | |
430 | |
431 } | |
432 rv = iparse(stacks,length,ldata); | |
433 free(ldata); | |
434 return rv; | |
435 } | |
436 #ifdef INSPECT | |
437 void dumpprog(int depth,stack *stacks,instruction *program) { | |
438 char *e; | |
439 instruction *cins = program; | |
440 e = malloc(depth+1); | |
441 memset(e,':',depth); | |
442 e[depth]=0; | |
443 while(cins){ | |
444 switch(cins->instruction){ | |
445 case Inoop: | |
446 fprintf(stderr,"%s noop\n",e); | |
447 break; | |
448 case Ipush: | |
449 fprintf(stderr,"%s push %c<%i\n",e,'@'+cins->op_a.s-stacks,cins->op_b.i); | |
450 break; | |
451 case Imove: | |
452 fprintf(stderr,"%s move %c<%c\n",e,'@'+cins->op_a.s-stacks,'@'+cins->op_b.s-stacks); | |
453 break; | |
454 case Iaddv: | |
455 fprintf(stderr,"%s addv %c+%i\n",e,'@'+cins->op_a.s-stacks,cins->op_b.i); | |
456 break; | |
457 case Iadds: | |
458 fprintf(stderr,"%s adds %c+%c\n",e,'@'+cins->op_a.s-stacks,'@'+cins->op_b.s-stacks); | |
459 break; | |
460 case Isubv: | |
461 fprintf(stderr,"%s subv %c-%i\n",e,'@'+cins->op_a.s-stacks,cins->op_b.i); | |
462 break; | |
463 case Isubs: | |
464 fprintf(stderr,"%s subs %c-%c\n",e,'@'+cins->op_a.s-stacks,'@'+cins->op_b.s-stacks); | |
465 break; | |
466 case Izclr: | |
467 fprintf(stderr,"%s zclr %c?\n",e,'@'+cins->op_a.s-stacks); | |
468 break; | |
469 case Iloop: | |
470 fprintf(stderr,"%s loop (%c\n",e,'@'+cins->op_a.s-stacks); | |
471 dumpprog(depth+2,stacks,cins->op_b.p); | |
472 fprintf(stderr,"%s )\n",e); | |
473 break; | |
474 | |
475 } | |
476 cins = cins->next; | |
477 } | |
478 | |
479 } | |
480 #endif | |
481 | |
482 void runstring(int length,char *program) { | |
483 stack stacks[27]; | |
484 int i; | |
485 int t; | |
486 instruction *bc; | |
487 for(i=0;i<27;i++) | |
488 init(&stacks[i]); | |
489 stacks[0].puspecial = PuItoa; | |
490 bc = parse(stacks,length,program); | |
491 #ifdef INSPECT | |
492 dumpprog(1,stacks,bc); | |
493 #endif | |
494 while((t = getchar()) && !feof(stdin)){ | |
495 | |
496 push(&stacks[9],t); | |
497 } | |
498 | |
499 run(bc); | |
500 freeprog(bc); | |
501 while(!empty(&stacks[15])){ | |
502 putchar(pop(&stacks[15])); | |
503 } | |
504 fflush(stdout); | |
505 for(i=0;i<27;i++) | |
506 free(stacks[i].data); | |
507 | |
508 } | |
509 | |
510 /*void runcstring(char *program) { | |
511 runstring(strlen(program),program); | |
512 }*/ | |
513 | |
514 int main (int argc, const char * argv[]) { | |
515 char *program; | |
516 int size = 0; | |
517 FILE *infile; | |
518 if(argc<2) | |
519 infile = stdin; | |
520 else | |
521 infile= fopen(argv[1],"r"); | |
522 | |
523 if(!infile) | |
524 return 1; | |
525 program = malloc(200); | |
526 while(!feof(infile)){ | |
527 program = realloc(program,size+200); | |
528 size+=fread(program+size,1,200,infile); | |
529 } | |
530 if(argc<2){ | |
531 clearerr(stdin); | |
532 rewind(stdin); | |
533 } | |
534 runstring(size,program); | |
535 | |
536 return 0; | |
537 } |