Blob Blame Raw

#include <math.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>



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