git @ Cat's Eye Technologies Pixley / master impl / mignon / parse.c
master

Tree @master (Download .tar.gz)

parse.c @masterraw · history · blame

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

#include "parse.h"
#include "sexp.h"

struct pstate *initial_pstate(const char *string)
{
    struct pstate *state;
    state = malloc(sizeof(struct pstate));
    state->ptr = string;
    state->result = NULL;
    state->child_result = NULL;
    state->status = P_START;
    state->parent = NULL;
    return state;
}

static struct pstate *stack_pstate(struct pstate *parent)
{
    struct pstate *state;
    state = malloc(sizeof(struct pstate));
    state->ptr = parent->ptr;
    state->result = NULL;
    state->child_result = NULL;
    state->status = P_START;
    state->parent = parent;
    return state;
}

static struct pstate *unstack_pstate(struct pstate *state)
{
    struct pstate *parent = state->parent;
    parent->ptr = state->ptr;
    parent->child_result = state->result;
    free(state);
    return parent;
}

void dump_pstate(struct pstate *state)
{
    while (state != NULL) {
        fprintf(stderr, "{%s,%d}", state->ptr, state->status);
        state = state->parent;
    }
    fprintf(stderr, "!\n");
}

struct pstate *parse_resumable(struct pstate *state)
{
    int done = 0;
    while (!done) {
#ifdef DEBUG
        dump_pstate(state);
#endif
        switch (state->status) {
            case P_START:
            {
                while (isspace((int)*(state->ptr))) {
                    state->ptr++;
                }
                if (*(state->ptr) == (char)0) {
                    return state;
                }
                if (*(state->ptr) == '(') {
                    state->ptr++;
                    state->status = P_LIST;
                    state->head = NULL;
                    state->tail = NULL;
                    state->prev = NULL;
                } else {
                    state->status = P_ATOM;
                }
                break;
            }
            case P_ATOM:
            {
                char sym[128];
                int i = 0;
                while (isalpha((int)*(state->ptr)) ||
                       isdigit((int)*(state->ptr)) ||
                       *(state->ptr) == '*' ||
                       *(state->ptr) == '-' ||
                       *(state->ptr) == '_' ||
                       *(state->ptr) == '?') {
                    sym[i] = *(state->ptr);
                    state->ptr++;
                    i++;
                }
                sym[i] = 0;
                state->result = atom(sym);
                state->status = P_DONE;
                break;
            }
            case P_LIST:
            {
                /* if we just parsed a child of this list... */
                if (state->child_result != NULL) {
                    state->tail = (struct cons *)cons(nil, nil);
                    if (state->prev != NULL) {
                        state->prev->tail = (struct value *)state->tail;
                    }
                    if (state->head == NULL) {
                        state->head = state->tail;
                    }
                    state->tail->head = state->child_result;
                    state->child_result = NULL;
                    state->prev = state->tail;
                }
                while (isspace((int)*(state->ptr))) {
                    state->ptr++;
                }
                if (*(state->ptr) == (char)0) {
                    return state;
                }
                if (*(state->ptr) == ')') {
                    state->ptr++;
                    if (state->head == NULL) {
                        state->result = nil;
                    } else {
                        state->result = (struct value *)state->head;
                    }
                    state->status = P_DONE;
                    break;
                } else {
                    /* create a new level in P_START. */
                    state = stack_pstate(state);
                }
                break;
            }
            case P_DONE:
                if (state->parent != NULL) {
                    state = unstack_pstate(state);
                } else {
                    done = 1;
                }
                break;
        }
    }
    return state;
}