Mercurial > repo
comparison fueue.c.1 @ 1990:777b7c4e0b9b
<oerjan> fetch http://zzo38computer.org/esoteric/Arc_Koen/fueue.c
author | HackBot |
---|---|
date | Sat, 02 Feb 2013 22:54:52 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1989:41b0d1504da2 | 1990:777b7c4e0b9b |
---|---|
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 '\n': | |
371 case '\t': | |
372 case ' ': // whitespace | |
373 (*k)++; | |
374 break; | |
375 case '[': | |
376 (*k)++; | |
377 pushblock(strtoqueue(s, k), &q); | |
378 (*k)++; | |
379 break; | |
380 default: | |
381 printf("FUEUE: UNKNOWN %c OP\n", s[*k]); | |
382 (*k)++; | |
383 break; | |
384 } | |
385 } | |
386 if (intmode) | |
387 { | |
388 pushnum(n, &q); | |
389 } | |
390 | |
391 if (s[*k] == '\0') | |
392 *k = -1; | |
393 return q; | |
394 } | |
395 | |
396 void print_queue(const Queue *q) | |
397 { | |
398 struct Token *ptmp = q->top; | |
399 while (ptmp != NULL) | |
400 { | |
401 if (ptmp->what == NUM) | |
402 { | |
403 printf(" %d", ptmp->val.num); | |
404 } | |
405 else if (ptmp->what == FUN) | |
406 { | |
407 printf("%c", ptmp->val.fun); | |
408 } | |
409 else if (ptmp->what == BLOCK) | |
410 { | |
411 printf("["); | |
412 print_queue(&(ptmp->val.block)); | |
413 printf("]"); | |
414 } | |
415 else | |
416 { | |
417 printf("That's impossible...Neither num nor fun nor block...\n"); | |
418 } | |
419 ptmp = ptmp->next; | |
420 } | |
421 } | |
422 | |
423 | |
424 | |
425 | |
426 int is_empty(const Queue *q) // bool | |
427 { | |
428 if (q->top == NULL) | |
429 { | |
430 if (q->bottom == NULL && q->size == 0) | |
431 { | |
432 return TRUE; | |
433 } | |
434 else | |
435 { | |
436 error_empty("is_empty"); | |
437 } | |
438 } | |
439 return FALSE; | |
440 } | |
441 | |
442 void initQueue(Queue *q) | |
443 { | |
444 q->size = 0; | |
445 q->top = NULL; | |
446 q->bottom = NULL; | |
447 } | |
448 | |
449 void push(struct Token *x, Queue *q) | |
450 { | |
451 if (is_empty(q)) | |
452 { | |
453 q->top = x; | |
454 } | |
455 else | |
456 { | |
457 q->bottom->next = x; | |
458 } | |
459 q->bottom = x; | |
460 q->size++; | |
461 x->next = NULL; // just in case | |
462 } | |
463 | |
464 Queue copyQueue(const Queue *q) | |
465 { | |
466 Queue c; | |
467 struct Token* ptmp = q->top; | |
468 initQueue(&c); | |
469 | |
470 while (ptmp != NULL) | |
471 { | |
472 push(copyToken(ptmp), &c); | |
473 ptmp = ptmp->next; | |
474 } | |
475 | |
476 return c; | |
477 } | |
478 | |
479 void initToken(struct Token *x) | |
480 { | |
481 x->what = NUM; | |
482 x->val.num = 0; | |
483 x->val.fun = '\0'; | |
484 initQueue(&(x->val.block)); | |
485 x->next = NULL; | |
486 } | |
487 | |
488 struct Token* copyToken(const struct Token *x) | |
489 { | |
490 struct Token *c = malloc(sizeof(struct Token)); | |
491 c->what = x->what; | |
492 | |
493 switch (x->what) | |
494 { | |
495 case NUM: | |
496 case FUN: | |
497 c->val = x->val; | |
498 break; | |
499 case BLOCK: | |
500 c->val.block = copyQueue(&(x->val.block)); | |
501 break; | |
502 default: | |
503 fprintf(stderr, "Error: found a %d in my soup\n", x->what); | |
504 break; | |
505 } | |
506 | |
507 c->next = NULL; | |
508 return c; | |
509 } | |
510 | |
511 void pushnum(int num, Queue* q) | |
512 { | |
513 struct Token *t = malloc(sizeof(struct Token)); | |
514 initToken(t); | |
515 t->what = NUM; | |
516 t->val.num = num; | |
517 | |
518 push(t, q); | |
519 } | |
520 | |
521 void pushfun(char f, Queue* q) | |
522 { | |
523 struct Token *t = malloc(sizeof(struct Token)); | |
524 initToken(t); | |
525 t->what = FUN; | |
526 t->val.fun = f; | |
527 push(t, q); | |
528 } | |
529 | |
530 void pushblock(Queue newq, Queue* q) | |
531 { | |
532 struct Token *t = malloc(sizeof(struct Token)); | |
533 initToken(t); | |
534 t->what = BLOCK; | |
535 t->val.block = newq; | |
536 push(t, q); | |
537 } | |
538 | |
539 void deletetop(Queue* q) // suppose q not empty | |
540 { | |
541 if (is_empty(q)) | |
542 error_empty("deletetop"); | |
543 | |
544 struct Token *todelete = NULL; | |
545 | |
546 if (q->top->what == BLOCK) // has to free the Queue inside | |
547 { | |
548 deleteQueue(&(q->top->val.block)); | |
549 } | |
550 | |
551 if (q->top->next == NULL) | |
552 { | |
553 free(q->top); | |
554 q->top = NULL; | |
555 q->bottom = NULL; | |
556 } | |
557 else | |
558 { | |
559 todelete = q->top; | |
560 q->top = q->top->next; | |
561 free(todelete); | |
562 } | |
563 q->size--; | |
564 } | |
565 | |
566 void deleteQueue(Queue *q) | |
567 { | |
568 while (!is_empty(q)) | |
569 { | |
570 deletetop(q); | |
571 } | |
572 } | |
573 | |
574 void sendback(Queue* q) // suppose q not empty, pop then push | |
575 { | |
576 if (is_empty(q)) | |
577 error_empty("sendback"); | |
578 | |
579 q->bottom->next = q->top; | |
580 q->top = q->top->next; | |
581 q->bottom = q->bottom->next; | |
582 q->bottom->next = NULL; | |
583 } | |
584 | |
585 struct Token* pop(Queue* q) // suppose q not empty | |
586 { | |
587 if (is_empty(q)) | |
588 error_empty("sendback"); | |
589 | |
590 struct Token* t = q->top; // note that t->next is equal to q->top->next now | |
591 q->top = q->top->next; | |
592 q->size--; | |
593 | |
594 return t; | |
595 } | |
596 | |
597 void append(Queue *q, const Queue *r) | |
598 { | |
599 if (is_empty(q)) | |
600 { | |
601 q->top = r->top; | |
602 q->bottom = r->bottom; | |
603 } | |
604 else if (!is_empty(r)) | |
605 { | |
606 q->bottom->next = r->top; | |
607 q->bottom = r->bottom; | |
608 } | |
609 q->size += r->size; | |
610 } | |
611 | |
612 int matchwhat(const Queue* q, const char s[]) // bool "nn" "n" "." ".." "n." "b." "b" | |
613 { | |
614 int itsok = TRUE; | |
615 if ((s[0] != '\0') && !(is_empty(q))) // if neither s nor q is empty | |
616 { | |
617 if (s[0] == 'n' && q->top->what != NUM) // if top should be num | |
618 itsok = FALSE; | |
619 if (s[0] == 'b' && q->top->what != BLOCK) // if top should be block | |
620 itsok = FALSE; | |
621 if (s[1] != '\0' && q->top->next == NULL) // if should have second element | |
622 { | |
623 itsok = FALSE; | |
624 } | |
625 else // so it indeed has a second element, or it doesn't need to have one | |
626 { | |
627 if (s[1] == 'n' && q->top->next->what != NUM) // second should be num | |
628 itsok = FALSE; | |
629 if (s[1] == 'b' && q->top->next->what != BLOCK) // second should be block | |
630 itsok = FALSE; | |
631 } | |
632 } | |
633 else | |
634 { | |
635 if (s[0] != '\0') // if s is not empty but q is | |
636 itsok = FALSE; | |
637 } | |
638 | |
639 // printf("matchwhat: %s\n", (itsok?"TRUE":"FALSE")); | |
640 return itsok; | |
641 } | |
642 | |
643 void error_empty(const char s[]) | |
644 { | |
645 fprintf(stderr, "Error: queue was empty in %s\n", s); | |
646 exit(EXIT_FAILURE); | |
647 } | |
648 | |
649 | |
650 |