changeset 1990:777b7c4e0b9b

<oerjan> fetch http://zzo38computer.org/esoteric/Arc_Koen/fueue.c
author HackBot
date Sat, 02 Feb 2013 22:54:52 +0000
parents 41b0d1504da2
children 511c13628966
files fueue.c.1
diffstat 1 files changed, 650 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fueue.c.1	Sat Feb 02 22:54:52 2013 +0000
@@ -0,0 +1,650 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define TRUE 1
+#define FALSE 0
+
+/*
+ * Fueue Interpreter in language C
+ *   the esoteric programming language Fueue was designed in 2012 by Taneb.
+ *
+ * The following program was written by Stephan Kunne on august 29 2012.
+ * It is public domain; you are free to use it, copy it, distribute it,
+ * or do whatever you'd like with it.
+ * Credit and feedback are always appreciated ; you can email me at
+ * firstname dot name at gmail dot com with all your questions or remarks.
+ *
+ * Examples:
+ *
+ *    ./fueuec '72 101 108 108 111 44 32 119 111 114 108 100 33 10 H'
+ *    Hello, world!
+ *
+ *    ./fueuec --print '):[):]'
+ *    ):[):]
+ *    :[):])
+ *    )[):][):]
+ *    [):]):
+ *    ):[):]
+ *    (...and so on)
+ */
+
+enum Typet
+{
+    NUM, FUN, BLOCK
+};
+
+typedef struct Queue Queue;
+struct Queue
+{
+    int size;
+    struct Token *top;
+    struct Token *bottom;
+};
+
+union value
+{
+    int num;
+    char fun;
+    Queue block;
+};
+
+struct Token
+{
+    enum Typet what;
+    union value val;
+    struct Token *next;
+};
+
+
+int is_empty(const Queue *q);  // bool
+void initQueue(Queue *q);  // make it an empty queue
+void push(struct Token *x, Queue *q);
+struct Token* copyToken(const struct Token *x);
+Queue copyQueue(const Queue *q);
+void initToken(struct Token *x);
+void pushnum(int num, Queue* q);  // create NUM token and pushes it
+void pushfun(char f, Queue* q);  // create FUN token and pushes it
+void pushblock(Queue newq, Queue* q);  // create BLOCK token and pushes it
+void deletetop(Queue* q);  // suppose q not empty
+void deleteQueue(Queue *q);
+void sendback(Queue* q);  // suppose q not empty, pop then push
+struct Token* pop(Queue* q);  // suppose q not empty
+void append(Queue *q, const Queue *r);
+int matchwhat(const Queue* q, const char s[]);  // bool peek at first 2 "nn" "n" "." ".." "n." "b." "b"
+void processFueue(Queue* q, int printmode);  // the recursive function that does everything
+Queue strtoqueue(const char s[], int *k);  // transforms a string program into a queue program
+void print_queue(const Queue *q);  // prints a queue program
+void error_empty(const char s[]);  // raised by functions that "suppose q not empty" when q is empty
+
+
+void processFueue(Queue* q, int printmode)
+{
+    int time = 0;  // catching input
+    int i = 0;  // to be used for input
+    int a = 0, b = 0; // to be used for some FUN
+    struct Token* p = NULL; // even more FUN
+    Queue newq;  // having FUN with BLOCKs (specifically '(')
+    initQueue(&newq);  // this is done at every iteration where newq is used, though
+
+    while (TRUE)  // stops thanks to a return; when 'H' is met
+    {
+    
+        if (printmode)
+        {
+            print_queue(q);
+            printf("\n");
+        }
+
+        if (time == q->size)  // if time == q->size then input char and push ascii/unicode value
+        {
+            fflush(stdout);
+            i = getchar();
+            pushnum(i, q);
+            time = 0;
+        }
+
+        if (q->top->what == NUM) // q not empty because of the time != q->size requirement
+        {
+            // print char with ascii/unicode value q->top->val.num
+            printf("%c", (char) q->top->val.num);
+            fflush(stdout);
+            deletetop(q);
+            time = 0;
+        }
+        else if (q->top->what == FUN)
+        {
+            char op = q->top->val.fun;
+            deletetop(q);
+            switch (op)
+            {
+                case '+':
+                case '*':
+                case '/':
+                    if (matchwhat(q, "nn"))
+                    {
+                        a = q->top->val.num;
+                        deletetop(q);
+                        b = q->top->val.num;
+                        deletetop(q);
+                        if (op == '+')
+                            { pushnum(a+b, q); }
+                        else if (op == '*')
+                            { pushnum(a*b, q); }
+                        else // op == '/'
+                            { pushnum(a/b, q); }
+                        time = 0;
+                    }
+                    else
+                    {
+                        pushfun(op, q);
+                        time++;
+                    }
+                    break;
+                case '-':
+                case '%':
+                    if (matchwhat(q, "n"))
+                    {
+                        a = q->top->val.num;
+                        deletetop(q);
+                        pushnum( ((op == '-')?(-a):(!a)) , q);
+                        time = 0;
+                    }
+                    else
+                    {
+                        pushfun(op, q);
+                        time++;
+                    }
+                    break;
+                case ':':
+                    if (!is_empty(q))
+                    {
+                        push(copyToken(q->top), q);  // push copy
+                        sendback(q);  // push original
+                        time = 0;
+                    }
+                    else
+                    {
+                        pushfun(op, q);
+                        time++;
+                    }
+                    break;
+                case '~':
+                    if (matchwhat(q, "..")) // if q has at least two items
+                    {
+                        p = pop(q);
+                        sendback(q);
+                        push(p, q);
+                        time = 0;
+                    }
+                    else
+                    {
+                        pushfun(op, q);
+                        time++;
+                    }
+                    break;
+                case '!':
+                    if (is_empty(q))
+                    {
+                        pushfun(op, q);
+                        time++;
+                    }
+                    else
+                    {
+                        deletetop(q);
+                        time = 0;
+                    }
+                    break;
+                case '$':
+                    if (matchwhat(q, "n."))
+                    {
+                        a = q->top->val.num;
+                        deletetop(q);
+                        for (; a > 0; a--)
+                        {
+                            push(copyToken(q->top), q);
+                        }
+                        
+                        deletetop(q);
+                        
+                        time = 0;
+                    }
+                    else
+                    {
+                        pushfun(op, q);
+                        time++;
+                    }
+                    break;
+                case '(':
+                    if (is_empty(q))
+                    {
+                        pushfun(op, q);
+                        time++;
+                    }
+                    else
+                    {
+                        initQueue(&newq);
+                        push(pop(q), &newq);
+                        pushblock(newq, q);
+                        time = 0;
+                        // newq is the queue inside the block
+                    }
+                    break;
+                case '<':
+                    if (matchwhat(q, "b."))
+                    {
+                        sendback(q);
+                        push(pop(q), &(q->bottom->val.block));
+                        time = 0;
+                    }
+                    else
+                    {
+                        pushfun(op, q);
+                        time++;
+                    }
+                    break;
+                case ')':
+                    if (matchwhat(q, "b"))
+                    {
+                        append(q, &(q->top->val.block));
+                        initQueue(&(q->top->val.block));  // mandatory since
+                        deletetop(q);  // deletetop does destroy the block it contains
+                        time = 0;
+                    }
+                    else
+                    {
+                        pushfun(op, q);
+                        time++;
+                    }
+                    break;
+                case 'H':
+                    // don't forget to delete the remaining of the queue here, will you?
+                    return;
+                default:
+                    // raise an error
+                    break;
+            }
+        }
+        else // if q->top->what == BLOCK
+        {
+            sendback(q);
+            time++;
+        }
+    }
+}
+
+
+
+int main(int argc, char *argv[])
+{
+    Queue q;
+    initQueue(&q);  // q is empty now
+    char s[1000] = "72 101 108 108 111 44 32 119 111 114 108 100 33 10 H";
+    int printmode = FALSE;  // a debug mode that will print the fueue program at each step
+    int k = 0;
+
+    switch (argc)
+    {
+        case 1:
+            break;
+        case 2:
+            if (strcmp(argv[1], "--print") == 0)
+            {
+                printmode = TRUE;
+            }
+            else
+            {
+                strncpy(s, argv[1], 1000);
+            }
+            break;
+        case 3:
+            strncpy(s, argv[2], 1000);
+            printmode = (strcmp(argv[1], "--print") == 0);
+            break;
+        default:
+            fprintf(stderr, "Error: %s received too many arguments. The Hello world program\n", argv[0]);
+            break;
+    }
+
+    q = strtoqueue(s, &k);
+
+    processFueue(&q, printmode);
+    return 0;
+}
+
+
+Queue strtoqueue(const char s[], int *k)  // takes a fueue program as a string, and gives a queue
+{
+    // *k is loop counter
+    Queue q;  // the queue to be returned
+    initQueue(&q);
+    int n = 0;  // decimals (usually n * 10 + 0-9)
+    int intmode = FALSE;  // bool "we're reading a number right now"
+
+    if (*k == -1)
+    {
+        printf("FUEUE: UNMATCHED OPENING SQUARE BRACKET PROBABLY FORGOT A CLOSING SQUARE BRACKET\n");
+        return q;
+    }
+
+    while (s[*k] != '\0' && s[*k] != ']')
+    {
+        if (intmode && (s[*k] > '9' || s[*k] < '0'))  // if intmode ends
+        {
+            pushnum(n, &q);
+            n = 0;
+            intmode = FALSE;
+        }
+
+        switch (s[*k])
+        {
+            case '+':
+            case '-':
+            case '*':
+            case '/':
+            case '%':
+            case ':':
+            case '~':
+            case '!':
+            case '$':
+            case '(':
+            case '<':
+            case ')':
+            case 'H':
+                pushfun(s[*k], &q);
+                (*k)++;
+                break;
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+                n = n * 10 + (int) (s[*k] - '0');
+                intmode = TRUE;
+                (*k)++;
+                break;
+            case '\n':
+            case '\t':
+            case ' ':  // whitespace
+                (*k)++;
+                break;
+            case '[':
+                (*k)++;
+                pushblock(strtoqueue(s, k), &q);
+                (*k)++;
+                break;
+            default:
+                printf("FUEUE: UNKNOWN %c OP\n", s[*k]);
+                (*k)++;
+                break;
+        }
+    }
+    if (intmode)
+    {
+        pushnum(n, &q);
+    }
+
+    if (s[*k] == '\0')
+        *k = -1;
+    return q;
+}
+
+void print_queue(const Queue *q)
+{
+    struct Token *ptmp = q->top;
+    while (ptmp != NULL)
+    {
+        if (ptmp->what == NUM)
+        {
+            printf(" %d", ptmp->val.num);
+        }
+        else if (ptmp->what == FUN)
+        {
+            printf("%c", ptmp->val.fun);
+        }
+        else if (ptmp->what == BLOCK)
+        {
+            printf("[");
+            print_queue(&(ptmp->val.block));
+            printf("]");
+        }
+        else
+        {
+            printf("That's impossible...Neither num nor fun nor block...\n");
+        }
+        ptmp = ptmp->next;
+    }
+}
+
+
+
+
+int is_empty(const Queue *q) // bool
+{
+    if (q->top == NULL)
+    {
+        if (q->bottom == NULL && q->size == 0)
+        {
+            return TRUE;
+        }
+        else
+        {
+            error_empty("is_empty");
+        }
+    }
+    return FALSE;
+}
+
+void initQueue(Queue *q)
+{
+    q->size = 0;
+    q->top = NULL;
+    q->bottom = NULL;
+}
+
+void push(struct Token *x, Queue *q)
+{
+    if (is_empty(q))
+    {
+        q->top = x;
+    }
+    else
+    {
+        q->bottom->next = x;
+    }
+    q->bottom = x;
+    q->size++;
+    x->next = NULL;  // just in case
+}
+
+Queue copyQueue(const Queue *q)
+{
+    Queue c;
+    struct Token* ptmp = q->top;
+    initQueue(&c);
+
+    while (ptmp != NULL)
+    {
+        push(copyToken(ptmp), &c);
+        ptmp = ptmp->next;
+    }
+
+    return c;
+}
+
+void initToken(struct Token *x)
+{
+    x->what = NUM;
+    x->val.num = 0;
+    x->val.fun = '\0';
+    initQueue(&(x->val.block));
+    x->next = NULL;
+}
+
+struct Token* copyToken(const struct Token *x)
+{
+    struct Token *c = malloc(sizeof(struct Token));
+    c->what = x->what;
+    
+    switch (x->what)
+    {
+        case NUM:
+        case FUN:
+            c->val = x->val;
+            break;
+        case BLOCK:
+            c->val.block = copyQueue(&(x->val.block));
+            break;
+        default:
+            fprintf(stderr, "Error: found a %d in my soup\n", x->what);
+            break;
+    }
+
+    c->next = NULL;
+    return c;
+}
+
+void pushnum(int num, Queue* q)
+{
+    struct Token *t = malloc(sizeof(struct Token));
+    initToken(t);
+    t->what = NUM;
+    t->val.num = num;
+    
+    push(t, q);
+}
+
+void pushfun(char f, Queue* q)
+{
+    struct Token *t = malloc(sizeof(struct Token));
+    initToken(t);
+    t->what = FUN;
+    t->val.fun = f;
+    push(t, q);
+}
+
+void pushblock(Queue newq, Queue* q)
+{
+    struct Token *t = malloc(sizeof(struct Token));
+    initToken(t);
+    t->what = BLOCK;
+    t->val.block = newq;
+    push(t, q);
+}
+
+void deletetop(Queue* q)  // suppose q not empty
+{
+    if (is_empty(q))
+        error_empty("deletetop");
+
+    struct Token *todelete = NULL;
+
+    if (q->top->what == BLOCK)  // has to free the Queue inside
+    {
+        deleteQueue(&(q->top->val.block));
+    }
+
+    if (q->top->next == NULL)
+    {
+        free(q->top);
+        q->top = NULL;
+        q->bottom = NULL;
+    }
+    else
+    {
+        todelete = q->top;
+        q->top = q->top->next;
+        free(todelete);
+    }
+    q->size--;
+}
+
+void deleteQueue(Queue *q)
+{
+    while (!is_empty(q))
+    {
+        deletetop(q);
+    }
+}
+
+void sendback(Queue* q) // suppose q not empty, pop then push
+{
+    if (is_empty(q))
+        error_empty("sendback");
+
+    q->bottom->next = q->top;
+    q->top = q->top->next;
+    q->bottom = q->bottom->next;
+    q->bottom->next = NULL;
+}
+
+struct Token* pop(Queue* q) // suppose q not empty
+{
+    if (is_empty(q))
+        error_empty("sendback");
+
+    struct Token* t = q->top;  // note that t->next is equal to q->top->next now
+    q->top = q->top->next;
+    q->size--;
+
+    return t;    
+}
+
+void append(Queue *q, const Queue *r)
+{
+    if (is_empty(q))
+    {
+        q->top = r->top;
+        q->bottom = r->bottom;
+    }
+    else if (!is_empty(r))
+    {
+        q->bottom->next = r->top;
+        q->bottom = r->bottom;
+    }
+    q->size += r->size;
+}
+
+int matchwhat(const Queue* q, const char s[])  // bool "nn" "n" "." ".." "n." "b." "b"
+{
+    int itsok = TRUE;
+    if ((s[0] != '\0') && !(is_empty(q)))  // if neither s nor q is empty
+    {
+        if (s[0] == 'n' && q->top->what != NUM) // if top should be num
+            itsok = FALSE;
+        if (s[0] == 'b' && q->top->what != BLOCK) // if top should be block
+            itsok = FALSE;
+        if (s[1] != '\0' && q->top->next == NULL) // if should have second element
+        {
+            itsok = FALSE;
+        }
+        else  // so it indeed has a second element, or it doesn't need to have one
+        {
+            if (s[1] == 'n' && q->top->next->what != NUM) // second should be num
+                itsok = FALSE;
+            if (s[1] == 'b' && q->top->next->what != BLOCK) // second should be block
+                itsok = FALSE;
+        }
+    }
+    else
+    {
+        if (s[0] != '\0') // if s is not empty but q is
+            itsok = FALSE;
+    }
+
+    // printf("matchwhat: %s\n", (itsok?"TRUE":"FALSE"));
+    return itsok;
+}
+
+void error_empty(const char s[])
+{
+    fprintf(stderr, "Error: queue was empty in %s\n", s);
+    exit(EXIT_FAILURE);
+}
+
+
+