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