Blob Blame Raw


#include "funcs.c"


enum {
  K_NONE = 0,
  K_POPEN,
  K_PCLOSE,
  K_BPOPEN,
  K_BCLOSE,
  K_COMMA,
  K_COLON,
};
const char *baseKeys[] = { "", "(", ")", "[", "]", ",", ":" };


typedef struct Op {
  const OpDesc *desc;
  Var v;
  struct Op *a, *b, *c;
} Op;



void prepareKeys() {
  if (keys) return;
  keys = (const char**)calloc(1, sizeof(baseKeys) + sizeof(char*)*opsCnt);
  if (!keys) { fprintf(stderr, "out of memory\n"); exit(1); }
  memcpy(keys, baseKeys, sizeof(baseKeys));
  keysCnt = sizeof(baseKeys)/sizeof(*baseKeys);

  for(int i = 0; i < opsCnt; ++i) {
    OpDesc *d = &ops[i];
    d->k = 0;
    if (!d->key || !*d->key) continue;
    for(int j = 1; j < keysCnt; ++j)
      if (0 == strcmp(keys[j], d->key)) { d->k = j; break; }
    if (!d->k) {
      d->k = keysCnt;
      keys[keysCnt++] = d->key;
    }
  }
}



Op* opCreate(const OpDesc *d) {
  Op *op = (Op*)calloc(1, sizeof(*op));
  if (!op) { fprintf(stderr, "out of memory\n"); exit(1); }
  op->desc = d;
  return op;
}


void opDestroy(Op *op) {
  if (!op) return;
  opDestroy(op->a);
  opDestroy(op->b);
  opDestroy(op->c);
  free(op);
}


Var opCall(Op *op, U32 t);


Op* opSubItem(Op *op, U32 t, U32 idx) {
  while(op && op->desc) {
    if (op->desc->mode == M_ARRAY) {
      while(op && idx) { op = op->b; --idx; }
      return op ? op->a : op;
    } else
    if (op->desc->mode == M_INDEX) {
      U32 i = asint(opCall(op->b, t));
      op = opSubItem(op->a, t, i);
    } else {
      return op;
    }
  }
  return NULL;
}


Var opCall(Op *op, U32 t) {
  if (!op || !op->desc) return vari(0);
  if (!op->desc->func) {
    if (op->desc->mode == M_INDEX) {
      U32 idx = asint(opCall(op->b, t));
      Op *o = opSubItem(op->a, t, idx);
      return opCall(o, t);
    }
    if (op->desc->mode == M_ARRAY)
      return opCall(op->a, t);
    return op->v;
  }
  Params p = { t, opCall(op->a, t), opCall(op->b, t), opCall(op->c, t) };
  return op->desc->func(p);
}


void opPrint(Op *op, FILE *f, int level) {
  if (!f) f = stdout;
  for(int i = 0; i < level; ++i)
    fprintf(f, "  ");
  if (!op || !op->desc)
    { fprintf(f, "nop\n"); return; }
  if (!op->desc->func && op->desc->mode != M_ARRAY && op->desc->mode != M_INDEX)
    { fprintf(f, "value: %d, %d, %g\n", op->v.type, op->v.u, op->v.f); return; }
  fprintf(f, "%d:%d:%s:\n", op->desc->mode, op->desc->priority, op->desc->key);
  ++level;
  opPrint(op->a, f, level);
  opPrint(op->b, f, level);
  opPrint(op->c, f, level);
}


Op* opParsePart(const Lex **l, int priority);


Op* opParseParentheses(const Lex **p) {
  const Lex *l = *p;
  if (iskey(l++, K_POPEN)) {
    Op *op = opParsePart(&l, INT_MAX);
    if (op && iskey(l++, K_PCLOSE))
      return *p = l, op;
    opDestroy(op);
  }
  return NULL;
}


Op* opParseValue(const Lex **p, const OpDesc *d) {
  const Lex *l = *p;
  if ( d->k ? iskey(l, d->k) : (l->type == LT_INT || l->type == LT_FLOAT) ) {
    Op *op = opCreate(d);
    op->v.type = l->type == LT_FLOAT ? T_F32 : T_U32;
    op->v.u = l->u;
    return *p = l + 1, op;
  }
  return NULL;
}


Op* opParseArray(const Lex **p, const OpDesc *d) {
  const Lex *l = *p;
  if (iskey(l++, d->k)) {
    Op *op = opCreate(d), *o = op;
    while(1) {
      o->a = opParsePart(&l, INT_MAX);
      if (iskey(l, K_BCLOSE)) return *p = l + 1, op;
      if (!iskey(l++, K_COMMA)) break;
      o->b = opCreate(d);
      o = o->b;
    };
    opDestroy(op);
  }
  return NULL;
}


Op* opParseIndex(const Lex **p, Op *a, const OpDesc *d) {
  const Lex *l = *p;
  if (iskey(l++, d->k)) {
    Op *b = opParsePart(&l, INT_MAX);
    if (b && iskey(l++, K_BCLOSE)) {
      Op *op = opCreate(d);
      op->a = a;
      op->b = b;
      return *p = l, op;
    }
    opDestroy(b);
  }
  return NULL;
}


Op* opParsePrefix(const Lex **p, const OpDesc *d) {
  const Lex *l = *p;
  if (iskey(l++, d->k)) {
    Op *sub = opParsePart(&l, d->priority);
    if (sub) {
      Op *op = opCreate(d);
      op->a = sub;
      return *p = l, op;
    }
  }
  return NULL;
}


Op* opParseBinary(const Lex **p, Op *a, const OpDesc *d) {
  const Lex *l = *p;
  if (iskey(l++, d->k)) {
    Op *b = opParsePart(&l, d->priority);
    if (b) {
      Op *op = opCreate(d);
      if (b->desc->priority == d->priority) {
        op->a = a;
        op->b = b->a;
        b->a = op;
        op = b;
      } else {
        op->a = a;
        op->b = b;
      }
      return *p = l, op;
    }
  }
  return NULL;
}


Op* opParseTernary(const Lex **p, Op *a, const OpDesc *d) {
  const Lex *l = *p;
  if (iskey(l++, d->k)) {
    Op *b = opParsePart(&l, d->priority - 1);
    if (b && iskey(l++, K_COLON)) {
      Op *c = opParsePart(&l, d->priority);
      if (c) {
        Op *op = opCreate(d);
        op->a = a;
        op->b = b;
        op->c = c;
        return *p = l, op;
      }
    }
    opDestroy(b);
  }
  return NULL;
}


Op* opParseFunc(const Lex **p, const OpDesc *d) {
  const Lex *l = *p;
  if (iskey(l++, d->k) && iskey(l++, K_POPEN)) {
    Op *sub = opParsePart(&l, INT_MAX);
    if (sub && iskey(l++, K_PCLOSE)) {
      Op *op = opCreate(d);
      op->a = sub;
      return *p = l, op;
    }
    opDestroy(sub);
  }
  return NULL;
}


Op* opParseFunc2(const Lex **p, const OpDesc *d) {
  const Lex *l = *p;
  if (iskey(l++, d->k) && iskey(l++, K_POPEN)) {
    Op *a = opParsePart(&l, INT_MAX);
    if (a && iskey(l++, K_COMMA)) {
      Op *b = opParsePart(&l, INT_MAX);
      if (b && iskey(l++, K_PCLOSE)) {
        Op *op = opCreate(d);
        op->a = a;
        op->b = b;
        return *p = l, op;
      }
      opDestroy(b);
    }
    opDestroy(a);
  }
  return NULL;
}


Op* opParsePart(const Lex **p, int priority) {
  //static int level = 0;
  //printf("opParsePart:%d:%d:", level, priority);
  //lexChainPrint(*p, NULL);
  //printf("\n");
  //++level;

  const Lex *l = *p;
  Op *op = opParseParentheses(&l);
  for(int i = 0; i < opsCnt; ++i) {
    //printf("  i = %d\n", i);
    const OpDesc *d = &ops[i];
    if (d->priority > priority) break;
    switch(d->mode) {
    case M_VALUE:
      if (!op) op = opParseValue(&l, d);
      break;
    case M_ARRAY:
      if (!op) op = opParseArray(&l, d);
      break;
    case M_INDEX:
      if (op) {
        Op *o = opParseIndex(&l, op, d);
        if (o) { op = o; i = 0; }
      }
      break;
    case M_PREFIX:
      if (!op) op = opParsePrefix(&l, d);
      break;
    case M_BINARY:
      if (op) {
        Op *o = opParseBinary(&l, op, d);
        if (o) { op = o; i = 0; }
      }
      break;
    case M_TERNARY:
      if (op) {
        Op *o = opParseTernary(&l, op, d);
        if (o) { op = o; i = 0; }
      }
      break;
    case M_FUNC:
      if (!op) op = opParseFunc(&l, d);
      break;
    case M_FUNC2:
      if (!op) op = opParseFunc2(&l, d);
      break;
    }
  }
  if (op) *p = l;

  //--level;
  return op;
}


Op* opParse(const Lex *l) {
  Op *op = opParsePart(&l, INT_MAX);
  if (!op || l->type != LT_NONE)
    { fprintf(stderr, "parse error at: "); lexChainPrint(l, stderr); fprintf(stderr, "\n"); }
  return op;
}