arithmetic.c revision 1.1.4.2 1 /* $NetBSD: arithmetic.c,v 1.1.4.2 2017/04/26 02:52:13 pgoyette Exp $ */
2
3 /*-
4 * Copyright (c) 1993
5 * The Regents of the University of California. All rights reserved.
6 * Copyright (c) 2007
7 * Herbert Xu <herbert (at) gondor.apana.org.au>. All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Kenneth Almquist.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * From FreeBSD, who obtained it from dash, modified both times...
37 */
38
39 #include <sys/cdefs.h>
40
41 #ifndef lint
42 __RCSID("$NetBSD: arithmetic.c,v 1.1.4.2 2017/04/26 02:52:13 pgoyette Exp $");
43 #endif /* not lint */
44
45 #include <limits.h>
46 #include <errno.h>
47 #include <inttypes.h>
48 #include <stdlib.h>
49 #include <stdio.h>
50
51 #include "shell.h"
52 #include "arithmetic.h"
53 #include "arith_tokens.h"
54 #include "expand.h"
55 #include "error.h"
56 #include "memalloc.h"
57 #include "output.h"
58 #include "options.h"
59 #include "var.h"
60
61 #if ARITH_BOR + ARITH_ASS_GAP != ARITH_BORASS || \
62 ARITH_ASS + ARITH_ASS_GAP != ARITH_EQ
63 #error Arithmetic tokens are out of order.
64 #endif
65
66 static const char *arith_startbuf;
67
68 const char *arith_buf;
69 union a_token_val a_t_val;
70
71 static int last_token;
72
73 #define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec
74
75 static const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = {
76 ARITH_PRECEDENCE(ARITH_MUL, 0),
77 ARITH_PRECEDENCE(ARITH_DIV, 0),
78 ARITH_PRECEDENCE(ARITH_REM, 0),
79 ARITH_PRECEDENCE(ARITH_ADD, 1),
80 ARITH_PRECEDENCE(ARITH_SUB, 1),
81 ARITH_PRECEDENCE(ARITH_LSHIFT, 2),
82 ARITH_PRECEDENCE(ARITH_RSHIFT, 2),
83 ARITH_PRECEDENCE(ARITH_LT, 3),
84 ARITH_PRECEDENCE(ARITH_LE, 3),
85 ARITH_PRECEDENCE(ARITH_GT, 3),
86 ARITH_PRECEDENCE(ARITH_GE, 3),
87 ARITH_PRECEDENCE(ARITH_EQ, 4),
88 ARITH_PRECEDENCE(ARITH_NE, 4),
89 ARITH_PRECEDENCE(ARITH_BAND, 5),
90 ARITH_PRECEDENCE(ARITH_BXOR, 6),
91 ARITH_PRECEDENCE(ARITH_BOR, 7),
92 };
93
94 #define ARITH_MAX_PREC 8
95
96 int expcmd(int, char **);
97
98 static void __dead
99 arith_err(const char *s)
100 {
101 error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
102 /* NOTREACHED */
103 }
104
105 static intmax_t
106 arith_lookupvarint(char *varname)
107 {
108 const char *str;
109 char *p;
110 intmax_t result;
111
112 str = lookupvar(varname);
113 if (uflag && str == NULL)
114 arith_err("variable not set");
115 if (str == NULL || *str == '\0')
116 str = "0";
117 errno = 0;
118 result = strtoimax(str, &p, 0);
119 if (errno != 0 || *p != '\0')
120 arith_err("variable contains non-numeric value");
121 return result;
122 }
123
124 static inline int
125 arith_prec(int op)
126 {
127
128 return prec[op - ARITH_BINOP_MIN];
129 }
130
131 static inline int
132 higher_prec(int op1, int op2)
133 {
134
135 return arith_prec(op1) < arith_prec(op2);
136 }
137
138 static intmax_t
139 do_binop(int op, intmax_t a, intmax_t b)
140 {
141
142 switch (op) {
143 default:
144 arith_err("token error");
145 case ARITH_REM:
146 case ARITH_DIV:
147 if (b == 0)
148 arith_err("division by zero");
149 if (a == INTMAX_MIN && b == -1)
150 arith_err("divide error");
151 return op == ARITH_REM ? a % b : a / b;
152 case ARITH_MUL:
153 return (uintmax_t)a * (uintmax_t)b;
154 case ARITH_ADD:
155 return (uintmax_t)a + (uintmax_t)b;
156 case ARITH_SUB:
157 return (uintmax_t)a - (uintmax_t)b;
158 case ARITH_LSHIFT:
159 return (uintmax_t)a << (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
160 case ARITH_RSHIFT:
161 return a >> (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
162 case ARITH_LT:
163 return a < b;
164 case ARITH_LE:
165 return a <= b;
166 case ARITH_GT:
167 return a > b;
168 case ARITH_GE:
169 return a >= b;
170 case ARITH_EQ:
171 return a == b;
172 case ARITH_NE:
173 return a != b;
174 case ARITH_BAND:
175 return a & b;
176 case ARITH_BXOR:
177 return a ^ b;
178 case ARITH_BOR:
179 return a | b;
180 }
181 }
182
183 static intmax_t assignment(int var, int noeval);
184
185 static intmax_t
186 primary(int token, union a_token_val *val, int op, int noeval)
187 {
188 intmax_t result;
189
190 switch (token) {
191 case ARITH_LPAREN:
192 result = assignment(op, noeval);
193 if (last_token != ARITH_RPAREN)
194 arith_err("expecting ')'");
195 last_token = arith_token();
196 return result;
197 case ARITH_NUM:
198 last_token = op;
199 return val->val;
200 case ARITH_VAR:
201 last_token = op;
202 return noeval ? val->val : arith_lookupvarint(val->name);
203 case ARITH_ADD:
204 *val = a_t_val;
205 return primary(op, val, arith_token(), noeval);
206 case ARITH_SUB:
207 *val = a_t_val;
208 return -primary(op, val, arith_token(), noeval);
209 case ARITH_NOT:
210 *val = a_t_val;
211 return !primary(op, val, arith_token(), noeval);
212 case ARITH_BNOT:
213 *val = a_t_val;
214 return ~primary(op, val, arith_token(), noeval);
215 default:
216 arith_err("expecting primary");
217 }
218 return 0; /* never reached */
219 }
220
221 static intmax_t
222 binop2(intmax_t a, int op, int precedence, int noeval)
223 {
224 union a_token_val val;
225 intmax_t b;
226 int op2;
227 int token;
228
229 for (;;) {
230 token = arith_token();
231 val = a_t_val;
232
233 b = primary(token, &val, arith_token(), noeval);
234
235 op2 = last_token;
236 if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX &&
237 higher_prec(op2, op)) {
238 b = binop2(b, op2, arith_prec(op), noeval);
239 op2 = last_token;
240 }
241
242 a = noeval ? b : do_binop(op, a, b);
243
244 if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX ||
245 arith_prec(op2) >= precedence)
246 return a;
247
248 op = op2;
249 }
250 }
251
252 static intmax_t
253 binop(int token, union a_token_val *val, int op, int noeval)
254 {
255 intmax_t a = primary(token, val, op, noeval);
256
257 op = last_token;
258 if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX)
259 return a;
260
261 return binop2(a, op, ARITH_MAX_PREC, noeval);
262 }
263
264 static intmax_t
265 and(int token, union a_token_val *val, int op, int noeval)
266 {
267 intmax_t a = binop(token, val, op, noeval);
268 intmax_t b;
269
270 op = last_token;
271 if (op != ARITH_AND)
272 return a;
273
274 token = arith_token();
275 *val = a_t_val;
276
277 b = and(token, val, arith_token(), noeval | !a);
278
279 return a && b;
280 }
281
282 static intmax_t
283 or(int token, union a_token_val *val, int op, int noeval)
284 {
285 intmax_t a = and(token, val, op, noeval);
286 intmax_t b;
287
288 op = last_token;
289 if (op != ARITH_OR)
290 return a;
291
292 token = arith_token();
293 *val = a_t_val;
294
295 b = or(token, val, arith_token(), noeval | !!a);
296
297 return a || b;
298 }
299
300 static intmax_t
301 cond(int token, union a_token_val *val, int op, int noeval)
302 {
303 intmax_t a = or(token, val, op, noeval);
304 intmax_t b;
305 intmax_t c;
306
307 if (last_token != ARITH_QMARK)
308 return a;
309
310 b = assignment(arith_token(), noeval | !a);
311
312 if (last_token != ARITH_COLON)
313 arith_err("expecting ':'");
314
315 token = arith_token();
316 *val = a_t_val;
317
318 c = cond(token, val, arith_token(), noeval | !!a);
319
320 return a ? b : c;
321 }
322
323 static intmax_t
324 assignment(int var, int noeval)
325 {
326 union a_token_val val = a_t_val;
327 int op = arith_token();
328 intmax_t result;
329 char sresult[DIGITS(result) + 1];
330
331
332 if (var != ARITH_VAR)
333 return cond(var, &val, op, noeval);
334
335 if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX))
336 return cond(var, &val, op, noeval);
337
338 result = assignment(arith_token(), noeval);
339 if (noeval)
340 return result;
341
342 if (op != ARITH_ASS)
343 result = do_binop(op - ARITH_ASS_GAP,
344 arith_lookupvarint(val.name), result);
345 snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result);
346 setvar(val.name, sresult, 0);
347 return result;
348 }
349
350 intmax_t
351 arith(const char *s)
352 {
353 struct stackmark smark;
354 intmax_t result;
355
356 setstackmark(&smark);
357
358 arith_buf = arith_startbuf = s;
359
360 result = assignment(arith_token(), 0);
361
362 if (last_token)
363 arith_err("expecting end of expression");
364
365 popstackmark(&smark);
366
367 return result;
368 }
369
370 /*
371 * The let(1)/exp(1) builtin.
372 */
373 int
374 expcmd(int argc, char **argv)
375 {
376 const char *p;
377 char *concat;
378 char **ap;
379 intmax_t i;
380
381 if (argc > 1) {
382 p = argv[1];
383 if (argc > 2) {
384 /*
385 * Concatenate arguments.
386 */
387 STARTSTACKSTR(concat);
388 ap = argv + 2;
389 for (;;) {
390 while (*p)
391 STPUTC(*p++, concat);
392 if ((p = *ap++) == NULL)
393 break;
394 STPUTC(' ', concat);
395 }
396 STPUTC('\0', concat);
397 p = grabstackstr(concat);
398 }
399 } else
400 p = "";
401
402 i = arith(p);
403
404 out1fmt(ARITH_FORMAT_STR "\n", i);
405 return !i;
406 }
407