ycl

Artifact [287821d4c5]
Login

Artifact [287821d4c5]

Artifact 287821d4c557455d1e8e4728fff7dbece3fe9bac:


#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define growby 1<<8
#define initcount 3

#define states_m(f) \
    f(command) \
    f(command_1) \
    f(end) \
    f(print) \
    f(word_1) \
    f(word_2) \
    f(word_3)

#define states_comma(f) f,
#define states_case(f) case (f): goto f;

FILE *streamin;


enum states {
    states_m(states_comma)
};

enum types {
    _int
    , _char
};

enum wordstate {
    curly
    ,square
    ,dquote
};

typedef struct array {
    void *val;
    enum types type;
    size_t size;
    size_t count;
    size_t cursor;
} array;

static inline array* array_resize(array* array ,size_t newsize) {
    array->val = realloc(array->val ,newsize);
}

static inline array* checksize (array* array) {
    if (array->cursor >= array->count) {
	array_resize(array ,array->size * (array->count = array->count + growby));
    }
}

static inline array* array_init(array* array ,size_t size ,size_t count) {
    array->cursor = 0;
    array->size = size;
    if (count == 0) {
	array->count = initcount;
    } else {
	array->count = count;
    }
    if (size > 0) {
	array->val = calloc(array->count ,array->size);
    }
    return array;
}

static inline void * push (array* array ,void* val ,size_t size) {
    checksize(array);
    assert(size % array->size == 0);
    void *address = array->val + (array->cursor++ * size);
    memmove(address ,val ,size);
    /*
    memmove(array->val + (array->cursor++ * size) ,val ,size);
    */
    return address;
}

static inline void* pop (array* array ,size_t size) {
    if (array->count <1) {
	return(0);
    }
    return((array->val + (--array->cursor * size)));
}

/*TODO: why can't this function be called "index"? */
static inline void* index (array* array , size_t idx) {
    return (void *)array->val + (array->size * idx);
}

static inline array* pushenum (array* array ,enum states state) {
    push(array ,&state ,sizeof(state));
    return array;
}

static inline array_free(array* array) {
    free(array->val);
    array->cursor = 0;
    array->count = 0;
    array->size = 0;
}

int main (int argc, char *argv[]) {
    streamin = stdin;
    array statestack;
    array_init(&statestack ,sizeof(enum states) ,0);
    enum states state = command;
    array res;
    pushenum(&statestack , command);

    control: {
	state = *(enum states*)pop(&statestack ,sizeof(state));
	printf("current state: %d\n" ,state);
	switch (state) {
	    states_m(states_case)
	    default:
		printf("bad state: %d\n" ,state);
		exit(1);
	}
	goto control;
    }
    command: {
	char *word;
	size_t i;
	static int initialized = 0;
	static array words;
	static array* values;
	static array* indexes;
	if (!initialized) {
	    array_init(&words ,sizeof(array) ,2);
	    values = &((array *)words.val)[0];
	    array_init(values ,sizeof(char) ,100);
	    indexes = &((array *)words.val)[1];
	    array_init(indexes ,sizeof(void *) ,100);
	    initialized = 1;
	}
	pushenum(&statestack ,command_1);
	goto word;
	command_1: {
	    word = (char *)((array *)res.val)->val;
	    if (strlen(word) == 1 && word[0] == '\n') {
		for (i=0; i<indexes->cursor;i++) {
		    printf("got this word: %s\n" , ((char **)indexes->val)[i]);
		}
	    } else {
		word = (char *)push(values ,word ,strlen(word)+1);
		push(indexes ,&word ,sizeof(word));
		goto command;
	    }
	}
    }
    end: {
	exit(0);
    }
    inword: {
	goto control;
    }
    inchar: {
	static array input;
	static int initialized = 0;
	if (!initialized) {
	    array_init(&input ,sizeof(char) ,initcount);
	}
	static int line = 0;

	if (input.cursor == 0) {
	    /*
	    no getline support with OS X Snow Leopard gcc :(
	    size_t linesize = input.size * input.count;
	    getline(input.val, &linesize, stdin);
	    if (linesize != input.size * input.count) {
		input.count = linesize / input.size;
	    }
	    */
	    ((char *)input.val)[input.cursor] = getc(streamin);
	    if (*(char *)input.val <0 || !memcmp(input.val ,"quit\n", 5) || feof(stdin)) {
		printf("quitting!\n");
		exit(0);
	    }
	    line++;
	}
	res.val = input.val;
	res.type = _char;
	res.cursor = 0;
	if (input.cursor >= input.count) {
	    input.cursor = 0;
	} else {
	    input.cursor++;
	}
	goto control;
    }

    print: {
	printf("got:%c\n" ,((char *)res.val)[0]);
	goto control;
    }
    word: {
	static array word;
	static char null = '\0';
	char thischar;
	array_init(&word ,sizeof(char) ,0);
	((char *)word.val)[(word.count*word.size)-word.size] = '\0';
	word_1:
	    pushenum(&statestack , word_2); 
	    goto inchar;
	    word_2:
		thischar = *((char *)res.val);
		if (thischar == ' ' || thischar == '\0'
		    || thischar == '\n') {
		    if (thischar == '\n') {
			push(&word ,&thischar ,sizeof(thischar));
		    }
		    ((char *)word.val)[word.cursor++] = '\0';
		    if (word.cursor != 0) {
			/*
			"return" a word to the "caller"
			*/
			res.val = (void *)&word;
			res.type = _char;
			res.cursor = 1;
			goto control;
		    }
		} else {
		    push(&word ,&thischar ,sizeof(thischar));
		    goto word_1;
		}
	pushenum(&statestack ,word_3);
	word_3:
	    pushenum(&statestack ,end);
	    goto control;
    }
}