123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975 |
- #ifndef EXPR_H
- #define EXPR_H
- #ifdef _MSC_VER
- #pragma warning(push)
- // Disable warning for zero-sized array:
- #pragma warning(disable : 4200)
- #endif
- #ifdef __cplusplus
- extern "C" {
- #endif
- #include <ctype.h> /* for isspace */
- #include <limits.h>
- #include <math.h> /* for pow */
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- /*
- * Simple expandable vector implementation
- */
- static int vec_expand(char **buf, int *length, int *cap, int memsz) {
- if (*length + 1 > *cap) {
- void *ptr;
- int n = (*cap == 0) ? 1 : *cap << 1;
- ptr = realloc(*buf, n * memsz);
- if (ptr == NULL) {
- return -1; /* allocation failed */
- }
- *buf = (char *)ptr;
- *cap = n;
- }
- return 0;
- }
- #define vec(T) \
- struct { \
- T *buf; \
- int len; \
- int cap; \
- }
- #define vec_init() \
- { NULL, 0, 0 }
- #define vec_len(v) ((v)->len)
- #define vec_unpack(v) \
- (char **)&(v)->buf, &(v)->len, &(v)->cap, sizeof(*(v)->buf)
- #define vec_push(v, val) \
- vec_expand(vec_unpack(v)) ? -1 : ((v)->buf[(v)->len++] = (val), 0)
- #define vec_nth(v, i) (v)->buf[i]
- #define vec_peek(v) (v)->buf[(v)->len - 1]
- #define vec_pop(v) (v)->buf[--(v)->len]
- #define vec_free(v) (free((v)->buf), (v)->buf = NULL, (v)->len = (v)->cap = 0)
- #define vec_foreach(v, var, iter) \
- if ((v)->len > 0) \
- for ((iter) = 0; (iter) < (v)->len && (((var) = (v)->buf[(iter)]), 1); \
- ++(iter))
- /*
- * Expression data types
- */
- struct expr;
- struct expr_func;
- enum expr_type {
- OP_UNKNOWN,
- OP_UNARY_MINUS,
- OP_UNARY_LOGICAL_NOT,
- OP_UNARY_BITWISE_NOT,
- OP_POWER,
- OP_DIVIDE,
- OP_MULTIPLY,
- OP_REMAINDER,
- OP_PLUS,
- OP_MINUS,
- OP_SHL,
- OP_SHR,
- OP_LT,
- OP_LE,
- OP_GT,
- OP_GE,
- OP_EQ,
- OP_NE,
- OP_BITWISE_AND,
- OP_BITWISE_OR,
- OP_BITWISE_XOR,
- OP_LOGICAL_AND,
- OP_LOGICAL_OR,
- OP_ASSIGN,
- OP_COMMA,
- OP_CONST,
- OP_VAR,
- OP_STRING,
- OP_FUNC,
- };
- static int prec[] = {0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 5, 5,
- 5, 5, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 0, 0};
- typedef vec(struct expr) vec_expr_t;
- typedef void (*exprfn_cleanup_t)(struct expr_func *f, void *context);
- typedef double (*exprfn_t)(struct expr_func *f, vec_expr_t *args,
- void *context);
- struct expr {
- enum expr_type type;
- union {
- struct {
- double value;
- } num;
- struct {
- double *value;
- } var;
- struct {
- vec_expr_t args;
- } op;
- struct {
- char *s;
- } str;
- struct {
- struct expr_func *f;
- vec_expr_t args;
- void *context;
- } func;
- } param;
- };
- #define expr_init() \
- { (enum expr_type)0 }
- struct expr_string {
- const char *s;
- int n;
- };
- struct expr_arg {
- int oslen;
- int eslen;
- vec_expr_t args;
- };
- typedef vec(struct expr_string) vec_str_t;
- typedef vec(struct expr_arg) vec_arg_t;
- static int expr_is_unary(enum expr_type op) {
- return op == OP_UNARY_MINUS || op == OP_UNARY_LOGICAL_NOT ||
- op == OP_UNARY_BITWISE_NOT;
- }
- static int expr_is_binary(enum expr_type op) {
- return !expr_is_unary(op) && op != OP_CONST && op != OP_VAR &&
- op != OP_FUNC && op != OP_UNKNOWN && op != OP_STRING;
- }
- static int expr_prec(enum expr_type a, enum expr_type b) {
- int left =
- expr_is_binary(a) && a != OP_ASSIGN && a != OP_POWER && a != OP_COMMA;
- return (left && prec[a] >= prec[b]) || (prec[a] > prec[b]);
- }
- #define isfirstvarchr(c) \
- (((unsigned char)c >= '@' && c != '^' && c != '|' && c != '~') || c == '$')
- #define isvarchr(c) \
- (((unsigned char)c >= '@' && c != '^' && c != '|' && c != '~') || \
- c == '$' || c == '#' || (c >= '0' && c <= '9'))
- static struct {
- const char *s;
- const enum expr_type op;
- } OPS[] = {
- {"-u", OP_UNARY_MINUS},
- {"!u", OP_UNARY_LOGICAL_NOT},
- {"~u", OP_UNARY_BITWISE_NOT},
- {"**", OP_POWER},
- {"*", OP_MULTIPLY},
- {"/", OP_DIVIDE},
- {"%", OP_REMAINDER},
- {"+", OP_PLUS},
- {"-", OP_MINUS},
- {"<<", OP_SHL},
- {">>", OP_SHR},
- {"<", OP_LT},
- {"<=", OP_LE},
- {">", OP_GT},
- {">=", OP_GE},
- {"==", OP_EQ},
- {"!=", OP_NE},
- {"&", OP_BITWISE_AND},
- {"|", OP_BITWISE_OR},
- {"^", OP_BITWISE_XOR},
- {"&&", OP_LOGICAL_AND},
- {"||", OP_LOGICAL_OR},
- {"=", OP_ASSIGN},
- {",", OP_COMMA},
- /* These are used by lexer and must be ignored by parser, so we put
- them at the end */
- {"-", OP_UNARY_MINUS},
- {"!", OP_UNARY_LOGICAL_NOT},
- {"~", OP_UNARY_BITWISE_NOT},
- };
- static enum expr_type expr_op(const char *s, size_t len, int unary) {
- for (unsigned int i = 0; i < sizeof(OPS) / sizeof(OPS[0]); i++) {
- if (strlen(OPS[i].s) == len && strncmp(OPS[i].s, s, len) == 0 &&
- (unary == -1 || expr_is_unary(OPS[i].op) == unary)) {
- return OPS[i].op;
- }
- }
- return OP_UNKNOWN;
- }
- static double expr_parse_number(const char *s, size_t len) {
- double num = 0;
- char buf[32];
- char *sz = buf;
- char *end = NULL;
- if (len >= sizeof(buf)) {
- sz = (char *)calloc(1, len + 1);
- if (sz == NULL) {
- return NAN;
- }
- }
- strncpy(sz, s, len);
- sz[len] = '\0';
- num = strtod(sz, &end);
- if (sz != buf) {
- free(sz);
- }
- return (end == sz + len ? num : NAN);
- }
- /*
- * Functions
- */
- struct expr_func {
- const char *name;
- exprfn_t f;
- exprfn_cleanup_t cleanup;
- size_t ctxsz;
- };
- static struct expr_func *expr_get_func(struct expr_func *funcs, const char *s,
- size_t len) {
- for (struct expr_func *f = funcs; f->name; f++) {
- if (strlen(f->name) == len && strncmp(f->name, s, len) == 0) {
- return f;
- }
- }
- return NULL;
- }
- /*
- * Variables
- */
- struct expr_var {
- double value;
- struct expr_var *next;
- char name[];
- };
- struct expr_var_list {
- struct expr_var *head;
- };
- static struct expr_var *expr_get_var(struct expr_var_list *vars, const char *s,
- size_t len) {
- struct expr_var *v = NULL;
- if (len == 0 || !isfirstvarchr(*s)) {
- return NULL;
- }
- for (v = vars->head; v; v = v->next) {
- if (strlen(v->name) == len && strncmp(v->name, s, len) == 0) {
- return v;
- }
- }
- v = (struct expr_var *)calloc(1, sizeof(struct expr_var) + len + 1);
- if (v == NULL) {
- return NULL; /* allocation failed */
- }
- v->next = vars->head;
- v->value = 0;
- strncpy(v->name, s, len);
- v->name[len] = '\0';
- vars->head = v;
- return v;
- }
- static int64_t to_int(double x) {
- if (isnan(x)) {
- return 0;
- } else if (isinf(x) != 0) {
- return INT64_MAX * isinf(x);
- } else {
- return (int64_t)x;
- }
- }
- static const char *expr_get_str(struct expr *e) {
- if (e->type != OP_STRING)
- return NULL;
- return e->param.str.s;
- }
- static double expr_eval(struct expr *e) {
- double n;
- switch (e->type) {
- case OP_UNARY_MINUS:
- return -(expr_eval(&e->param.op.args.buf[0]));
- case OP_UNARY_LOGICAL_NOT:
- return !(expr_eval(&e->param.op.args.buf[0]));
- case OP_UNARY_BITWISE_NOT:
- return ~(to_int(expr_eval(&e->param.op.args.buf[0])));
- case OP_POWER:
- return pow(expr_eval(&e->param.op.args.buf[0]),
- expr_eval(&e->param.op.args.buf[1]));
- case OP_MULTIPLY:
- return expr_eval(&e->param.op.args.buf[0]) *
- expr_eval(&e->param.op.args.buf[1]);
- case OP_DIVIDE:
- return expr_eval(&e->param.op.args.buf[0]) /
- expr_eval(&e->param.op.args.buf[1]);
- case OP_REMAINDER:
- return fmod(expr_eval(&e->param.op.args.buf[0]),
- expr_eval(&e->param.op.args.buf[1]));
- case OP_PLUS:
- return expr_eval(&e->param.op.args.buf[0]) +
- expr_eval(&e->param.op.args.buf[1]);
- case OP_MINUS:
- return expr_eval(&e->param.op.args.buf[0]) -
- expr_eval(&e->param.op.args.buf[1]);
- case OP_SHL:
- return to_int(expr_eval(&e->param.op.args.buf[0]))
- << to_int(expr_eval(&e->param.op.args.buf[1]));
- case OP_SHR:
- return to_int(expr_eval(&e->param.op.args.buf[0])) >>
- to_int(expr_eval(&e->param.op.args.buf[1]));
- case OP_LT:
- return expr_eval(&e->param.op.args.buf[0]) <
- expr_eval(&e->param.op.args.buf[1]);
- case OP_LE:
- return expr_eval(&e->param.op.args.buf[0]) <=
- expr_eval(&e->param.op.args.buf[1]);
- case OP_GT:
- return expr_eval(&e->param.op.args.buf[0]) >
- expr_eval(&e->param.op.args.buf[1]);
- case OP_GE:
- return expr_eval(&e->param.op.args.buf[0]) >=
- expr_eval(&e->param.op.args.buf[1]);
- case OP_EQ:
- return expr_eval(&e->param.op.args.buf[0]) ==
- expr_eval(&e->param.op.args.buf[1]);
- case OP_NE:
- return expr_eval(&e->param.op.args.buf[0]) !=
- expr_eval(&e->param.op.args.buf[1]);
- case OP_BITWISE_AND:
- return to_int(expr_eval(&e->param.op.args.buf[0])) &
- to_int(expr_eval(&e->param.op.args.buf[1]));
- case OP_BITWISE_OR:
- return to_int(expr_eval(&e->param.op.args.buf[0])) |
- to_int(expr_eval(&e->param.op.args.buf[1]));
- case OP_BITWISE_XOR:
- return to_int(expr_eval(&e->param.op.args.buf[0])) ^
- to_int(expr_eval(&e->param.op.args.buf[1]));
- case OP_LOGICAL_AND:
- n = expr_eval(&e->param.op.args.buf[0]);
- if (n != 0) {
- n = expr_eval(&e->param.op.args.buf[1]);
- if (n != 0) {
- return n;
- }
- }
- return 0;
- case OP_LOGICAL_OR:
- n = expr_eval(&e->param.op.args.buf[0]);
- if (n != 0 && !isnan(n)) {
- return n;
- } else {
- n = expr_eval(&e->param.op.args.buf[1]);
- if (n != 0) {
- return n;
- }
- }
- return 0;
- case OP_ASSIGN:
- n = expr_eval(&e->param.op.args.buf[1]);
- if (vec_nth(&e->param.op.args, 0).type == OP_VAR) {
- *e->param.op.args.buf[0].param.var.value = n;
- }
- return n;
- case OP_COMMA:
- expr_eval(&e->param.op.args.buf[0]);
- return expr_eval(&e->param.op.args.buf[1]);
- case OP_CONST:
- return e->param.num.value;
- case OP_VAR:
- return *e->param.var.value;
- case OP_FUNC:
- return e->param.func.f->f(e->param.func.f, &e->param.func.args,
- e->param.func.context);
- default:
- return NAN;
- }
- }
- #define EXPR_TOP (1 << 0)
- #define EXPR_TOPEN (1 << 1)
- #define EXPR_TCLOSE (1 << 2)
- #define EXPR_TLITERAL (1 << 3)
- #define EXPR_TWORD (1 << 4)
- #define EXPR_TDEFAULT (EXPR_TOPEN | EXPR_TLITERAL | EXPR_TWORD)
- #define EXPR_UNARY (1 << 5)
- #define EXPR_COMMA (1 << 6)
- static int expr_next_token(const char *s, size_t len, int *flags) {
- unsigned int i = 0;
- if (len == 0) {
- return 0;
- }
- char c = s[0];
- if (c == '#') {
- for (; i < len && s[i] != '\n'; i++)
- ;
- return i;
- } else if (c == '\n') {
- for (; i < len && isspace(s[i]); i++)
- ;
- if (*flags & EXPR_TOP) {
- if (i == len || s[i] == ')') {
- *flags = *flags & (~EXPR_COMMA);
- } else {
- *flags = EXPR_TLITERAL | EXPR_TWORD | EXPR_TOPEN | EXPR_COMMA;
- }
- }
- return i;
- } else if (isspace(c)) {
- while (i < len && isspace(s[i]) && s[i] != '\n') {
- i++;
- }
- return i;
- } else if (isdigit(c)) {
- if ((*flags & EXPR_TLITERAL) == 0) {
- return -1; // unexpected number
- }
- *flags = EXPR_TOP | EXPR_TCLOSE;
- if (c == '0') {
- i++;
- if (i < len && (s[i] == 'x' || s[i] == 'X')) {
- i++;
- for (; i < len && isxdigit(s[i]); i++)
- ;
- return i;
- }
- }
- for (; i < len && (s[i] == '.' || isdigit(s[i])); i++)
- ;
- if (i < len && (s[i] == 'e' || s[i] == 'E')) {
- i++;
- if (i < len && (s[i] == '+' || s[i] == '-'))
- i++;
- for (; i < len && isdigit(s[i]); i++)
- ;
- }
- return i;
- } else if (c == '"') {
- if ((*flags & EXPR_TLITERAL) == 0) {
- return -6; // unexpected string
- }
- *flags = EXPR_TOP | EXPR_TCLOSE;
- i++;
- for (; i < len && s[i] != '"'; i++)
- ;
- if (i >= len) {
- return -7; // missing expected quote
- }
- i++;
- return i;
- } else if (isfirstvarchr(c)) {
- if ((*flags & EXPR_TWORD) == 0) {
- return -2; // unexpected word
- }
- *flags = EXPR_TOP | EXPR_TOPEN | EXPR_TCLOSE;
- while ((isvarchr(c)) && i < len) {
- i++;
- c = s[i];
- }
- return i;
- } else if (c == '(' || c == ')') {
- if (c == '(' && (*flags & EXPR_TOPEN) != 0) {
- *flags = EXPR_TLITERAL | EXPR_TWORD | EXPR_TOPEN | EXPR_TCLOSE;
- } else if (c == ')' && (*flags & EXPR_TCLOSE) != 0) {
- *flags = EXPR_TOP | EXPR_TCLOSE;
- } else {
- return -3; // unexpected parenthesis
- }
- return 1;
- } else {
- if ((*flags & EXPR_TOP) == 0) {
- if (expr_op(&c, 1, 1) == OP_UNKNOWN) {
- return -4; // missing expected operand
- }
- *flags = EXPR_TLITERAL | EXPR_TWORD | EXPR_TOPEN | EXPR_UNARY;
- return 1;
- } else {
- int found = 0;
- while (!isvarchr(c) && !isspace(c) && c != '(' && c != ')' && i < len) {
- if (expr_op(s, i + 1, 0) != OP_UNKNOWN) {
- found = 1;
- } else if (found) {
- break;
- }
- i++;
- c = s[i];
- }
- if (!found) {
- return -5; // unknown operator
- }
- *flags = EXPR_TLITERAL | EXPR_TWORD | EXPR_TOPEN;
- return i;
- }
- }
- }
- #define EXPR_PAREN_ALLOWED 0
- #define EXPR_PAREN_EXPECTED 1
- #define EXPR_PAREN_FORBIDDEN 2
- static int expr_bind(const char *s, size_t len, vec_expr_t *es) {
- enum expr_type op = expr_op(s, len, -1);
- if (op == OP_UNKNOWN) {
- return -1;
- }
- if (expr_is_unary(op)) {
- if (vec_len(es) < 1) {
- return -1;
- }
- struct expr arg = vec_pop(es);
- struct expr unary = expr_init();
- unary.type = op;
- vec_push(&unary.param.op.args, arg);
- vec_push(es, unary);
- } else {
- if (vec_len(es) < 2) {
- return -1;
- }
- struct expr b = vec_pop(es);
- struct expr a = vec_pop(es);
- struct expr binary = expr_init();
- binary.type = op;
- if (op == OP_ASSIGN && a.type != OP_VAR) {
- return -1; /* Bad assignment */
- }
- vec_push(&binary.param.op.args, a);
- vec_push(&binary.param.op.args, b);
- vec_push(es, binary);
- }
- return 0;
- }
- static struct expr expr_const(double value) {
- struct expr e = expr_init();
- e.type = OP_CONST;
- e.param.num.value = value;
- return e;
- }
- static struct expr expr_varref(struct expr_var *v) {
- struct expr e = expr_init();
- e.type = OP_VAR;
- e.param.var.value = &v->value;
- return e;
- }
- static struct expr expr_binary(enum expr_type type, struct expr a,
- struct expr b) {
- struct expr e = expr_init();
- e.type = type;
- vec_push(&e.param.op.args, a);
- vec_push(&e.param.op.args, b);
- return e;
- }
- static inline void expr_copy(struct expr *dst, struct expr *src) {
- int i;
- struct expr arg;
- dst->type = src->type;
- if (src->type == OP_FUNC) {
- dst->param.func.f = src->param.func.f;
- vec_foreach(&src->param.func.args, arg, i) {
- struct expr tmp = expr_init();
- expr_copy(&tmp, &arg);
- vec_push(&dst->param.func.args, tmp);
- }
- if (src->param.func.f->ctxsz > 0) {
- dst->param.func.context = calloc(1, src->param.func.f->ctxsz);
- }
- } else if (src->type == OP_CONST) {
- dst->param.num.value = src->param.num.value;
- } else if (src->type == OP_VAR) {
- dst->param.var.value = src->param.var.value;
- } else if (src->type == OP_STRING) {
- size_t len = strlen(src->param.str.s);
- dst->param.str.s = (char *)calloc(1, len + 1);
- if (dst->param.str.s != NULL) {
- strncpy(dst->param.str.s, src->param.str.s, len);
- }
- } else {
- vec_foreach(&src->param.op.args, arg, i) {
- struct expr tmp = expr_init();
- expr_copy(&tmp, &arg);
- vec_push(&dst->param.op.args, tmp);
- }
- }
- }
- static void expr_destroy_args(struct expr *e);
- static struct expr *expr_create(const char *s, size_t len,
- struct expr_var_list *vars,
- struct expr_func *funcs) {
- double num;
- const char *id = NULL;
- size_t idn = 0;
- struct expr *result = NULL;
- vec_expr_t es = vec_init();
- vec_str_t os = vec_init();
- vec_arg_t as = vec_init();
- struct macro {
- char *name;
- vec_expr_t body;
- };
- vec(struct macro) macros = vec_init();
- int flags = EXPR_TDEFAULT;
- int paren = EXPR_PAREN_ALLOWED;
- for (;;) {
- int n = expr_next_token(s, len, &flags);
- if (n == 0) {
- break;
- } else if (n < 0) {
- goto cleanup;
- }
- const char *tok = s;
- s = s + n;
- len = len - n;
- if (*tok == '#') {
- continue;
- }
- if (flags & EXPR_UNARY) {
- if (n == 1) {
- switch (*tok) {
- case '-':
- tok = "-u";
- break;
- case '~':
- tok = "~u";
- break;
- case '!':
- tok = "!u";
- break;
- default:
- goto cleanup;
- }
- n = 2;
- }
- }
- if (*tok == '\n' && (flags & EXPR_COMMA)) {
- flags = flags & (~EXPR_COMMA);
- n = 1;
- tok = ",";
- }
- if (isspace(*tok)) {
- continue;
- }
- int paren_next = EXPR_PAREN_ALLOWED;
- if (idn > 0) {
- struct expr_var *v;
- if (n == 1 && *tok == '(') {
- int i;
- int has_macro = 0;
- struct macro m;
- vec_foreach(¯os, m, i) {
- if (strlen(m.name) == idn && strncmp(m.name, id, idn) == 0) {
- has_macro = 1;
- break;
- }
- }
- if ((idn == 1 && id[0] == '$') || has_macro ||
- expr_get_func(funcs, id, idn) != NULL) {
- struct expr_string str = {id, (int)idn};
- vec_push(&os, str);
- paren = EXPR_PAREN_EXPECTED;
- } else {
- goto cleanup; /* invalid function name */
- }
- } else if ((v = expr_get_var(vars, id, idn)) != NULL) {
- vec_push(&es, expr_varref(v));
- paren = EXPR_PAREN_FORBIDDEN;
- }
- id = NULL;
- idn = 0;
- }
- if (n == 1 && *tok == '(') {
- if (paren == EXPR_PAREN_EXPECTED) {
- struct expr_string str = {"{", 1};
- vec_push(&os, str);
- struct expr_arg arg = {vec_len(&os), vec_len(&es), vec_init()};
- vec_push(&as, arg);
- } else if (paren == EXPR_PAREN_ALLOWED) {
- struct expr_string str = {"(", 1};
- vec_push(&os, str);
- } else {
- goto cleanup; // Bad call
- }
- } else if (paren == EXPR_PAREN_EXPECTED) {
- goto cleanup; // Bad call
- } else if (n == 1 && *tok == ')') {
- int minlen = (vec_len(&as) > 0 ? vec_peek(&as).oslen : 0);
- while (vec_len(&os) > minlen && *vec_peek(&os).s != '(' &&
- *vec_peek(&os).s != '{') {
- struct expr_string str = vec_pop(&os);
- if (expr_bind(str.s, str.n, &es) == -1) {
- goto cleanup;
- }
- }
- if (vec_len(&os) == 0) {
- goto cleanup; // Bad parens
- }
- struct expr_string str = vec_pop(&os);
- if (str.n == 1 && *str.s == '{') {
- str = vec_pop(&os);
- struct expr_arg arg = vec_pop(&as);
- if (vec_len(&es) > arg.eslen) {
- vec_push(&arg.args, vec_pop(&es));
- }
- if (str.n == 1 && str.s[0] == '$') {
- if (vec_len(&arg.args) < 1) {
- vec_free(&arg.args);
- goto cleanup; /* too few arguments for $() function */
- }
- struct expr *u = &vec_nth(&arg.args, 0);
- if (u->type != OP_VAR) {
- vec_free(&arg.args);
- goto cleanup; /* first argument is not a variable */
- }
- for (struct expr_var *v = vars->head; v; v = v->next) {
- if (&v->value == u->param.var.value) {
- struct macro m = {v->name, arg.args};
- vec_push(¯os, m);
- break;
- }
- }
- vec_push(&es, expr_const(0));
- } else {
- int i = 0;
- int found = -1;
- struct macro m;
- vec_foreach(¯os, m, i) {
- if (strlen(m.name) == (size_t)str.n &&
- strncmp(m.name, str.s, str.n) == 0) {
- found = i;
- }
- }
- if (found != -1) {
- m = vec_nth(¯os, found);
- struct expr root = expr_const(0);
- struct expr *p = &root;
- /* Assign macro parameters */
- for (int j = 0; j < vec_len(&arg.args); j++) {
- char varname[13];
- snprintf(varname, sizeof(varname), "$%d", (j + 1));
- struct expr_var *v = expr_get_var(vars, varname, strlen(varname));
- struct expr ev = expr_varref(v);
- struct expr assign =
- expr_binary(OP_ASSIGN, ev, vec_nth(&arg.args, j));
- *p = expr_binary(OP_COMMA, assign, expr_const(0));
- p = &vec_nth(&p->param.op.args, 1);
- }
- /* Expand macro body */
- for (int j = 1; j < vec_len(&m.body); j++) {
- if (j < vec_len(&m.body) - 1) {
- *p = expr_binary(OP_COMMA, expr_const(0), expr_const(0));
- expr_copy(&vec_nth(&p->param.op.args, 0), &vec_nth(&m.body, j));
- } else {
- expr_copy(p, &vec_nth(&m.body, j));
- }
- p = &vec_nth(&p->param.op.args, 1);
- }
- vec_push(&es, root);
- vec_free(&arg.args);
- } else {
- struct expr_func *f = expr_get_func(funcs, str.s, str.n);
- struct expr bound_func = expr_init();
- bound_func.type = OP_FUNC;
- bound_func.param.func.f = f;
- bound_func.param.func.args = arg.args;
- if (f->ctxsz > 0) {
- void *p = calloc(1, f->ctxsz);
- if (p == NULL) {
- goto cleanup; /* allocation failed */
- }
- bound_func.param.func.context = p;
- }
- vec_push(&es, bound_func);
- }
- }
- }
- paren_next = EXPR_PAREN_FORBIDDEN;
- } else if (!isnan(num = expr_parse_number(tok, n))) {
- vec_push(&es, expr_const(num));
- paren_next = EXPR_PAREN_FORBIDDEN;
- } else if (n > 1 && *tok == '"') {
- char *str = (char *)calloc(1, n - 1);
- if (str == NULL) {
- goto cleanup; /* allocation failed */
- }
- strncpy(str, tok + 1, n - 2);
- struct expr e = expr_init();
- e.type = OP_STRING;
- e.param.str.s = str;
- vec_push(&es, e);
- paren_next = EXPR_PAREN_FORBIDDEN;
- } else if (expr_op(tok, n, -1) != OP_UNKNOWN) {
- enum expr_type op = expr_op(tok, n, -1);
- struct expr_string o2 = {NULL, 0};
- if (vec_len(&os) > 0) {
- o2 = vec_peek(&os);
- }
- for (;;) {
- if (n == 1 && *tok == ',' && vec_len(&os) > 0) {
- struct expr_string str = vec_peek(&os);
- if (str.n == 1 && *str.s == '{') {
- struct expr e = vec_pop(&es);
- vec_push(&vec_peek(&as).args, e);
- break;
- }
- }
- enum expr_type type2 = expr_op(o2.s, o2.n, -1);
- if (!(type2 != OP_UNKNOWN && expr_prec(op, type2))) {
- struct expr_string str = {tok, n};
- vec_push(&os, str);
- break;
- }
- if (expr_bind(o2.s, o2.n, &es) == -1) {
- goto cleanup;
- }
- (void)vec_pop(&os);
- if (vec_len(&os) > 0) {
- o2 = vec_peek(&os);
- } else {
- o2.n = 0;
- }
- }
- } else {
- if (n > 0 && !isdigit(*tok)) {
- /* Valid identifier, a variable or a function */
- id = tok;
- idn = n;
- } else {
- goto cleanup; // Bad variable name, e.g. '2.3.4' or '4ever'
- }
- }
- paren = paren_next;
- }
- if (idn > 0) {
- vec_push(&es, expr_varref(expr_get_var(vars, id, idn)));
- }
- while (vec_len(&os) > 0) {
- struct expr_string rest = vec_pop(&os);
- if (rest.n == 1 && (*rest.s == '(' || *rest.s == ')')) {
- goto cleanup; // Bad paren
- }
- if (expr_bind(rest.s, rest.n, &es) == -1) {
- goto cleanup;
- }
- }
- result = (struct expr *)calloc(1, sizeof(struct expr));
- if (result != NULL) {
- if (vec_len(&es) == 0) {
- result->type = OP_CONST;
- } else {
- *result = vec_pop(&es);
- }
- }
- int i, j;
- struct macro m;
- struct expr e;
- struct expr_arg a;
- cleanup:
- vec_foreach(¯os, m, i) {
- struct expr e2;
- vec_foreach(&m.body, e2, j) { expr_destroy_args(&e2); }
- vec_free(&m.body);
- }
- vec_free(¯os);
- vec_foreach(&es, e, i) { expr_destroy_args(&e); }
- vec_free(&es);
- vec_foreach(&as, a, i) {
- vec_foreach(&a.args, e, j) { expr_destroy_args(&e); }
- vec_free(&a.args);
- }
- vec_free(&as);
- /*vec_foreach(&os, o, i) {vec_free(&m.body);}*/
- vec_free(&os);
- return result;
- }
- static void expr_destroy_args(struct expr *e) {
- int i;
- struct expr arg;
- if (e->type == OP_FUNC) {
- vec_foreach(&e->param.func.args, arg, i) { expr_destroy_args(&arg); }
- vec_free(&e->param.func.args);
- if (e->param.func.context != NULL) {
- if (e->param.func.f->cleanup != NULL) {
- e->param.func.f->cleanup(e->param.func.f, e->param.func.context);
- }
- free(e->param.func.context);
- }
- } else if (e->type == OP_STRING) {
- free(e->param.str.s);
- } else if (e->type != OP_CONST && e->type != OP_VAR) {
- vec_foreach(&e->param.op.args, arg, i) { expr_destroy_args(&arg); }
- vec_free(&e->param.op.args);
- }
- }
- static void expr_destroy(struct expr *e, struct expr_var_list *vars) {
- if (e != NULL) {
- expr_destroy_args(e);
- free(e);
- }
- if (vars != NULL) {
- for (struct expr_var *v = vars->head; v;) {
- struct expr_var *next = v->next;
- free(v);
- v = next;
- }
- }
- }
- #ifdef __cplusplus
- } /* extern "C" */
- #endif
- #ifdef _MSC_VER
- #pragma warning(pop)
- #endif
- #endif /* EXPR_H */
|