2138
|
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[10000] = "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], 10000);
|
|
297 }
|
|
298 break;
|
|
299 case 3:
|
|
300 strncpy(s, argv[2], 10000);
|
|
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
|