Mercurial > hg > toybox
view toys/pending/expr.c @ 953:13916d161ec0
xzcat: remove XZ_(PREALLOC|SINGLE), inline xz_dec_bcj_create
Because we only use XZ_DYNALLOC, there's a bunch of dead code.
This patch removes the #ifdef's and if()s associated with support for
multiple modes.
single_call was only used to store the mode; it is no longer needed.
A little bit of reorganization was needed to reduce the number of prototypes.
Documentation associated with dead code was dropped.
There are still some relics of multiple modes in the continued presence
of "XZ_DYNALLOC" and xz_mode.
Additionally, I inlined xz_dec_bcj_create; it was called once.
This loses about 125 lines, mostly comments.
author | Isaac Dunham <idunham@lavabit.com> |
---|---|
date | Wed, 17 Jul 2013 17:25:07 -0500 |
parents | 32eec4a8f363 |
children | cff20c82a797 |
line wrap: on
line source
/* expr.c - evaluate expression * * Copyright 2013 Daniel Verkamp <daniel@drv.nu> * * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/expr.html USE_EXPR(NEWTOY(expr, NULL, TOYFLAG_USR|TOYFLAG_BIN)) config EXPR bool "expr" default n help usage: expr args Evaluate expression and print result. The supported operators, in order of increasing precedence, are: | & = > >= < <= != + - * / % In addition, parentheses () are supported for grouping. */ // TODO: int overflow checking #define FOR_expr #include "toys.h" GLOBALS( int argidx; ) // Scalar value. // If s is NULL, the value is an integer (i). // If s is not NULL, the value is a string (s). struct value { char *s; long long i; }; static void parse_expr(struct value *ret, struct value *v); static void get_value(struct value *v) { char *endp, *arg; if (TT.argidx == toys.optc) { v->i = 0; v->s = ""; // signal end of expression return; } if (TT.argidx >= toys.optc) { error_exit("syntax error"); } arg = toys.optargs[TT.argidx++]; v->i = strtoll(arg, &endp, 10); v->s = *endp ? arg : NULL; } // check if v matches a token, and consume it if so static int match(struct value *v, const char *tok) { if (v->s && !strcmp(v->s, tok)) { get_value(v); return 1; } return 0; } // check if v is the integer 0 or the empty string static int is_zero(const struct value *v) { return ((v->s && *v->s == '\0') || v->i == 0); } static char *num_to_str(long long num) { static char num_buf[21]; snprintf(num_buf, sizeof(num_buf), "%lld", num); return num_buf; } static int cmp(const struct value *lhs, const struct value *rhs) { if (lhs->s || rhs->s) { // at least one operand is a string char *ls = lhs->s ? lhs->s : num_to_str(lhs->i); char *rs = rhs->s ? rhs->s : num_to_str(rhs->i); return strcmp(ls, rs); } else { return lhs->i - rhs->i; } } // operators struct op { const char *tok; // calculate "lhs op rhs" (e.g. lhs + rhs) and store result in lhs void (*calc)(struct value *lhs, const struct value *rhs); }; static void re(struct value *lhs, const struct value *rhs) { error_exit("regular expression match not implemented"); } static void mod(struct value *lhs, const struct value *rhs) { if (lhs->s || rhs->s) error_exit("non-integer argument"); if (is_zero(rhs)) error_exit("division by zero"); lhs->i %= rhs->i; } static void divi(struct value *lhs, const struct value *rhs) { if (lhs->s || rhs->s) error_exit("non-integer argument"); if (is_zero(rhs)) error_exit("division by zero"); lhs->i /= rhs->i; } static void mul(struct value *lhs, const struct value *rhs) { if (lhs->s || rhs->s) error_exit("non-integer argument"); lhs->i *= rhs->i; } static void sub(struct value *lhs, const struct value *rhs) { if (lhs->s || rhs->s) error_exit("non-integer argument"); lhs->i -= rhs->i; } static void add(struct value *lhs, const struct value *rhs) { if (lhs->s || rhs->s) error_exit("non-integer argument"); lhs->i += rhs->i; } static void ne(struct value *lhs, const struct value *rhs) { lhs->i = cmp(lhs, rhs) != 0; lhs->s = NULL; } static void lte(struct value *lhs, const struct value *rhs) { lhs->i = cmp(lhs, rhs) <= 0; lhs->s = NULL; } static void lt(struct value *lhs, const struct value *rhs) { lhs->i = cmp(lhs, rhs) < 0; lhs->s = NULL; } static void gte(struct value *lhs, const struct value *rhs) { lhs->i = cmp(lhs, rhs) >= 0; lhs->s = NULL; } static void gt(struct value *lhs, const struct value *rhs) { lhs->i = cmp(lhs, rhs) > 0; lhs->s = NULL; } static void eq(struct value *lhs, const struct value *rhs) { lhs->i = cmp(lhs, rhs) == 0; lhs->s = NULL; } static void and(struct value *lhs, const struct value *rhs) { if (is_zero(lhs) || is_zero(rhs)) { lhs->i = 0; lhs->s = NULL; } } static void or(struct value *lhs, const struct value *rhs) { if (is_zero(lhs)) { *lhs = *rhs; } } // operators in order of increasing precedence static const struct op ops[] = { {"|", or }, {"&", and }, {"=", eq }, {">", gt }, {">=", gte }, {"<", lt }, {"<=", lte }, {"!=", ne }, {"+", add }, {"-", sub }, {"*", mul }, {"/", divi}, {"%", mod }, {":", re }, {"(", NULL}, // special case - must be last }; static void parse_parens(struct value *ret, struct value *v) { if (match(v, "(")) { parse_expr(ret, v); if (!match(v, ")")) error_exit("syntax error"); // missing closing paren } else { // v is a string or integer - return it and get the next token *ret = *v; get_value(v); } } static void parse_op(struct value *lhs, struct value *tok, const struct op *op) { // special case parsing for parentheses if (*op->tok == '(') { parse_parens(lhs, tok); return; } parse_op(lhs, tok, op + 1); while (match(tok, op->tok)) { struct value rhs; parse_op(&rhs, tok, op + 1); if (rhs.s && !*rhs.s) error_exit("syntax error"); // premature end of expression op->calc(lhs, &rhs); } } static void parse_expr(struct value *ret, struct value *v) { parse_op(ret, v, ops); // start at the top of the ops table } void expr_main(void) { struct value tok, ret = {0}; toys.exitval = 2; // if exiting early, indicate invalid expression TT.argidx = 0; get_value(&tok); // warm up the parser with the initial value parse_expr(&ret, &tok); if (!tok.s || *tok.s) error_exit("syntax error"); // final token should be end of expression if (ret.s) printf("%s\n", ret.s); else printf("%lld\n", ret.i); exit(is_zero(&ret)); }