aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Landley <rob@landley.net>2014-12-01 03:15:25 -0600
committerRob Landley <rob@landley.net>2014-12-01 03:15:25 -0600
commitef6a773198040a05a56dec2261516fb149823cf6 (patch)
tree710afa654265f59b4adfe2da795fe2b747c462b0
parentde211e0288bd2cd8e27ab23252ec2e4077b3d589 (diff)
downloadtoybox-ef6a773198040a05a56dec2261516fb149823cf6.tar.gz
Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
-rw-r--r--tests/expr.test2
-rw-r--r--toys/pending/expr.c178
2 files changed, 75 insertions, 105 deletions
diff --git a/tests/expr.test b/tests/expr.test
index 1c038a5c..33900d7a 100644
--- a/tests/expr.test
+++ b/tests/expr.test
@@ -17,3 +17,5 @@ testing "expr % * same priority" "expr 3 % 2 \* 4" "4\n" "" ""
testing "expr * % same priority" "expr 3 \* 2 % 4" "2\n" "" ""
testing "expr = > same priority" "expr 0 = 2 \> 3" "0\n" "" ""
testing "expr > = same priority" "expr 3 \> 2 = 1" "1\n" "" ""
+testing "expr string becomes integer" "expr ab21xx : '[^0-9]*\([0-9]*\)' + 3" \
+ "24\n" "" ""
diff --git a/toys/pending/expr.c b/toys/pending/expr.c
index 6742ff68..c7da4d1c 100644
--- a/toys/pending/expr.c
+++ b/toys/pending/expr.c
@@ -16,7 +16,7 @@ config EXPR
The supported operators, in order of increasing precedence, are:
- | & = > >= < <= != + - * / %
+ | & = > >= < <= != + - * / % :
In addition, parentheses () are supported for grouping.
*/
@@ -39,44 +39,10 @@ struct value {
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)
+static int is_zero(struct value *v)
{
- return ((v->s && *v->s == '\0') || v->i == 0);
+ return v->s ? !*v->s : !v->i;
}
static char *num_to_str(long long num)
@@ -86,30 +52,17 @@ static char *num_to_str(long long num)
return num_buf;
}
-static int cmp(const struct value *lhs, const struct value *rhs)
+static int cmp(struct value *lhs, 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;
- }
+ } 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)
+static void re(struct value *lhs, struct value *rhs)
{
regex_t rp;
regmatch_t rm[2];
@@ -130,75 +83,75 @@ static void re(struct value *lhs, const struct value *rhs)
}
}
-static void mod(struct value *lhs, const struct value *rhs)
+static void mod(struct value *lhs, 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)
+static void divi(struct value *lhs, 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)
+static void mul(struct value *lhs, 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)
+static void sub(struct value *lhs, 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)
+static void add(struct value *lhs, 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)
+static void ne(struct value *lhs, struct value *rhs)
{
lhs->i = cmp(lhs, rhs) != 0;
lhs->s = NULL;
}
-static void lte(struct value *lhs, const struct value *rhs)
+static void lte(struct value *lhs, struct value *rhs)
{
lhs->i = cmp(lhs, rhs) <= 0;
lhs->s = NULL;
}
-static void lt(struct value *lhs, const struct value *rhs)
+static void lt(struct value *lhs, struct value *rhs)
{
lhs->i = cmp(lhs, rhs) < 0;
lhs->s = NULL;
}
-static void gte(struct value *lhs, const struct value *rhs)
+static void gte(struct value *lhs, struct value *rhs)
{
lhs->i = cmp(lhs, rhs) >= 0;
lhs->s = NULL;
}
-static void gt(struct value *lhs, const struct value *rhs)
+static void gt(struct value *lhs, struct value *rhs)
{
lhs->i = cmp(lhs, rhs) > 0;
lhs->s = NULL;
}
-static void eq(struct value *lhs, const struct value *rhs)
+static void eq(struct value *lhs, struct value *rhs)
{
- lhs->i = cmp(lhs, rhs) == 0;
+ lhs->i = !cmp(lhs, rhs);
lhs->s = NULL;
}
-static void and(struct value *lhs, const struct value *rhs)
+static void and(struct value *lhs, struct value *rhs)
{
if (is_zero(lhs) || is_zero(rhs)) {
lhs->i = 0;
@@ -206,52 +159,71 @@ static void and(struct value *lhs, const struct value *rhs)
}
}
-static void or(struct value *lhs, const struct value *rhs)
+static void or(struct value *lhs, struct value *rhs)
{
- if (is_zero(lhs)) {
- *lhs = *rhs;
- }
+ if (is_zero(lhs)) *lhs = *rhs;
}
+static void get_value(struct value *v)
+{
+ char *endp, *arg;
-// operators in order of increasing precedence
-static const struct op ops[] = {
- {"|", or },
- {"&", and },
- {"=", eq },
- {"==", eq },
- {">", gt },
- {">=", gte },
- {"<", lt },
- {"<=", lte },
- {"!=", ne },
- {"+", add },
- {"-", sub },
- {"*", mul },
- {"/", divi},
- {"%", mod },
- {":", re },
- {"(", NULL}, // special case - must be last
-};
+ if (TT.argidx == toys.optc) {
+ v->i = 0;
+ v->s = ""; // signal end of expression
+ return;
+ }
+// can't happen, the increment is after the == test
+// 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;
+}
-static void parse_parens(struct value *ret, struct value *v)
+// check if v matches a token, and consume it if so
+static int match(struct value *v, char *tok)
{
- 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;
+ if (v->s && !strcmp(v->s, tok)) {
get_value(v);
+ return 1;
}
+
+ return 0;
}
-static void parse_op(struct value *lhs, struct value *tok, const struct op *op)
+// operators in order of increasing precedence
+static struct op {
+ char *tok;
+
+ // calculate "lhs op rhs" (e.g. lhs + rhs) and store result in lhs
+ void (*calc)(struct value *lhs, struct value *rhs);
+} ops[] = {
+ {"|", or }, {"&", and }, {"=", eq }, {"==", eq }, {">", gt },
+ {">=", gte }, {"<", lt }, {"<=", lte }, {"!=", ne }, {"+", add },
+ {"-", sub }, {"*", mul }, {"/", divi}, {"%", mod }, {":", re },
+ {"(", NULL}, // special case - must be last
+};
+
+// "|,&,= ==> >=< <= !=,+-,*/%,:"
+
+static void parse_op(struct value *lhs, struct value *tok, struct op *op)
{
+ if (!op) op = ops;
+
// special case parsing for parentheses
if (*op->tok == '(') {
- parse_parens(lhs, tok);
+ if (match(tok, "(")) {
+ parse_op(lhs, tok, 0);
+ if (!match(tok, ")")) error_exit("syntax error"); // missing closing paren
+ } else {
+ // tok is a string or integer - return it and get the next token
+ *lhs = *tok;
+ get_value(tok);
+ }
+
return;
}
@@ -264,11 +236,6 @@ static void parse_op(struct value *lhs, struct value *tok, const struct op *op)
}
}
-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};
@@ -278,9 +245,10 @@ void expr_main(void)
TT.argidx = 0;
get_value(&tok); // warm up the parser with the initial value
- parse_expr(&ret, &tok);
+ parse_op(&ret, &tok, 0);
- if (!tok.s || *tok.s) error_exit("syntax error"); // final token should be end of expression
+ // final token should be end of expression
+ if (!tok.s || *tok.s) error_exit("syntax error");
if (ret.s) printf("%s\n", ret.s);
else printf("%lld\n", ret.i);