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