arith_yacc.c revision 221463
155714Skris/*-
255714Skris * Copyright (c) 1993
355714Skris *	The Regents of the University of California.  All rights reserved.
455714Skris * Copyright (c) 2007
555714Skris *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
655714Skris *
755714Skris * This code is derived from software contributed to Berkeley by
855714Skris * Kenneth Almquist.
955714Skris *
1055714Skris * Redistribution and use in source and binary forms, with or without
1155714Skris * modification, are permitted provided that the following conditions
1255714Skris * are met:
1355714Skris * 1. Redistributions of source code must retain the above copyright
1455714Skris *    notice, this list of conditions and the following disclaimer.
1555714Skris * 2. Redistributions in binary form must reproduce the above copyright
1655714Skris *    notice, this list of conditions and the following disclaimer in the
1755714Skris *    documentation and/or other materials provided with the distribution.
1855714Skris * 3. Neither the name of the University nor the names of its contributors
1955714Skris *    may be used to endorse or promote products derived from this software
2055714Skris *    without specific prior written permission.
2155714Skris *
2255714Skris * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2355714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2455714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2555714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2655714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2755714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2855714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2955714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3055714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3155714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3255714Skris * SUCH DAMAGE.
3355714Skris */
3455714Skris
3555714Skris#include <sys/cdefs.h>
3655714Skris__FBSDID("$FreeBSD: head/bin/sh/arith_yacc.c 221463 2011-05-04 22:12:22Z jilles $");
3755714Skris
3855714Skris#include <sys/limits.h>
3955714Skris#include <errno.h>
4055714Skris#include <inttypes.h>
4155714Skris#include <stdlib.h>
4255714Skris#include <stdio.h>
4355714Skris#include "arith.h"
4455714Skris#include "arith_yacc.h"
4555714Skris#include "expand.h"
4655714Skris#include "shell.h"
4755714Skris#include "error.h"
4855714Skris#include "memalloc.h"
4955714Skris#include "output.h"
5055714Skris#include "options.h"
5155714Skris#include "var.h"
5255714Skris
5355714Skris#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
5455714Skris#error Arithmetic tokens are out of order.
5555714Skris#endif
5655714Skris
5755714Skrisstatic const char *arith_startbuf;
5855714Skris
5955714Skrisconst char *arith_buf;
6055714Skrisunion yystype yylval;
6155714Skris
6255714Skrisstatic int last_token;
6355714Skris
6455714Skris#define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec
6555714Skris
6668651Skrisstatic const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = {
6768651Skris	ARITH_PRECEDENCE(ARITH_MUL, 0),
6868651Skris	ARITH_PRECEDENCE(ARITH_DIV, 0),
6955714Skris	ARITH_PRECEDENCE(ARITH_REM, 0),
7055714Skris	ARITH_PRECEDENCE(ARITH_ADD, 1),
7155714Skris	ARITH_PRECEDENCE(ARITH_SUB, 1),
7255714Skris	ARITH_PRECEDENCE(ARITH_LSHIFT, 2),
7355714Skris	ARITH_PRECEDENCE(ARITH_RSHIFT, 2),
7455714Skris	ARITH_PRECEDENCE(ARITH_LT, 3),
7555714Skris	ARITH_PRECEDENCE(ARITH_LE, 3),
7655714Skris	ARITH_PRECEDENCE(ARITH_GT, 3),
7755714Skris	ARITH_PRECEDENCE(ARITH_GE, 3),
7855714Skris	ARITH_PRECEDENCE(ARITH_EQ, 4),
7955714Skris	ARITH_PRECEDENCE(ARITH_NE, 4),
8055714Skris	ARITH_PRECEDENCE(ARITH_BAND, 5),
8155714Skris	ARITH_PRECEDENCE(ARITH_BXOR, 6),
8255714Skris	ARITH_PRECEDENCE(ARITH_BOR, 7),
8355714Skris};
8455714Skris
8555714Skris#define ARITH_MAX_PREC 8
8655714Skris
8755714Skrisstatic __dead2 void yyerror(const char *s)
8855714Skris{
8955714Skris	error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
9055714Skris	/* NOTREACHED */
9155714Skris}
9255714Skris
9355714Skrisstatic arith_t arith_lookupvarint(char *varname)
9455714Skris{
9555714Skris	const char *str;
9655714Skris	char *p;
9755714Skris	arith_t result;
9855714Skris
9955714Skris	str = lookupvar(varname);
10055714Skris	if (uflag && str == NULL)
10155714Skris		yyerror("variable not set");
10255714Skris	if (str == NULL || *str == '\0')
10355714Skris		str = "0";
10455714Skris	errno = 0;
10555714Skris	result = strtoarith_t(str, &p, 0);
10655714Skris	if (errno != 0 || *p != '\0')
10755714Skris		yyerror("variable conversion error");
10855714Skris	return result;
10955714Skris}
11055714Skris
11155714Skrisstatic 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
347expcmd(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