arith_yacc.c revision 222386
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__FBSDID("$FreeBSD: head/bin/sh/arith_yacc.c 222386 2011-05-27 20:53:07Z jilles $");
37
38#include <sys/limits.h>
39#include <errno.h>
40#include <inttypes.h>
41#include <stdlib.h>
42#include <stdio.h>
43#include "arith.h"
44#include "arith_yacc.h"
45#include "expand.h"
46#include "shell.h"
47#include "error.h"
48#include "memalloc.h"
49#include "output.h"
50#include "options.h"
51#include "var.h"
52
53#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
54#error Arithmetic tokens are out of order.
55#endif
56
57static const char *arith_startbuf;
58
59const char *arith_buf;
60union yystype yylval;
61
62static int last_token;
63
64#define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec
65
66static const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = {
67	ARITH_PRECEDENCE(ARITH_MUL, 0),
68	ARITH_PRECEDENCE(ARITH_DIV, 0),
69	ARITH_PRECEDENCE(ARITH_REM, 0),
70	ARITH_PRECEDENCE(ARITH_ADD, 1),
71	ARITH_PRECEDENCE(ARITH_SUB, 1),
72	ARITH_PRECEDENCE(ARITH_LSHIFT, 2),
73	ARITH_PRECEDENCE(ARITH_RSHIFT, 2),
74	ARITH_PRECEDENCE(ARITH_LT, 3),
75	ARITH_PRECEDENCE(ARITH_LE, 3),
76	ARITH_PRECEDENCE(ARITH_GT, 3),
77	ARITH_PRECEDENCE(ARITH_GE, 3),
78	ARITH_PRECEDENCE(ARITH_EQ, 4),
79	ARITH_PRECEDENCE(ARITH_NE, 4),
80	ARITH_PRECEDENCE(ARITH_BAND, 5),
81	ARITH_PRECEDENCE(ARITH_BXOR, 6),
82	ARITH_PRECEDENCE(ARITH_BOR, 7),
83};
84
85#define ARITH_MAX_PREC 8
86
87static __dead2 void yyerror(const char *s)
88{
89	error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
90	/* NOTREACHED */
91}
92
93static 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, 0);
106	if (errno != 0 || *p != '\0')
107		yyerror("variable conversion error");
108	return result;
109}
110
111static inline int arith_prec(int op)
112{
113	return prec[op - ARITH_BINOP_MIN];
114}
115
116static inline int higher_prec(int op1, int op2)
117{
118	return arith_prec(op1) < arith_prec(op2);
119}
120
121static 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 a * b;
135	case ARITH_ADD:
136		return a + b;
137	case ARITH_SUB:
138		return a - b;
139	case ARITH_LSHIFT:
140		return a << b;
141	case ARITH_RSHIFT:
142		return a >> b;
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
164static arith_t assignment(int var, int noeval);
165
166static arith_t primary(int token, union yystype *val, int op, int noeval)
167{
168	arith_t result;
169
170again:
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
203static 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
233static 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
244static 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
261static 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
278static 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
300static 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
324arith_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 */
346int
347letcmd(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
381