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