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