1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1993
5 * The Regents of the University of California. All rights reserved.
6 * Copyright (c) 2007
7 * Herbert Xu <herbert@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
37#if defined(__has_include)
38#if __has_include(<sys/cdefs.h>)
39#include <sys/cdefs.h>
40#endif
41#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
42#include <sys/cdefs.h>
43#endif
44#include <limits.h>
45#include <errno.h>
46#include <inttypes.h>
47#include <stdlib.h>
48#include <stdio.h>
49#include "arith.h"
50#include "arith_yacc.h"
51#include "expand.h"
52#include "shell.h"
53#include "error.h"
54#include "memalloc.h"
55#include "output.h"
56#include "options.h"
57#include "var.h"
58
59#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
60#error Arithmetic tokens are out of order.
61#endif
62
63static const char *arith_startbuf;
64
65const char *arith_buf;
66union yystype yylval;
67
68static int last_token;
69
70#define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec
71
72static const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = {
73 ARITH_PRECEDENCE(ARITH_MUL, 0),
74 ARITH_PRECEDENCE(ARITH_DIV, 0),
75 ARITH_PRECEDENCE(ARITH_REM, 0),
76 ARITH_PRECEDENCE(ARITH_ADD, 1),
77 ARITH_PRECEDENCE(ARITH_SUB, 1),
78 ARITH_PRECEDENCE(ARITH_LSHIFT, 2),
79 ARITH_PRECEDENCE(ARITH_RSHIFT, 2),
80 ARITH_PRECEDENCE(ARITH_LT, 3),
81 ARITH_PRECEDENCE(ARITH_LE, 3),
82 ARITH_PRECEDENCE(ARITH_GT, 3),
83 ARITH_PRECEDENCE(ARITH_GE, 3),
84 ARITH_PRECEDENCE(ARITH_EQ, 4),
85 ARITH_PRECEDENCE(ARITH_NE, 4),
86 ARITH_PRECEDENCE(ARITH_BAND, 5),
87 ARITH_PRECEDENCE(ARITH_BXOR, 6),
88 ARITH_PRECEDENCE(ARITH_BOR, 7),
89};
90
91#define ARITH_MAX_PREC 8
92
93int letcmd(int, char **);
94
95static __dead2 void yyerror(const char *s)
96{
97 error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
98 /* NOTREACHED */
99}
100
101static arith_t arith_lookupvarint(char *varname)
102{
103 const char *str;
104 char *p;
105 arith_t result;
106
107 str = lookupvar(varname);
108 if (uflag && str == NULL)
109 yyerror("variable not set");
110 if (str == NULL || *str == '\0')
111 str = "0";
112 errno = 0;
113 result = strtoarith_t(str, &p);
114 if (errno != 0 || *p != '\0')
115 yyerror("variable conversion error");
116 return result;
117}
118
119static inline int arith_prec(int op)
120{
121 return prec[op - ARITH_BINOP_MIN];
122}
123
124static inline int higher_prec(int op1, int op2)
125{
126 return arith_prec(op1) < arith_prec(op2);
127}
128
129static arith_t do_binop(int op, arith_t a, arith_t b)
130{
131
132 switch (op) {
133 default:
134 case ARITH_REM:
135 case ARITH_DIV:
136 if (!b)
137 yyerror("division by zero");
138 if (a == ARITH_MIN && b == -1)
139 yyerror("divide error");
140 return op == ARITH_REM ? a % b : a / b;
141 case ARITH_MUL:
142 return (uintmax_t)a * (uintmax_t)b;
143 case ARITH_ADD:
144 return (uintmax_t)a + (uintmax_t)b;
145 case ARITH_SUB:
146 return (uintmax_t)a - (uintmax_t)b;
147 case ARITH_LSHIFT:
148 return (uintmax_t)a << (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
149 case ARITH_RSHIFT:
150 return a >> (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
151 case ARITH_LT:
152 return a < b;
153 case ARITH_LE:
154 return a <= b;
155 case ARITH_GT:
156 return a > b;
157 case ARITH_GE:
158 return a >= b;
159 case ARITH_EQ:
160 return a == b;
161 case ARITH_NE:
162 return a != b;
163 case ARITH_BAND:
164 return a & b;
165 case ARITH_BXOR:
166 return a ^ b;
167 case ARITH_BOR:
168 return a | b;
169 }
170}
171
172static arith_t assignment(int var, int noeval);
173
174static arith_t primary(int token, union yystype *val, int op, int noeval)
175{
176 arith_t result;
177
178again:
179 switch (token) {
180 case ARITH_LPAREN:
181 result = assignment(op, noeval);
182 if (last_token != ARITH_RPAREN)
183 yyerror("expecting ')'");
184 last_token = yylex();
185 return result;
186 case ARITH_NUM:
187 last_token = op;
188 return val->val;
189 case ARITH_VAR:
190 last_token = op;
191 return noeval ? val->val : arith_lookupvarint(val->name);
192 case ARITH_ADD:
193 token = op;
194 *val = yylval;
195 op = yylex();
196 goto again;
197 case ARITH_SUB:
198 *val = yylval;
199 return -primary(op, val, yylex(), noeval);
200 case ARITH_NOT:
201 *val = yylval;
202 return !primary(op, val, yylex(), noeval);
203 case ARITH_BNOT:
204 *val = yylval;
205 return ~primary(op, val, yylex(), noeval);
206 default:
207 yyerror("expecting primary");
208 }
209}
210
211static arith_t binop2(arith_t a, int op, int precedence, int noeval)
212{
213 for (;;) {
214 union yystype val;
215 arith_t b;
216 int op2;
217 int token;
218
219 token = yylex();
220 val = yylval;
221
222 b = primary(token, &val, yylex(), noeval);
223
224 op2 = last_token;
225 if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX &&
226 higher_prec(op2, op)) {
227 b = binop2(b, op2, arith_prec(op), noeval);
228 op2 = last_token;
229 }
230
231 a = noeval ? b : do_binop(op, a, b);
232
233 if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX ||
234 arith_prec(op2) >= precedence)
235 return a;
236
237 op = op2;
238 }
239}
240
241static arith_t binop(int token, union yystype *val, int op, int noeval)
242{
243 arith_t a = primary(token, val, op, noeval);
244
245 op = last_token;
246 if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX)
247 return a;
248
249 return binop2(a, op, ARITH_MAX_PREC, noeval);
250}
251
252static arith_t and(int token, union yystype *val, int op, int noeval)
253{
254 arith_t a = binop(token, val, op, noeval);
255 arith_t b;
256
257 op = last_token;
258 if (op != ARITH_AND)
259 return a;
260
261 token = yylex();
262 *val = yylval;
263
264 b = and(token, val, yylex(), noeval | !a);
265
266 return a && b;
267}
268
269static arith_t or(int token, union yystype *val, int op, int noeval)
270{
271 arith_t a = and(token, val, op, noeval);
272 arith_t b;
273
274 op = last_token;
275 if (op != ARITH_OR)
276 return a;
277
278 token = yylex();
279 *val = yylval;
280
281 b = or(token, val, yylex(), noeval | !!a);
282
283 return a || b;
284}
285
286static arith_t cond(int token, union yystype *val, int op, int noeval)
287{
288 arith_t a = or(token, val, op, noeval);
289 arith_t b;
290 arith_t c;
291
292 if (last_token != ARITH_QMARK)
293 return a;
294
295 b = assignment(yylex(), noeval | !a);
296
297 if (last_token != ARITH_COLON)
298 yyerror("expecting ':'");
299
300 token = yylex();
301 *val = yylval;
302
303 c = cond(token, val, yylex(), noeval | !!a);
304
305 return a ? b : c;
306}
307
308static arith_t assignment(int var, int noeval)
309{
310 union yystype val = yylval;
311 int op = yylex();
312 arith_t result;
313 char sresult[DIGITS(result) + 1];
314
315 if (var != ARITH_VAR)
316 return cond(var, &val, op, noeval);
317
318 if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX))
319 return cond(var, &val, op, noeval);
320
321 result = assignment(yylex(), noeval);
322 if (noeval)
323 return result;
324
325 if (op != ARITH_ASS)
326 result = do_binop(op - 11, arith_lookupvarint(val.name), result);
327 snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result);
328 setvar(val.name, sresult, 0);
329 return result;
330}
331
332arith_t arith(const char *s)
333{
334 struct stackmark smark;
335 arith_t result;
336
337 setstackmark(&smark);
338
339 arith_buf = arith_startbuf = s;
340
341 result = assignment(yylex(), 0);
342
343 if (last_token)
344 yyerror("expecting EOF");
345
346 popstackmark(&smark);
347
348 return result;
349}
350
351/*
352 * The exp(1) builtin.
353 */
354int
355letcmd(int argc, char **argv)
356{
357 const char *p;
358 char *concat;
359 char **ap;
360 arith_t i;
361
362 if (argc > 1) {
363 p = argv[1];
364 if (argc > 2) {
365 /*
366 * Concatenate arguments.
367 */
368 STARTSTACKSTR(concat);
369 ap = argv + 2;
370 for (;;) {
371 while (*p)
372 STPUTC(*p++, concat);
373 if ((p = *ap++) == NULL)
374 break;
375 STPUTC(' ', concat);
376 }
377 STPUTC('\0', concat);
378 p = grabstackstr(concat);
379 }
380 } else
381 p = "";
382
383 i = arith(p);
384
385 out1fmt(ARITH_FORMAT_STR "\n", i);
386 return !i;
387}