#include <math.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>
typedef int I32;
typedef unsigned int U32;
typedef float F32;
typedef enum {
LT_NONE = 0,
LT_KEY,
LT_INT,
LT_FLOAT,
} LexType;
typedef struct {
LexType type;
union {
U32 u;
F32 f;
};
} Lex;
typedef struct {
Lex *data;
size_t size;
} LexList;
const char **keys;
int keysCnt;
static inline int iskey(const Lex *l, U32 k)
{ return l && l->type == LT_KEY && l->u == k; }
static inline const char* skipSpaces(const char *s)
{ while(isspace(*s)) ++s; return s; }
void lexPrint(const Lex *l, FILE *f) {
if (!f) f = stdout;
switch(l->type) {
case LT_NONE:
fprintf(f, "[none]");
break;
case LT_KEY:
if (l->u < keysCnt) fprintf(f, "[key:%d:%s]", l->u, keys[l->u]);
else fprintf(f, "[key:%d]", l->u);
break;
case LT_INT:
fprintf(f, "[int:%x:%d]", l->u, l->u);
break;
case LT_FLOAT:
fprintf(f, "[float:%x:%g]", l->u, l->f);
break;
default:
fprintf(f, "[unknown:%u:%08x]", l->type, l->u);
break;
}
}
void lexChainPrint(const Lex *l, FILE *f) {
do { lexPrint(l, f); } while((l++)->type);
}
int lexParseEnd(Lex *l, const char **p) {
const char *s = skipSpaces(*p);
if (*s) return 0;
l->type = LT_NONE;
*p = s;
return 1;
}
int lexParseKey(Lex *l, const char **p) {
const char *s = skipSpaces(*p);
size_t maxlen = 0;
U32 key = 0;
for(U32 i = 1; i < keysCnt; ++i) {
size_t len = strlen(keys[i]);
if (len > maxlen && 0 == strncmp(s, keys[i], len))
{ key = i; maxlen = len; }
}
if (!key) return 0;
l->type = LT_KEY;
l->u = key;
*p = s + maxlen;
return 1;
}
int lexParseNum(Lex *l, const char **p) {
const char *s = skipSpaces(*p);
const char *s0 = s;
U32 factor = 10;
if (*s == '0') {
++s;
if (*s >= '0' && *s <= '7') factor = 8; else
if (*s == 'x' || *s == 'X') { s0 = ++s; factor = 16; }
}
U32 iv = 0;
double fv = 0;
while(1) {
U32 d = 0;
if (*s >= '0' && *s <= '9') d = *s - '0'; else
if (*s >= 'a' && *s <= 'f') d = *s - 'a' + 10; else
if (*s >= 'A' && *s <= 'F') d = *s - 'A' + 10; else
break;
if (d >= factor) break;
iv = iv*factor + d;
fv = fv*factor + d;
++s;
}
int success = 0;
if (s > s0) {
l->type = LT_INT;
l->u = iv;
*p = s;
success = 1;
}
if (factor != 10) return success;
s0 = s;
if (*s == '.') {
++s;
double f = 1;
while(*s >= '0' && *s <= '9')
fv += (f *= 0.1)*(*s++ - '0');
}
if (s > s0 && (*s == 'e' || *s == 'E')) {
double e = 0;
double sign = (*s == '-' || *s == '+') && (*s++ == '-') ? -1 : 1;
s0 = s;
while(*s >= '0' && *s <= '9')
e = e*10 + (*s++ - '0');
fv *= pow(10, e*sign);
}
if (s <= s0) return success;
if (*s == 'f') ++s;
l->type = LT_FLOAT;
l->f = fv;
*p = s;
return 1;
}
void lexListDeinit(LexList *ll)
{ free(ll->data); memset(ll, 0, sizeof(*ll)); }
Lex* lexListAdd(LexList *ll) {
++ll->size;
ll->data = (Lex*)realloc(ll->data, sizeof(*ll->data) * ll->size);
if (!ll->data) { fprintf(stderr, "out of memory\n"); exit(1); }
Lex *l = ll->data + ll->size - 1;
memset(l, 0, sizeof(*l));
return l;
}
void lexListPrint(const LexList *ll, FILE *f) {
if (!f) f = stdout;
fprintf(f, "count %zu: ", ll->size);
for(size_t i = 0; i < ll->size; ++i)
lexPrint(ll->data + i, f);
fprintf(f, "\n");
}
int lexListParse(LexList *ll, const char *s) {
lexListDeinit(ll);
Lex *l = lexListAdd(ll);
while(1) {
if (lexParseEnd(l, &s)) break;
if (!lexParseKey(l, &s) && !lexParseNum(l, &s))
{ fprintf(stderr, "lex parse error at: %s\n", s); return 0; }
l = lexListAdd(ll);
}
return 1;
}
Lex* lexParse(const char *s) {
LexList ll = {};
lexListParse(&ll, s);
return ll.data;
}