annotate toys/pending/expr.c @ 1736:5892daac85ab draft

Switch nsenter to default y.
author Rob Landley <rob@landley.net>
date Thu, 12 Mar 2015 15:34:03 -0500
parents e064dd8ff138
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
1 /* expr.c - evaluate expression
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
2 *
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
3 * Copyright 2013 Daniel Verkamp <daniel@drv.nu>
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
4 *
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
5 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/expr.html
1595
9db327a6920d Note posix mailing list posting correcting a bug in the web version of the standard.
Rob Landley <rob@landley.net>
parents: 1590
diff changeset
6 *
9db327a6920d Note posix mailing list posting correcting a bug in the web version of the standard.
Rob Landley <rob@landley.net>
parents: 1590
diff changeset
7 * The web standard is incomplete (precedence grouping missing), see:
9db327a6920d Note posix mailing list posting correcting a bug in the web version of the standard.
Rob Landley <rob@landley.net>
parents: 1590
diff changeset
8 * http://permalink.gmane.org/gmane.comp.standards.posix.austin.general/10141
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
9
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
10 USE_EXPR(NEWTOY(expr, NULL, TOYFLAG_USR|TOYFLAG_BIN))
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
11
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
12 config EXPR
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
13 bool "expr"
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
14 default n
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
15 help
1629
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
16 usage: expr ARG1 OPERATOR ARG2...
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
17
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
18 Evaluate expression and print result. For example, "expr 1 + 2".
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
19
1629
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
20 The supported operators are (grouped from highest to lowest priority):
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
21
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
22 ( ) : * / % + - != <= < >= > = & |
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
23
1636
e064dd8ff138 typo fixes
Elliott Hughes <enh@google.com>
parents: 1629
diff changeset
24 Each constant and operator must be a separate command line argument.
1629
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
25 All operators are infix, meaning they expect a constant (or expression
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
26 that resolves to a constant) on each side of the operator. Operators of
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
27 the same priority (within each group above) are evaluated left to right.
1636
e064dd8ff138 typo fixes
Elliott Hughes <enh@google.com>
parents: 1629
diff changeset
28 Parentheses may be used (as separate arguments) to elevate the priority
1629
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
29 of expressions.
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
30
1629
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
31 Calling expr from a command shell requires a lot of \( or '*' escaping
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
32 to avoid interpreting shell control characters.
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
33
1636
e064dd8ff138 typo fixes
Elliott Hughes <enh@google.com>
parents: 1629
diff changeset
34 The & and | operators are logical (not bitwise) and may operate on
1629
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
35 strings (a blank string is "false"). Comparison operators may also
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
36 operate on strings (alphabetical sort).
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
37
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
38 Constants may be strings or integers. Comparison, logical, and regex
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
39 operators may operate on strings (a blank string is "false"), other
0459ee56c9d6 Fluff out help text.
Rob Landley <rob@landley.net>
parents: 1595
diff changeset
40 operators require integers.
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
41 */
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
42
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
43 // TODO: int overflow checking
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
44
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
45 #define FOR_expr
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
46 #include "toys.h"
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
47
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
48
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
49 GLOBALS(
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
50 int argidx;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
51 )
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
52
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
53 // Scalar value.
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
54 // If s is NULL, the value is an integer (i).
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
55 // If s is not NULL, the value is a string (s).
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
56 struct value {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
57 char *s;
922
32eec4a8f363 Force 64 bit math in expr, from Daniel Verkamp
Rob Landley <rob@landley.net>
parents: 920
diff changeset
58 long long i;
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
59 };
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
60
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
61 // check if v is the integer 0 or the empty string
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
62 static int is_zero(struct value *v)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
63 {
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
64 return v->s ? !*v->s : !v->i;
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
65 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
66
922
32eec4a8f363 Force 64 bit math in expr, from Daniel Verkamp
Rob Landley <rob@landley.net>
parents: 920
diff changeset
67 static char *num_to_str(long long num)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
68 {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
69 static char num_buf[21];
922
32eec4a8f363 Force 64 bit math in expr, from Daniel Verkamp
Rob Landley <rob@landley.net>
parents: 920
diff changeset
70 snprintf(num_buf, sizeof(num_buf), "%lld", num);
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
71 return num_buf;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
72 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
73
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
74 static int cmp(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
75 {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
76 if (lhs->s || rhs->s) {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
77 // at least one operand is a string
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
78 char *ls = lhs->s ? lhs->s : num_to_str(lhs->i);
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
79 char *rs = rhs->s ? rhs->s : num_to_str(rhs->i);
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
80 return strcmp(ls, rs);
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
81 } else return lhs->i - rhs->i;
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
82 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
83
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
84 static void re(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
85 {
1585
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
86 regex_t rp;
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
87 regmatch_t rm[2];
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
88
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
89 xregcomp(&rp, rhs->s, 0);
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
90 if (!regexec(&rp, lhs->s, 2, rm, 0) && rm[0].rm_so == 0) {
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
91 if (rp.re_nsub > 0 && rm[1].rm_so >= 0)
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
92 lhs->s = xmprintf("%.*s", rm[1].rm_eo - rm[1].rm_so, lhs->s+rm[1].rm_so);
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
93 else {
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
94 lhs->i = rm[0].rm_eo;
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
95 lhs->s = 0;
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
96 }
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
97 } else {
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
98 if (!rp.re_nsub) {
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
99 lhs->i = 0;
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
100 lhs->s = 0;
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
101 } else lhs->s = "";
cff20c82a797 expr.c: Added '==' sign into list of operations. Also added support for regex pattern match.
Ashwini Sharma <ak.ashwini1981@gmail.com>
parents: 922
diff changeset
102 }
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
103 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
104
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
105 static void mod(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
106 {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
107 if (lhs->s || rhs->s) error_exit("non-integer argument");
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
108 if (is_zero(rhs)) error_exit("division by zero");
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
109 lhs->i %= rhs->i;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
110 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
111
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
112 static void divi(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
113 {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
114 if (lhs->s || rhs->s) error_exit("non-integer argument");
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
115 if (is_zero(rhs)) error_exit("division by zero");
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
116 lhs->i /= rhs->i;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
117 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
118
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
119 static void mul(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
120 {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
121 if (lhs->s || rhs->s) error_exit("non-integer argument");
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
122 lhs->i *= rhs->i;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
123 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
124
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
125 static void sub(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
126 {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
127 if (lhs->s || rhs->s) error_exit("non-integer argument");
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
128 lhs->i -= rhs->i;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
129 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
130
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
131 static void add(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
132 {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
133 if (lhs->s || rhs->s) error_exit("non-integer argument");
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
134 lhs->i += rhs->i;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
135 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
136
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
137 static void ne(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
138 {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
139 lhs->i = cmp(lhs, rhs) != 0;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
140 lhs->s = NULL;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
141 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
142
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
143 static void lte(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
144 {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
145 lhs->i = cmp(lhs, rhs) <= 0;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
146 lhs->s = NULL;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
147 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
148
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
149 static void lt(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
150 {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
151 lhs->i = cmp(lhs, rhs) < 0;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
152 lhs->s = NULL;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
153 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
154
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
155 static void gte(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
156 {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
157 lhs->i = cmp(lhs, rhs) >= 0;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
158 lhs->s = NULL;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
159 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
160
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
161 static void gt(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
162 {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
163 lhs->i = cmp(lhs, rhs) > 0;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
164 lhs->s = NULL;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
165 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
166
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
167 static void eq(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
168 {
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
169 lhs->i = !cmp(lhs, rhs);
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
170 lhs->s = NULL;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
171 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
172
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
173 static void and(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
174 {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
175 if (is_zero(lhs) || is_zero(rhs)) {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
176 lhs->i = 0;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
177 lhs->s = NULL;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
178 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
179 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
180
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
181 static void or(struct value *lhs, struct value *rhs)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
182 {
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
183 if (is_zero(lhs)) *lhs = *rhs;
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
184 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
185
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
186 static void get_value(struct value *v)
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
187 {
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
188 char *endp, *arg;
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
189
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
190 if (TT.argidx == toys.optc) {
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
191 v->i = 0;
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
192 v->s = ""; // signal end of expression
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
193 return;
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
194 }
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
195
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
196 // can't happen, the increment is after the == test
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
197 // if (TT.argidx >= toys.optc) error_exit("syntax error");
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
198
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
199 arg = toys.optargs[TT.argidx++];
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
200
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
201 v->i = strtoll(arg, &endp, 10);
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
202 v->s = *endp ? arg : NULL;
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
203 }
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
204
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
205 // check if v matches a token, and consume it if so
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
206 static int match(struct value *v, char *tok)
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
207 {
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
208 if (v->s && !strcmp(v->s, tok)) {
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
209 get_value(v);
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
210 return 1;
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
211 }
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
212
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
213 return 0;
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
214 }
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
215
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
216 // operators in order of increasing precedence
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
217 static struct op {
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
218 char *tok;
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
219
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
220 // calculate "lhs op rhs" (e.g. lhs + rhs) and store result in lhs
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
221 void (*calc)(struct value *lhs, struct value *rhs);
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
222 } ops[] = {
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
223 {"|", or }, {"&", and }, {"=", eq }, {"==", eq }, {">", gt },
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
224 {">=", gte }, {"<", lt }, {"<=", lte }, {"!=", ne }, {"+", add },
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
225 {"-", sub }, {"*", mul }, {"/", divi}, {"%", mod }, {":", re },
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
226 {"(", NULL}, // special case - must be last
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
227 };
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
228
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
229 // "|,&,= ==> >=< <= !=,+-,*/%,:"
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
230
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
231 static void parse_op(struct value *lhs, struct value *tok, struct op *op)
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
232 {
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
233 if (!op) op = ops;
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
234
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
235 // special case parsing for parentheses
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
236 if (*op->tok == '(') {
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
237 if (match(tok, "(")) {
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
238 parse_op(lhs, tok, 0);
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
239 if (!match(tok, ")")) error_exit("syntax error"); // missing closing paren
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
240 } else {
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
241 // tok is a string or integer - return it and get the next token
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
242 *lhs = *tok;
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
243 get_value(tok);
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
244 }
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
245
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
246 return;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
247 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
248
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
249 parse_op(lhs, tok, op + 1);
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
250 while (match(tok, op->tok)) {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
251 struct value rhs;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
252 parse_op(&rhs, tok, op + 1);
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
253 if (rhs.s && !*rhs.s) error_exit("syntax error"); // premature end of expression
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
254 op->calc(lhs, &rhs);
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
255 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
256 }
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
257
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
258 void expr_main(void)
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
259 {
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
260 struct value tok, ret = {0};
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
261
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
262 toys.exitval = 2; // if exiting early, indicate invalid expression
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
263
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
264 TT.argidx = 0;
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
265
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
266 get_value(&tok); // warm up the parser with the initial value
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
267 parse_op(&ret, &tok, 0);
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
268
1590
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
269 // final token should be end of expression
d5931155cafe Refactor expr and add another test entry that works with TEST_HOST=1 but not with the one in pending.
Rob Landley <rob@landley.net>
parents: 1585
diff changeset
270 if (!tok.s || *tok.s) error_exit("syntax error");
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
271
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
272 if (ret.s) printf("%s\n", ret.s);
922
32eec4a8f363 Force 64 bit math in expr, from Daniel Verkamp
Rob Landley <rob@landley.net>
parents: 920
diff changeset
273 else printf("%lld\n", ret.i);
920
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
274
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
275 exit(is_zero(&ret));
74b5cf0309fc Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff changeset
276 }