#include #include #include #include #include #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; icursor;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; } }