arith_yacc.c revision 222386
1279377Simp/*-
2279377Simp * Copyright (c) 1993
3279377Simp *	The Regents of the University of California.  All rights reserved.
4279377Simp * Copyright (c) 2007
5279377Simp *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
6279377Simp *
7279377Simp * This code is derived from software contributed to Berkeley by
8279377Simp * Kenneth Almquist.
9279377Simp *
10279377Simp * Redistribution and use in source and binary forms, with or without
11279377Simp * modification, are permitted provided that the following conditions
12279377Simp * are met:
13279377Simp * 1. Redistributions of source code must retain the above copyright
14279377Simp *    notice, this list of conditions and the following disclaimer.
15279377Simp * 2. Redistributions in binary form must reproduce the above copyright
16279377Simp *    notice, this list of conditions and the following disclaimer in the
17279377Simp *    documentation and/or other materials provided with the distribution.
18279377Simp * 3. Neither the name of the University nor the names of its contributors
19279377Simp *    may be used to endorse or promote products derived from this software
20279377Simp *    without specific prior written permission.
21279377Simp *
22279377Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23279377Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24279377Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25279377Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26279377Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27279377Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28279377Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29279377Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30279377Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31279377Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32279377Simp * SUCH DAMAGE.
33279377Simp */
34279377Simp
35279377Simp#include <sys/cdefs.h>
36279377Simp__FBSDID("$FreeBSD: head/bin/sh/arith_yacc.c 222386 2011-05-27 20:53:07Z jilles $");
37279377Simp
38279377Simp#include <sys/limits.h>
39279377Simp#include <errno.h>
40279377Simp#include <inttypes.h>
41279377Simp#include <stdlib.h>
42279377Simp#include <stdio.h>
43279377Simp#include "arith.h"
44279377Simp#include "arith_yacc.h"
45279377Simp#include "expand.h"
46279377Simp#include "shell.h"
47295436Sandrew#include "error.h"
48279377Simp#include "memalloc.h"
49279377Simp#include "output.h"
50279377Simp#include "options.h"
51295436Sandrew#include "var.h"
52295436Sandrew
53295436Sandrew#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
54295436Sandrew#error Arithmetic tokens are out of order.
55295436Sandrew#endif
56295436Sandrew
57295436Sandrewstatic const char *arith_startbuf;
58295436Sandrew
59279377Simpconst char *arith_buf;
60279377Simpunion yystype yylval;
61279377Simp
62279377Simpstatic int last_token;
63279377Simp
64279377Simp#define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec
65279377Simp
66295436Sandrewstatic const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = {
67295436Sandrew	ARITH_PRECEDENCE(ARITH_MUL, 0),
68295436Sandrew	ARITH_PRECEDENCE(ARITH_DIV, 0),
69295436Sandrew	ARITH_PRECEDENCE(ARITH_REM, 0),
70295436Sandrew	ARITH_PRECEDENCE(ARITH_ADD, 1),
71295436Sandrew	ARITH_PRECEDENCE(ARITH_SUB, 1),
72295436Sandrew	ARITH_PRECEDENCE(ARITH_LSHIFT, 2),
73295436Sandrew	ARITH_PRECEDENCE(ARITH_RSHIFT, 2),
74295436Sandrew	ARITH_PRECEDENCE(ARITH_LT, 3),
75295436Sandrew	ARITH_PRECEDENCE(ARITH_LE, 3),
76295436Sandrew	ARITH_PRECEDENCE(ARITH_GT, 3),
77295436Sandrew	ARITH_PRECEDENCE(ARITH_GE, 3),
78295436Sandrew	ARITH_PRECEDENCE(ARITH_EQ, 4),
79295436Sandrew	ARITH_PRECEDENCE(ARITH_NE, 4),
80295436Sandrew	ARITH_PRECEDENCE(ARITH_BAND, 5),
81295436Sandrew	ARITH_PRECEDENCE(ARITH_BXOR, 6),
82279377Simp	ARITH_PRECEDENCE(ARITH_BOR, 7),
83279377Simp};
84279377Simp
85279377Simp#define ARITH_MAX_PREC 8
86279377Simp
87279377Simpstatic __dead2 void yyerror(const char *s)
88279377Simp{
89279377Simp	error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
90279377Simp	/* NOTREACHED */
91279377Simp}
92279377Simp
93279377Simpstatic arith_t arith_lookupvarint(char *varname)
94279377Simp{
95279377Simp	const char *str;
96279377Simp	char *p;
97279377Simp	arith_t result;
98279377Simp
99279377Simp	str = lookupvar(varname);
100279377Simp	if (uflag && str == NULL)
101279377Simp		yyerror("variable not set");
102279377Simp	if (str == NULL || *str == '\0')
103279377Simp		str = "0";
104279377Simp	errno = 0;
105279377Simp	result = strtoarith_t(str, &p, 0);
106279377Simp	if (errno != 0 || *p != '\0')
107279377Simp		yyerror("variable conversion error");
108279377Simp	return result;
109279377Simp}
110279377Simp
111279377Simpstatic inline int arith_prec(int op)
112279377Simp{
113279377Simp	return prec[op - ARITH_BINOP_MIN];
114279377Simp}
115279377Simp
116279377Simpstatic inline int higher_prec(int op1, int op2)
117279377Simp{
118279377Simp	return arith_prec(op1) < arith_prec(op2);
119279377Simp}
120279377Simp
121279377Simpstatic arith_t do_binop(int op, arith_t a, arith_t b)
122279377Simp{
123295436Sandrew
124279377Simp	switch (op) {
125279377Simp	default:
126279377Simp	case ARITH_REM:
127279377Simp	case ARITH_DIV:
128279377Simp		if (!b)
129279377Simp			yyerror("division by zero");
130279377Simp		if (a == ARITH_MIN && b == -1)
131279377Simp			yyerror("divide error");
132279377Simp		return op == ARITH_REM ? a % b : a / b;
133279377Simp	case ARITH_MUL:
134279377Simp		return a * b;
135279377Simp	case ARITH_ADD:
136279377Simp		return a + b;
137279377Simp	case ARITH_SUB:
138279377Simp		return a - b;
139279377Simp	case ARITH_LSHIFT:
140279377Simp		return a << b;
141279377Simp	case ARITH_RSHIFT:
142279377Simp		return a >> b;
143279377Simp	case ARITH_LT:
144279377Simp		return a < b;
145279377Simp	case ARITH_LE:
146279377Simp		return a <= b;
147279377Simp	case ARITH_GT:
148279377Simp		return a > b;
149279377Simp	case ARITH_GE:
150279377Simp		return a >= b;
151279377Simp	case ARITH_EQ:
152279377Simp		return a == b;
153279377Simp	case ARITH_NE:
154279377Simp		return a != b;
155279377Simp	case ARITH_BAND:
156279377Simp		return a & b;
157279377Simp	case ARITH_BXOR:
158279377Simp		return a ^ b;
159279377Simp	case ARITH_BOR:
160279377Simp		return a | b;
161279377Simp	}
162279377Simp}
163279377Simp
164279377Simpstatic arith_t assignment(int var, int noeval);
165279377Simp
166279377Simpstatic arith_t primary(int token, union yystype *val, int op, int noeval)
167279377Simp{
168279377Simp	arith_t result;
169279377Simp
170279377Simpagain:
171279377Simp	switch (token) {
172279377Simp	case ARITH_LPAREN:
173279377Simp		result = assignment(op, noeval);
174279377Simp		if (last_token != ARITH_RPAREN)
175279377Simp			yyerror("expecting ')'");
176279377Simp		last_token = yylex();
177279377Simp		return result;
178279377Simp	case ARITH_NUM:
179279377Simp		last_token = op;
180279377Simp		return val->val;
181279377Simp	case ARITH_VAR:
182279377Simp		last_token = op;
183279377Simp		return noeval ? val->val : arith_lookupvarint(val->name);
184279377Simp	case ARITH_ADD:
185279377Simp		token = op;
186279377Simp		*val = yylval;
187295436Sandrew		op = yylex();
188295436Sandrew		goto again;
189295436Sandrew	case ARITH_SUB:
190295436Sandrew		*val = yylval;
191295436Sandrew		return -primary(op, val, yylex(), noeval);
192295436Sandrew	case ARITH_NOT:
193295436Sandrew		*val = yylval;
194295436Sandrew		return !primary(op, val, yylex(), noeval);
195295436Sandrew	case ARITH_BNOT:
196295436Sandrew		*val = yylval;
197295436Sandrew		return ~primary(op, val, yylex(), noeval);
198295436Sandrew	default:
199295436Sandrew		yyerror("expecting primary");
200295436Sandrew	}
201295436Sandrew}
202295436Sandrew
203295436Sandrewstatic arith_t binop2(arith_t a, int op, int precedence, int noeval)
204279377Simp{
205279377Simp	for (;;) {
206279377Simp		union yystype val;
207279377Simp		arith_t b;
208279377Simp		int op2;
209279377Simp		int token;
210279377Simp
211279377Simp		token = yylex();
212279377Simp		val = yylval;
213279377Simp
214279377Simp		b = primary(token, &val, yylex(), noeval);
215279377Simp
216279377Simp		op2 = last_token;
217279377Simp		if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX &&
218279377Simp		    higher_prec(op2, op)) {
219279377Simp			b = binop2(b, op2, arith_prec(op), noeval);
220279377Simp			op2 = last_token;
221279377Simp		}
222279377Simp
223279377Simp		a = noeval ? b : do_binop(op, a, b);
224295436Sandrew
225295436Sandrew		if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX ||
226295436Sandrew		    arith_prec(op2) >= precedence)
227295436Sandrew			return a;
228295436Sandrew
229295436Sandrew		op = op2;
230295436Sandrew	}
231295436Sandrew}
232295436Sandrew
233295436Sandrewstatic arith_t binop(int token, union yystype *val, int op, int noeval)
234295436Sandrew{
235295436Sandrew	arith_t a = primary(token, val, op, noeval);
236295436Sandrew
237295436Sandrew	op = last_token;
238295436Sandrew	if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX)
239295436Sandrew		return a;
240279377Simp
241279377Simp	return binop2(a, op, ARITH_MAX_PREC, noeval);
242279377Simp}
243279377Simp
244279377Simpstatic arith_t and(int token, union yystype *val, int op, int noeval)
245279377Simp{
246279377Simp	arith_t a = binop(token, val, op, noeval);
247279377Simp	arith_t b;
248279377Simp
249279377Simp	op = last_token;
250279377Simp	if (op != ARITH_AND)
251279377Simp		return a;
252279377Simp
253279377Simp	token = yylex();
254279377Simp	*val = yylval;
255279377Simp
256279377Simp	b = and(token, val, yylex(), noeval | !a);
257279377Simp
258295436Sandrew	return a && b;
259295436Sandrew}
260279377Simp
261279377Simpstatic arith_t or(int token, union yystype *val, int op, int noeval)
262279377Simp{
263279377Simp	arith_t a = and(token, val, op, noeval);
264279377Simp	arith_t b;
265279377Simp
266279377Simp	op = last_token;
267279377Simp	if (op != ARITH_OR)
268279377Simp		return a;
269279377Simp
270279377Simp	token = yylex();
271279377Simp	*val = yylval;
272279377Simp
273279377Simp	b = or(token, val, yylex(), noeval | !!a);
274279377Simp
275279377Simp	return a || b;
276279377Simp}
277279377Simp
278279377Simpstatic arith_t cond(int token, union yystype *val, int op, int noeval)
279279377Simp{
280279377Simp	arith_t a = or(token, val, op, noeval);
281279377Simp	arith_t b;
282279377Simp	arith_t c;
283279377Simp
284279377Simp	if (last_token != ARITH_QMARK)
285279377Simp		return a;
286279377Simp
287279377Simp	b = assignment(yylex(), noeval | !a);
288279377Simp
289279377Simp	if (last_token != ARITH_COLON)
290279377Simp		yyerror("expecting ':'");
291279377Simp
292279377Simp	token = yylex();
293295436Sandrew	*val = yylval;
294295436Sandrew
295295436Sandrew	c = cond(token, val, yylex(), noeval | !!a);
296295436Sandrew
297295436Sandrew	return a ? b : c;
298295436Sandrew}
299295436Sandrew
300295436Sandrewstatic arith_t assignment(int var, int noeval)
301279377Simp{
302279377Simp	union yystype val = yylval;
303279377Simp	int op = yylex();
304279377Simp	arith_t result;
305279377Simp	char sresult[DIGITS(result) + 1];
306279377Simp
307279377Simp	if (var != ARITH_VAR)
308279377Simp		return cond(var, &val, op, noeval);
309279377Simp
310279377Simp	if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX))
311279377Simp		return cond(var, &val, op, noeval);
312279377Simp
313279377Simp	result = assignment(yylex(), noeval);
314279377Simp	if (noeval)
315279377Simp		return result;
316279377Simp
317279377Simp	if (op != ARITH_ASS)
318279377Simp		result = do_binop(op - 11, arith_lookupvarint(val.name), result);
319279377Simp	snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result);
320279377Simp	setvar(val.name, sresult, 0);
321279377Simp	return result;
322279377Simp}
323279377Simp
324279377Simparith_t arith(const char *s)
325279377Simp{
326279377Simp	struct stackmark smark;
327279377Simp	arith_t result;
328279377Simp
329279377Simp	setstackmark(&smark);
330279377Simp
331279377Simp	arith_buf = arith_startbuf = s;
332279377Simp
333279377Simp	result = assignment(yylex(), 0);
334279377Simp
335279377Simp	if (last_token)
336279377Simp		yyerror("expecting EOF");
337279377Simp
338279377Simp	popstackmark(&smark);
339279377Simp
340279377Simp	return result;
341279377Simp}
342279377Simp
343279377Simp/*
344279377Simp *  The exp(1) builtin.
345279377Simp */
346279377Simpint
347279377Simpletcmd(int argc, char **argv)
348279377Simp{
349279377Simp	const char *p;
350279377Simp	char *concat;
351279377Simp	char **ap;
352279377Simp	arith_t i;
353279377Simp
354279377Simp	if (argc > 1) {
355279377Simp		p = argv[1];
356279377Simp		if (argc > 2) {
357279377Simp			/*
358279377Simp			 * Concatenate arguments.
359279377Simp			 */
360279377Simp			STARTSTACKSTR(concat);
361279377Simp			ap = argv + 2;
362279377Simp			for (;;) {
363279377Simp				while (*p)
364279377Simp					STPUTC(*p++, concat);
365279377Simp				if ((p = *ap++) == NULL)
366279377Simp					break;
367279377Simp				STPUTC(' ', concat);
368279377Simp			}
369295436Sandrew			STPUTC('\0', concat);
370279377Simp			p = grabstackstr(concat);
371279377Simp		}
372279377Simp	} else
373279377Simp		p = "";
374279377Simp
375279377Simp	i = arith(p);
376279377Simp
377279377Simp	out1fmt(ARITH_FORMAT_STR "\n", i);
378279377Simp	return !i;
379279377Simp}
380279377Simp
381279377Simp