// vim: set ts=4 sw=4 et tw=80:

#include <stdio.h>
#include <stdlib.h>
#include "bexp.h"
#include "ctype.h"

typedef struct stack {
    value first;
    struct stack* next;
    char container[];
} expr_stack_t;

static void read_word();
static void read_value();
static void read_command();
static void discard();
static int ensure(char* str);
static void print_value(const value* val);
static void read_command();

static expr_stack_t* tos = NULL;

int main() {
    while(!feof(stdin)) {
        read_word();
    }
}

void discard() {
    fprintf(stderr, "Input malformed. Discarding until space...\n");
    while(!isspace(getchar()));
    return;
}

void read_word() {
    char c;
    while (isspace(c = getchar()));
    ungetc(c, stdin);
    if (c == '0' || c == '1') {
        read_value();
    } else {
        read_command();
    }
}

void read_value() {
    int str_size = 10;
    expr_stack_t* new = malloc(sizeof(expr_stack_t) + str_size * sizeof(char));
    if (!new) {
        perror("Cannot allocate new stack element");
        return;
    }
    new->next = tos;

    int count = 0;
    int c;
    while(!isspace(c = getchar())) {
        if (c != '0' && c != '1') {
            free(new);
            discard();
            return;
        }

        new->container[count++] = c;

        if (str_size == count) {
            str_size *= 2;
            new = realloc(new, sizeof(expr_stack_t) + str_size * sizeof(char));
            if (!new) {
                perror("Cannot allocate new stack element");
                free(new);
                return;
            }
        }
    }

    // reverse the string in container to match least to most significant order
    // in bexp
    char* i = new->container;
    char* j = new->container + count - 1;
    while (i < j) {
        char tmp = *i;
        *i = *j;
        *j = tmp;
        i++;
        j--;
    }

    new->first.begin = new->container;
    new->first.end = new->container + count;
    tos = new;
}

int ensure(char* str) {
    while (*str) {
        if (tolower(getchar()) != *str) {
            return 0;
        }
        str++;
    }
    return 1;
}

void print_value(const value* val) {
    char* v = val->end - 1;
    while (v >= val->begin) putchar(*(v--));
    putchar('\n');
}

void read_command() {
    operator_t op;
    switch(getchar()) {
        case '&': op = AND; break;
        case '|': op = OR; break;
        case '^': op = XOR; break;
        case '+': op = PLUS; break;
        case '>': op = GREATER_THAN; break;
        case '<': op = LESS_THAN; break;
        case '!': op = NOT; break;
        case '~': op = COMPLEMENT; break;
        case 't':
        case 'T':
                  if (!ensure("op")) {
                      discard();
                  } else {
                      if (tos == NULL) {
                          printf("empty\n");
                      } else {
                          print_value(&(tos->first));
                      }
                  }
                  return;
        case 'p':
        case 'P':
                  if (!ensure("op")) {
                      discard();
                  } else {
                      if (tos == NULL) {
                          printf("empty\n");
                      } else {
                          print_value(&(tos->first));
                          expr_stack_t* t = tos;
                          tos = tos->next;
                          free(t);
                      }
                  }
                  return;
        default: discard(); return;
    }

    int binary = op != NOT && op != COMPLEMENT;

    if (tos == NULL || (binary && tos->next == NULL)) {
        printf("too few values on stack\n");
        return;
    }

    const static value dummy = { NULL, NULL };
    expression ex = { op, tos->first, binary ? tos->next->first : dummy };
    int length = bexp_length(&ex);

    expr_stack_t* new_tos = malloc(sizeof(expr_stack_t) + sizeof(char) * length);
    if (!new_tos) {
        perror("Cannot allocate space for result");
        return;
    }
    new_tos->first.begin = new_tos->container;
    new_tos->first.end = new_tos->container + length;

    bexp_evaluate(&new_tos->first, &ex);
    expr_stack_t* new_next = tos->next;
    free(tos);
    tos = new_next;

    if (binary) {
        new_next = tos->next;
        free(tos);
        tos = new_next;
    }

    new_tos->next = tos;
    tos = new_tos;
}
