Mercurial > hg > toybox
annotate toys/pending/expr.c @ 922:32eec4a8f363
Force 64 bit math in expr, from Daniel Verkamp
author | Rob Landley <rob@landley.net> |
---|---|
date | Sat, 15 Jun 2013 00:49:06 -0500 |
parents | 74b5cf0309fc |
children | cff20c82a797 |
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 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
6 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
7 USE_EXPR(NEWTOY(expr, NULL, TOYFLAG_USR|TOYFLAG_BIN)) |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
8 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
9 config EXPR |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
10 bool "expr" |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
11 default n |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
12 help |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
13 usage: expr args |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
14 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
15 Evaluate expression and print result. |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
16 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
17 The supported operators, in order of increasing precedence, are: |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
18 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
19 | & = > >= < <= != + - * / % |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
20 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
21 In addition, parentheses () are supported for grouping. |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
22 */ |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
23 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
24 // TODO: int overflow checking |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
25 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
26 #define FOR_expr |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
27 #include "toys.h" |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
28 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
29 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
30 GLOBALS( |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
31 int argidx; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
32 ) |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
33 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
34 // Scalar value. |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
35 // 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
|
36 // 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
|
37 struct value { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
38 char *s; |
922
32eec4a8f363
Force 64 bit math in expr, from Daniel Verkamp
Rob Landley <rob@landley.net>
parents:
920
diff
changeset
|
39 long long i; |
920
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
40 }; |
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 static void parse_expr(struct value *ret, struct value *v); |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
43 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
44 static void get_value(struct value *v) |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
45 { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
46 char *endp, *arg; |
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 if (TT.argidx == toys.optc) { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
49 v->i = 0; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
50 v->s = ""; // signal end of expression |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
51 return; |
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 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
54 if (TT.argidx >= toys.optc) { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
55 error_exit("syntax error"); |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
56 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
57 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
58 arg = toys.optargs[TT.argidx++]; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
59 |
922
32eec4a8f363
Force 64 bit math in expr, from Daniel Verkamp
Rob Landley <rob@landley.net>
parents:
920
diff
changeset
|
60 v->i = strtoll(arg, &endp, 10); |
920
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
61 v->s = *endp ? arg : NULL; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
62 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
63 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
64 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
65 // check if v matches a token, and consume it if so |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
66 static int match(struct value *v, const char *tok) |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
67 { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
68 if (v->s && !strcmp(v->s, tok)) { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
69 get_value(v); |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
70 return 1; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
71 } |
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 return 0; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
74 } |
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 // check if v is the integer 0 or the empty string |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
77 static int is_zero(const struct value *v) |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
78 { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
79 return ((v->s && *v->s == '\0') || v->i == 0); |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
80 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
81 |
922
32eec4a8f363
Force 64 bit math in expr, from Daniel Verkamp
Rob Landley <rob@landley.net>
parents:
920
diff
changeset
|
82 static char *num_to_str(long long num) |
920
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
83 { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
84 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
|
85 snprintf(num_buf, sizeof(num_buf), "%lld", num); |
920
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
86 return num_buf; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
87 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
88 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
89 static int cmp(const struct value *lhs, const struct value *rhs) |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
90 { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
91 if (lhs->s || rhs->s) { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
92 // at least one operand is a string |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
93 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
|
94 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
|
95 return strcmp(ls, rs); |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
96 } else { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
97 return lhs->i - rhs->i; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
98 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
99 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
100 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
101 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
102 // operators |
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 struct op { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
105 const char *tok; |
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 // calculate "lhs op rhs" (e.g. lhs + rhs) and store result in lhs |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
108 void (*calc)(struct value *lhs, const struct value *rhs); |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
109 }; |
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 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
112 static void re(struct value *lhs, const struct value *rhs) |
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 error_exit("regular expression match not implemented"); |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
115 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
116 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
117 static void mod(struct value *lhs, const struct value *rhs) |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
118 { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
119 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
|
120 if (is_zero(rhs)) error_exit("division by zero"); |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
121 lhs->i %= rhs->i; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
122 } |
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 static void divi(struct value *lhs, const struct value *rhs) |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
125 { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
126 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
|
127 if (is_zero(rhs)) error_exit("division by zero"); |
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 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
131 static void mul(struct value *lhs, const struct value *rhs) |
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 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
137 static void sub(struct value *lhs, const struct value *rhs) |
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 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
|
140 lhs->i -= rhs->i; |
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 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
143 static void add(struct value *lhs, const struct value *rhs) |
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 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
|
146 lhs->i += rhs->i; |
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 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
149 static void ne(struct value *lhs, const struct value *rhs) |
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 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
155 static void lte(struct value *lhs, const struct value *rhs) |
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 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
161 static void lt(struct value *lhs, const struct value *rhs) |
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 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
167 static void gte(struct value *lhs, const struct value *rhs) |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
168 { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
169 lhs->i = cmp(lhs, rhs) >= 0; |
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 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
173 static void gt(struct value *lhs, const struct value *rhs) |
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 lhs->i = cmp(lhs, rhs) > 0; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
176 lhs->s = NULL; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
177 } |
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 static void eq(struct value *lhs, const struct value *rhs) |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
180 { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
181 lhs->i = cmp(lhs, rhs) == 0; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
182 lhs->s = NULL; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
183 } |
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 static void and(struct value *lhs, const struct value *rhs) |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
186 { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
187 if (is_zero(lhs) || is_zero(rhs)) { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
188 lhs->i = 0; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
189 lhs->s = NULL; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
190 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
191 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
192 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
193 static void or(struct value *lhs, const struct value *rhs) |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
194 { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
195 if (is_zero(lhs)) { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
196 *lhs = *rhs; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
197 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
198 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
199 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
200 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
201 // operators in order of increasing precedence |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
202 static const struct op ops[] = { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
203 {"|", or }, |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
204 {"&", and }, |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
205 {"=", eq }, |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
206 {">", gt }, |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
207 {">=", gte }, |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
208 {"<", lt }, |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
209 {"<=", lte }, |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
210 {"!=", ne }, |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
211 {"+", add }, |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
212 {"-", sub }, |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
213 {"*", mul }, |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
214 {"/", divi}, |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
215 {"%", mod }, |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
216 {":", re }, |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
217 {"(", NULL}, // special case - must be last |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
218 }; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
219 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
220 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
221 static void parse_parens(struct value *ret, struct value *v) |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
222 { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
223 if (match(v, "(")) { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
224 parse_expr(ret, v); |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
225 if (!match(v, ")")) error_exit("syntax error"); // missing closing paren |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
226 } else { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
227 // v is a string or integer - return it and get the next token |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
228 *ret = *v; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
229 get_value(v); |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
230 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
231 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
232 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
233 static void parse_op(struct value *lhs, struct value *tok, const struct op *op) |
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 == '(') { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
237 parse_parens(lhs, tok); |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
238 return; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
239 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
240 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
241 parse_op(lhs, tok, op + 1); |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
242 while (match(tok, op->tok)) { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
243 struct value rhs; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
244 parse_op(&rhs, tok, op + 1); |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
245 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
|
246 op->calc(lhs, &rhs); |
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 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
250 static void parse_expr(struct value *ret, struct value *v) |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
251 { |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
252 parse_op(ret, v, ops); // start at the top of the ops table |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
253 } |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
254 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
255 void expr_main(void) |
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 struct value tok, ret = {0}; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
258 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
259 toys.exitval = 2; // if exiting early, indicate invalid expression |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
260 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
261 TT.argidx = 0; |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
262 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
263 get_value(&tok); // warm up the parser with the initial value |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
264 parse_expr(&ret, &tok); |
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 if (!tok.s || *tok.s) error_exit("syntax error"); // final token should be end of expression |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
267 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
268 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
|
269 else printf("%lld\n", ret.i); |
920
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
270 |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
271 exit(is_zero(&ret)); |
74b5cf0309fc
Start of expr, by Daniel Verkamp.
Rob Landley <rob@landley.net>
parents:
diff
changeset
|
272 } |