Mercurial > repo
comparison fueue.c @ 1987:d92f741c7f8f
<oerjan> fetch http://zzo38computer.org/esoteric/Arc_Koen/fueue.c
author | HackBot |
---|---|
date | Sat, 02 Feb 2013 22:32:53 +0000 |
parents | |
children | 511c13628966 |
comparison
equal
deleted
inserted
replaced
1986:23c726e07478 | 1987:d92f741c7f8f |
---|---|
1 #include <stdio.h> | |
2 #include <stdlib.h> | |
3 #include <string.h> | |
4 #define TRUE 1 | |
5 #define FALSE 0 | |
6 | |
7 /* | |
8 * Fueue Interpreter in language C | |
9 * the esoteric programming language Fueue was designed in 2012 by Taneb. | |
10 * | |
11 * The following program was written by Stephan Kunne on august 29 2012. | |
12 * It is public domain; you are free to use it, copy it, distribute it, | |
13 * or do whatever you'd like with it. | |
14 * Credit and feedback are always appreciated ; you can email me at | |
15 * firstname dot name at gmail dot com with all your questions or remarks. | |
16 * | |
17 * Examples: | |
18 * | |
19 * ./fueuec '72 101 108 108 111 44 32 119 111 114 108 100 33 10 H' | |
20 * Hello, world! | |
21 * | |
22 * ./fueuec --print '):[):]' | |
23 * ):[):] | |
24 * :[):]) | |
25 * )[):][):] | |
26 * [):]): | |
27 * ):[):] | |
28 * (...and so on) | |
29 */ | |
30 | |
31 enum Typet | |
32 { | |
33 NUM, FUN, BLOCK | |
34 }; | |
35 | |
36 typedef struct Queue Queue; | |
37 struct Queue | |
38 { | |
39 int size; | |
40 struct Token *top; | |
41 struct Token *bottom; | |
42 }; | |
43 | |
44 union value | |
45 { | |
46 int num; | |
47 char fun; | |
48 Queue block; | |
49 }; | |
50 | |
51 struct Token | |
52 { | |
53 enum Typet what; | |
54 union value val; | |
55 struct Token *next; | |
56 }; | |
57 | |
58 | |
59 int is_empty(const Queue *q); // bool | |
60 void initQueue(Queue *q); // make it an empty queue | |
61 void push(struct Token *x, Queue *q); | |
62 struct Token* copyToken(const struct Token *x); | |
63 Queue copyQueue(const Queue *q); | |
64 void initToken(struct Token *x); | |
65 void pushnum(int num, Queue* q); // create NUM token and pushes it | |
66 void pushfun(char f, Queue* q); // create FUN token and pushes it | |
67 void pushblock(Queue newq, Queue* q); // create BLOCK token and pushes it | |
68 void deletetop(Queue* q); // suppose q not empty | |
69 void deleteQueue(Queue *q); | |
70 void sendback(Queue* q); // suppose q not empty, pop then push | |
71 struct Token* pop(Queue* q); // suppose q not empty | |
72 void append(Queue *q, const Queue *r); | |
73 int matchwhat(const Queue* q, const char s[]); // bool peek at first 2 "nn" "n" "." ".." "n." "b." "b" | |
74 void processFueue(Queue* q, int printmode); // the recursive function that does everything | |
75 Queue strtoqueue(const char s[], int *k); // transforms a string program into a queue program | |
76 void print_queue(const Queue *q); // prints a queue program | |
77 void error_empty(const char s[]); // raised by functions that "suppose q not empty" when q is empty | |
78 | |
79 | |
80 void processFueue(Queue* q, int printmode) | |
81 { | |
82 int time = 0; // catching input | |
83 int i = 0; // to be used for input | |
84 int a = 0, b = 0; // to be used for some FUN | |
85 struct Token* p = NULL; // even more FUN | |
86 Queue newq; // having FUN with BLOCKs (specifically '(') | |
87 initQueue(&newq); // this is done at every iteration where newq is used, though | |
88 | |
89 while (TRUE) // stops thanks to a return; when 'H' is met | |
90 { | |
91 | |
92 if (printmode) | |
93 { | |
94 print_queue(q); | |
95 printf("\n"); | |
96 } | |
97 | |
98 if (time == q->size) // if time == q->size then input char and push ascii/unicode value | |
99 { | |
100 fflush(stdout); | |
101 i = getchar(); | |
102 pushnum(i, q); | |
103 time = 0; | |
104 } | |
105 | |
106 if (q->top->what == NUM) // q not empty because of the time != q->size requirement | |
107 { | |
108 // print char with ascii/unicode value q->top->val.num | |
109 printf("%c", (char) q->top->val.num); | |
110 fflush(stdout); | |
111 deletetop(q); | |
112 time = 0; | |
113 } | |
114 else if (q->top->what == FUN) | |
115 { | |
116 char op = q->top->val.fun; | |
117 deletetop(q); | |
118 switch (op) | |
119 { | |
120 case '+': | |
121 case '*': | |
122 case '/': | |
123 if (matchwhat(q, "nn")) | |
124 { | |
125 a = q->top->val.num; | |
126 deletetop(q); | |
127 b = q->top->val.num; | |
128 deletetop(q); | |
129 if (op == '+') | |
130 { pushnum(a+b, q); } | |
131 else if (op == '*') | |
132 { pushnum(a*b, q); } | |
133 else // op == '/' | |
134 { pushnum(a/b, q); } | |
135 time = 0; | |
136 } | |
137 else | |
138 { | |
139 pushfun(op, q); | |
140 time++; | |
141 } | |
142 break; | |
143 case '-': | |
144 case '%': | |
145 if (matchwhat(q, "n")) | |
146 { | |
147 a = q->top->val.num; | |
148 deletetop(q); | |
149 pushnum( ((op == '-')?(-a):(!a)) , q); | |
150 time = 0; | |
151 } | |
152 else | |
153 { | |
154 pushfun(op, q); | |
155 time++; | |
156 } | |
157 break; | |
158 case ':': | |
159 if (!is_empty(q)) | |
160 { | |
161 push(copyToken(q->top), q); // push copy | |
162 sendback(q); // push original | |
163 time = 0; | |
164 } | |
165 else | |
166 { | |
167 pushfun(op, q); | |
168 time++; | |
169 } | |
170 break; | |
171 case '~': | |
172 if (matchwhat(q, "..")) // if q has at least two items | |
173 { | |
174 p = pop(q); | |
175 sendback(q); | |
176 push(p, q); | |
177 time = 0; | |
178 } | |
179 else | |
180 { | |
181 pushfun(op, q); | |
182 time++; | |
183 } | |
184 break; | |
185 case '!': | |
186 if (is_empty(q)) | |
187 { | |
188 pushfun(op, q); | |
189 time++; | |
190 } | |
191 else | |
192 { | |
193 deletetop(q); | |
194 time = 0; | |
195 } | |
196 break; | |
197 case '$': | |
198 if (matchwhat(q, "n.")) | |
199 { | |
200 a = q->top->val.num; | |
201 deletetop(q); | |
202 for (; a > 0; a--) | |
203 { | |
204 push(copyToken(q->top), q); | |
205 } | |
206 | |
207 deletetop(q); | |
208 | |
209 time = 0; | |
210 } | |
211 else | |
212 { | |
213 pushfun(op, q); | |
214 time++; | |
215 } | |
216 break; | |
217 case '(': | |
218 if (is_empty(q)) | |
219 { | |
220 pushfun(op, q); | |
221 time++; | |
222 } | |
223 else | |
224 { | |
225 initQueue(&newq); | |
226 push(pop(q), &newq); | |
227 pushblock(newq, q); | |
228 time = 0; | |
229 // newq is the queue inside the block | |
230 } | |
231 break; | |
232 case '<': | |
233 if (matchwhat(q, "b.")) | |
234 { | |
235 sendback(q); | |
236 push(pop(q), &(q->bottom->val.block)); | |
237 time = 0; | |
238 } | |
239 else | |
240 { | |
241 pushfun(op, q); | |
242 time++; | |
243 } | |
244 break; | |
245 case ')': | |
246 if (matchwhat(q, "b")) | |
247 { | |
248 append(q, &(q->top->val.block)); | |
249 initQueue(&(q->top->val.block)); // mandatory since | |
250 deletetop(q); // deletetop does destroy the block it contains | |
251 time = 0; | |
252 } | |
253 else | |
254 { | |
255 pushfun(op, q); | |
256 time++; | |
257 } | |
258 break; | |
259 case 'H': | |
260 // don't forget to delete the remaining of the queue here, will you? | |
261 return; | |
262 default: | |
263 // raise an error | |
264 break; | |
265 } | |
266 } | |
267 else // if q->top->what == BLOCK | |
268 { | |
269 sendback(q); | |
270 time++; | |
271 } | |
272 } | |
273 } | |
274 | |
275 | |
276 | |
277 int main(int argc, char *argv[]) | |
278 { | |
279 Queue q; | |
280 initQueue(&q); // q is empty now | |
281 char s[1000] = "72 101 108 108 111 44 32 119 111 114 108 100 33 10 H"; | |
282 int printmode = FALSE; // a debug mode that will print the fueue program at each step | |
283 int k = 0; | |
284 | |
285 switch (argc) | |
286 { | |
287 case 1: | |
288 break; | |
289 case 2: | |
290 if (strcmp(argv[1], "--print") == 0) | |
291 { | |
292 printmode = TRUE; | |
293 } | |
294 else | |
295 { | |
296 strncpy(s, argv[1], 1000); | |
297 } | |
298 break; | |
299 case 3: | |
300 strncpy(s, argv[2], 1000); | |
301 printmode = (strcmp(argv[1], "--print") == 0); | |
302 break; | |
303 default: | |
304 fprintf(stderr, "Error: %s received too many arguments. The Hello world program\n", argv[0]); | |
305 break; | |
306 } | |
307 | |
308 q = strtoqueue(s, &k); | |
309 | |
310 processFueue(&q, printmode); | |
311 return 0; | |
312 } | |
313 | |
314 | |
315 Queue strtoqueue(const char s[], int *k) // takes a fueue program as a string, and gives a queue | |
316 { | |
317 // *k is loop counter | |
318 Queue q; // the queue to be returned | |
319 initQueue(&q); | |
320 int n = 0; // decimals (usually n * 10 + 0-9) | |
321 int intmode = FALSE; // bool "we're reading a number right now" | |
322 | |
323 if (*k == -1) | |
324 { | |
325 printf("FUEUE: UNMATCHED OPENING SQUARE BRACKET PROBABLY FORGOT A CLOSING SQUARE BRACKET\n"); | |
326 return q; | |
327 } | |
328 | |
329 while (s[*k] != '\0' && s[*k] != ']') | |
330 { | |
331 if (intmode && (s[*k] > '9' || s[*k] < '0')) // if intmode ends | |
332 { | |
333 pushnum(n, &q); | |
334 n = 0; | |
335 intmode = FALSE; | |
336 } | |
337 | |
338 switch (s[*k]) | |
339 { | |
340 case '+': | |
341 case '-': | |
342 case '*': | |
343 case '/': | |
344 case '%': | |
345 case ':': | |
346 case '~': | |
347 case '!': | |
348 case '$': | |
349 case '(': | |
350 case '<': | |
351 case ')': | |
352 case 'H': | |
353 pushfun(s[*k], &q); | |
354 (*k)++; | |
355 break; | |
356 case '0': | |
357 case '1': | |
358 case '2': | |
359 case '3': | |
360 case '4': | |
361 case '5': | |
362 case '6': | |
363 case '7': | |
364 case '8': | |
365 case '9': | |
366 n = n * 10 + (int) (s[*k] - '0'); | |
367 intmode = TRUE; | |
368 (*k)++; | |
369 break; | |
370 case ' ': // whitespace | |
371 (*k)++; | |
372 break; | |
373 case '[': | |
374 (*k)++; | |
375 pushblock(strtoqueue(s, k), &q); | |
376 (*k)++; | |
377 break; | |
378 default: | |
379 printf("FUEUE: UNKNOWN %c OP\n", s[*k]); | |
380 break; | |
381 } | |
382 } | |
383 if (intmode) | |
384 { | |
385 pushnum(n, &q); | |
386 } | |
387 | |
388 if (s[*k] == '\0') | |
389 *k = -1; | |
390 return q; | |
391 } | |
392 | |
393 void print_queue(const Queue *q) | |
394 { | |
395 struct Token *ptmp = q->top; | |
396 while (ptmp != NULL) | |
397 { | |
398 if (ptmp->what == NUM) | |
399 { | |
400 printf(" %d", ptmp->val.num); | |
401 } | |
402 else if (ptmp->what == FUN) | |
403 { | |
404 printf("%c", ptmp->val.fun); | |
405 } | |
406 else if (ptmp->what == BLOCK) | |
407 { | |
408 printf("["); | |
409 print_queue(&(ptmp->val.block)); | |
410 printf("]"); | |
411 } | |
412 else | |
413 { | |
414 printf("That's impossible...Neither num nor fun nor block...\n"); | |
415 } | |
416 ptmp = ptmp->next; | |
417 } | |
418 } | |
419 | |
420 | |
421 | |
422 | |
423 int is_empty(const Queue *q) // bool | |
424 { | |
425 if (q->top == NULL) | |
426 { | |
427 if (q->bottom == NULL && q->size == 0) | |
428 { | |
429 return TRUE; | |
430 } | |
431 else | |
432 { | |
433 error_empty("is_empty"); | |
434 } | |
435 } | |
436 return FALSE; | |
437 } | |
438 | |
439 void initQueue(Queue *q) | |
440 { | |
441 q->size = 0; | |
442 q->top = NULL; | |
443 q->bottom = NULL; | |
444 } | |
445 | |
446 void push(struct Token *x, Queue *q) | |
447 { | |
448 if (is_empty(q)) | |
449 { | |
450 q->top = x; | |
451 } | |
452 else | |
453 { | |
454 q->bottom->next = x; | |
455 } | |
456 q->bottom = x; | |
457 q->size++; | |
458 x->next = NULL; // just in case | |
459 } | |
460 | |
461 Queue copyQueue(const Queue *q) | |
462 { | |
463 Queue c; | |
464 struct Token* ptmp = q->top; | |
465 initQueue(&c); | |
466 | |
467 while (ptmp != NULL) | |
468 { | |
469 push(copyToken(ptmp), &c); | |
470 ptmp = ptmp->next; | |
471 } | |
472 | |
473 return c; | |
474 } | |
475 | |
476 void initToken(struct Token *x) | |
477 { | |
478 x->what = NUM; | |
479 x->val.num = 0; | |
480 x->val.fun = '\0'; | |
481 initQueue(&(x->val.block)); | |
482 x->next = NULL; | |
483 } | |
484 | |
485 struct Token* copyToken(const struct Token *x) | |
486 { | |
487 struct Token *c = malloc(sizeof(struct Token)); | |
488 c->what = x->what; | |
489 | |
490 switch (x->what) | |
491 { | |
492 case NUM: | |
493 case FUN: | |
494 c->val = x->val; | |
495 break; | |
496 case BLOCK: | |
497 c->val.block = copyQueue(&(x->val.block)); | |
498 break; | |
499 default: | |
500 fprintf(stderr, "Error: found a %d in my soup\n", x->what); | |
501 break; | |
502 } | |
503 | |
504 c->next = NULL; | |
505 return c; | |
506 } | |
507 | |
508 void pushnum(int num, Queue* q) | |
509 { | |
510 struct Token *t = malloc(sizeof(struct Token)); | |
511 initToken(t); | |
512 t->what = NUM; | |
513 t->val.num = num; | |
514 | |
515 push(t, q); | |
516 } | |
517 | |
518 void pushfun(char f, Queue* q) | |
519 { | |
520 struct Token *t = malloc(sizeof(struct Token)); | |
521 initToken(t); | |
522 t->what = FUN; | |
523 t->val.fun = f; | |
524 push(t, q); | |
525 } | |
526 | |
527 void pushblock(Queue newq, Queue* q) | |
528 { | |
529 struct Token *t = malloc(sizeof(struct Token)); | |
530 initToken(t); | |
531 t->what = BLOCK; | |
532 t->val.block = newq; | |
533 push(t, q); | |
534 } | |
535 | |
536 void deletetop(Queue* q) // suppose q not empty | |
537 { | |
538 if (is_empty(q)) | |
539 error_empty("deletetop"); | |
540 | |
541 struct Token *todelete = NULL; | |
542 | |
543 if (q->top->what == BLOCK) // has to free the Queue inside | |
544 { | |
545 deleteQueue(&(q->top->val.block)); | |
546 } | |
547 | |
548 if (q->top->next == NULL) | |
549 { | |
550 free(q->top); | |
551 q->top = NULL; | |
552 q->bottom = NULL; | |
553 } | |
554 else | |
555 { | |
556 todelete = q->top; | |
557 q->top = q->top->next; | |
558 free(todelete); | |
559 } | |
560 q->size--; | |
561 } | |
562 | |
563 void deleteQueue(Queue *q) | |
564 { | |
565 while (!is_empty(q)) | |
566 { | |
567 deletetop(q); | |
568 } | |
569 } | |
570 | |
571 void sendback(Queue* q) // suppose q not empty, pop then push | |
572 { | |
573 if (is_empty(q)) | |
574 error_empty("sendback"); | |
575 | |
576 q->bottom->next = q->top; | |
577 q->top = q->top->next; | |
578 q->bottom = q->bottom->next; | |
579 q->bottom->next = NULL; | |
580 } | |
581 | |
582 struct Token* pop(Queue* q) // suppose q not empty | |
583 { | |
584 if (is_empty(q)) | |
585 error_empty("sendback"); | |
586 | |
587 struct Token* t = q->top; // note that t->next is equal to q->top->next now | |
588 q->top = q->top->next; | |
589 q->size--; | |
590 | |
591 return t; | |
592 } | |
593 | |
594 void append(Queue *q, const Queue *r) | |
595 { | |
596 if (is_empty(q)) | |
597 { | |
598 q->top = r->top; | |
599 q->bottom = r->bottom; | |
600 } | |
601 else if (!is_empty(r)) | |
602 { | |
603 q->bottom->next = r->top; | |
604 q->bottom = r->bottom; | |
605 } | |
606 q->size += r->size; | |
607 } | |
608 | |
609 int matchwhat(const Queue* q, const char s[]) // bool "nn" "n" "." ".." "n." "b." "b" | |
610 { | |
611 int itsok = TRUE; | |
612 if ((s[0] != '\0') && !(is_empty(q))) // if neither s nor q is empty | |
613 { | |
614 if (s[0] == 'n' && q->top->what != NUM) // if top should be num | |
615 itsok = FALSE; | |
616 if (s[0] == 'b' && q->top->what != BLOCK) // if top should be block | |
617 itsok = FALSE; | |
618 if (s[1] != '\0' && q->top->next == NULL) // if should have second element | |
619 { | |
620 itsok = FALSE; | |
621 } | |
622 else // so it indeed has a second element, or it doesn't need to have one | |
623 { | |
624 if (s[1] == 'n' && q->top->next->what != NUM) // second should be num | |
625 itsok = FALSE; | |
626 if (s[1] == 'b' && q->top->next->what != BLOCK) // second should be block | |
627 itsok = FALSE; | |
628 } | |
629 } | |
630 else | |
631 { | |
632 if (s[0] != '\0') // if s is not empty but q is | |
633 itsok = FALSE; | |
634 } | |
635 | |
636 // printf("matchwhat: %s\n", (itsok?"TRUE":"FALSE")); | |
637 return itsok; | |
638 } | |
639 | |
640 void error_empty(const char s[]) | |
641 { | |
642 fprintf(stderr, "Error: queue was empty in %s\n", s); | |
643 exit(EXIT_FAILURE); | |
644 } | |
645 | |
646 | |
647 | |
648 |