xref: /dragonfly/bin/sh/arith_yacc.c (revision 3e3895bf)
199512ac4SPeter Avalos /*-
299512ac4SPeter Avalos  * Copyright (c) 1993
399512ac4SPeter Avalos  *	The Regents of the University of California.  All rights reserved.
499512ac4SPeter Avalos  * Copyright (c) 2007
599512ac4SPeter Avalos  *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
699512ac4SPeter Avalos  *
799512ac4SPeter Avalos  * This code is derived from software contributed to Berkeley by
899512ac4SPeter Avalos  * Kenneth Almquist.
999512ac4SPeter Avalos  *
1099512ac4SPeter Avalos  * Redistribution and use in source and binary forms, with or without
1199512ac4SPeter Avalos  * modification, are permitted provided that the following conditions
1299512ac4SPeter Avalos  * are met:
1399512ac4SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
1499512ac4SPeter Avalos  *    notice, this list of conditions and the following disclaimer.
1599512ac4SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
1699512ac4SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
1799512ac4SPeter Avalos  *    documentation and/or other materials provided with the distribution.
1899512ac4SPeter Avalos  * 3. Neither the name of the University nor the names of its contributors
1999512ac4SPeter Avalos  *    may be used to endorse or promote products derived from this software
2099512ac4SPeter Avalos  *    without specific prior written permission.
2199512ac4SPeter Avalos  *
2299512ac4SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2399512ac4SPeter Avalos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2499512ac4SPeter Avalos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2599512ac4SPeter Avalos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2699512ac4SPeter Avalos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2799512ac4SPeter Avalos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2899512ac4SPeter Avalos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2999512ac4SPeter Avalos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3099512ac4SPeter Avalos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3199512ac4SPeter Avalos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3299512ac4SPeter Avalos  * SUCH DAMAGE.
3399512ac4SPeter Avalos  */
3499512ac4SPeter Avalos 
3502d0b1ceSMatthew Dillon #include <sys/cdefs.h>
36*3e3895bfSKrzysztof Piecuch __FBSDID("$FreeBSD: head/bin/sh/arith_yacc.c 343981 2019-02-10 22:23:05Z jilles $");
3702d0b1ceSMatthew Dillon 
3871978b8eSPeter Avalos #include <limits.h>
3999512ac4SPeter Avalos #include <errno.h>
4099512ac4SPeter Avalos #include <inttypes.h>
4199512ac4SPeter Avalos #include <stdlib.h>
4299512ac4SPeter Avalos #include <stdio.h>
4399512ac4SPeter Avalos #include "arith.h"
4499512ac4SPeter Avalos #include "arith_yacc.h"
4599512ac4SPeter Avalos #include "expand.h"
4699512ac4SPeter Avalos #include "shell.h"
4799512ac4SPeter Avalos #include "error.h"
4899512ac4SPeter Avalos #include "memalloc.h"
4999512ac4SPeter Avalos #include "output.h"
5099512ac4SPeter Avalos #include "options.h"
5199512ac4SPeter Avalos #include "var.h"
5299512ac4SPeter Avalos 
5399512ac4SPeter Avalos #if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
5499512ac4SPeter Avalos #error Arithmetic tokens are out of order.
5599512ac4SPeter Avalos #endif
5699512ac4SPeter Avalos 
5799512ac4SPeter Avalos static const char *arith_startbuf;
5899512ac4SPeter Avalos 
5999512ac4SPeter Avalos const char *arith_buf;
6099512ac4SPeter Avalos union yystype yylval;
6199512ac4SPeter Avalos 
6299512ac4SPeter Avalos static int last_token;
6399512ac4SPeter Avalos 
6499512ac4SPeter Avalos #define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec
6599512ac4SPeter Avalos 
6699512ac4SPeter Avalos static const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = {
6799512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_MUL, 0),
6899512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_DIV, 0),
6999512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_REM, 0),
7099512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_ADD, 1),
7199512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_SUB, 1),
7299512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_LSHIFT, 2),
7399512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_RSHIFT, 2),
7499512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_LT, 3),
7599512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_LE, 3),
7699512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_GT, 3),
7799512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_GE, 3),
7899512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_EQ, 4),
7999512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_NE, 4),
8099512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_BAND, 5),
8199512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_BXOR, 6),
8299512ac4SPeter Avalos 	ARITH_PRECEDENCE(ARITH_BOR, 7),
8399512ac4SPeter Avalos };
8499512ac4SPeter Avalos 
8599512ac4SPeter Avalos #define ARITH_MAX_PREC 8
8699512ac4SPeter Avalos 
8702d0b1ceSMatthew Dillon int letcmd(int, char **);
8802d0b1ceSMatthew Dillon 
yyerror(const char * s)8902d0b1ceSMatthew Dillon static __dead2 void yyerror(const char *s)
9099512ac4SPeter Avalos {
9199512ac4SPeter Avalos 	error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
9299512ac4SPeter Avalos 	/* NOTREACHED */
9399512ac4SPeter Avalos }
9499512ac4SPeter Avalos 
arith_lookupvarint(char * varname)9502d0b1ceSMatthew Dillon static arith_t arith_lookupvarint(char *varname)
9699512ac4SPeter Avalos {
9799512ac4SPeter Avalos 	const char *str;
9899512ac4SPeter Avalos 	char *p;
9999512ac4SPeter Avalos 	arith_t result;
10099512ac4SPeter Avalos 
10199512ac4SPeter Avalos 	str = lookupvar(varname);
102024481c1SPeter Avalos 	if (uflag && str == NULL)
103024481c1SPeter Avalos 		yyerror("variable not set");
10499512ac4SPeter Avalos 	if (str == NULL || *str == '\0')
10599512ac4SPeter Avalos 		str = "0";
10699512ac4SPeter Avalos 	errno = 0;
107*3e3895bfSKrzysztof Piecuch 	result = strtoarith_t(str, &p);
10899512ac4SPeter Avalos 	if (errno != 0 || *p != '\0')
10999512ac4SPeter Avalos 		yyerror("variable conversion error");
11099512ac4SPeter Avalos 	return result;
11199512ac4SPeter Avalos }
11299512ac4SPeter Avalos 
arith_prec(int op)11302d0b1ceSMatthew Dillon static inline int arith_prec(int op)
11499512ac4SPeter Avalos {
11599512ac4SPeter Avalos 	return prec[op - ARITH_BINOP_MIN];
11699512ac4SPeter Avalos }
11799512ac4SPeter Avalos 
higher_prec(int op1,int op2)11802d0b1ceSMatthew Dillon static inline int higher_prec(int op1, int op2)
11999512ac4SPeter Avalos {
12099512ac4SPeter Avalos 	return arith_prec(op1) < arith_prec(op2);
12199512ac4SPeter Avalos }
12299512ac4SPeter Avalos 
do_binop(int op,arith_t a,arith_t b)12302d0b1ceSMatthew Dillon static arith_t do_binop(int op, arith_t a, arith_t b)
12499512ac4SPeter Avalos {
12599512ac4SPeter Avalos 
12699512ac4SPeter Avalos 	switch (op) {
12799512ac4SPeter Avalos 	default:
12899512ac4SPeter Avalos 	case ARITH_REM:
12999512ac4SPeter Avalos 	case ARITH_DIV:
13099512ac4SPeter Avalos 		if (!b)
13199512ac4SPeter Avalos 			yyerror("division by zero");
132f5960706SPeter Avalos 		if (a == ARITH_MIN && b == -1)
133f5960706SPeter Avalos 			yyerror("divide error");
13499512ac4SPeter Avalos 		return op == ARITH_REM ? a % b : a / b;
13599512ac4SPeter Avalos 	case ARITH_MUL:
136279f045cSPeter Avalos 		return (uintmax_t)a * (uintmax_t)b;
13799512ac4SPeter Avalos 	case ARITH_ADD:
138279f045cSPeter Avalos 		return (uintmax_t)a + (uintmax_t)b;
13999512ac4SPeter Avalos 	case ARITH_SUB:
140279f045cSPeter Avalos 		return (uintmax_t)a - (uintmax_t)b;
14199512ac4SPeter Avalos 	case ARITH_LSHIFT:
14202d0b1ceSMatthew Dillon 		return (uintmax_t)a << (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
14399512ac4SPeter Avalos 	case ARITH_RSHIFT:
14402d0b1ceSMatthew Dillon 		return a >> (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
14599512ac4SPeter Avalos 	case ARITH_LT:
14699512ac4SPeter Avalos 		return a < b;
14799512ac4SPeter Avalos 	case ARITH_LE:
14899512ac4SPeter Avalos 		return a <= b;
14999512ac4SPeter Avalos 	case ARITH_GT:
15099512ac4SPeter Avalos 		return a > b;
15199512ac4SPeter Avalos 	case ARITH_GE:
15299512ac4SPeter Avalos 		return a >= b;
15399512ac4SPeter Avalos 	case ARITH_EQ:
15499512ac4SPeter Avalos 		return a == b;
15599512ac4SPeter Avalos 	case ARITH_NE:
15699512ac4SPeter Avalos 		return a != b;
15799512ac4SPeter Avalos 	case ARITH_BAND:
15899512ac4SPeter Avalos 		return a & b;
15999512ac4SPeter Avalos 	case ARITH_BXOR:
16099512ac4SPeter Avalos 		return a ^ b;
16199512ac4SPeter Avalos 	case ARITH_BOR:
16299512ac4SPeter Avalos 		return a | b;
16399512ac4SPeter Avalos 	}
16499512ac4SPeter Avalos }
16599512ac4SPeter Avalos 
16699512ac4SPeter Avalos static arith_t assignment(int var, int noeval);
16799512ac4SPeter Avalos 
primary(int token,union yystype * val,int op,int noeval)16802d0b1ceSMatthew Dillon static arith_t primary(int token, union yystype *val, int op, int noeval)
16999512ac4SPeter Avalos {
17099512ac4SPeter Avalos 	arith_t result;
17199512ac4SPeter Avalos 
17299512ac4SPeter Avalos again:
17399512ac4SPeter Avalos 	switch (token) {
17499512ac4SPeter Avalos 	case ARITH_LPAREN:
17599512ac4SPeter Avalos 		result = assignment(op, noeval);
17699512ac4SPeter Avalos 		if (last_token != ARITH_RPAREN)
17799512ac4SPeter Avalos 			yyerror("expecting ')'");
17899512ac4SPeter Avalos 		last_token = yylex();
17999512ac4SPeter Avalos 		return result;
18099512ac4SPeter Avalos 	case ARITH_NUM:
18199512ac4SPeter Avalos 		last_token = op;
18299512ac4SPeter Avalos 		return val->val;
18399512ac4SPeter Avalos 	case ARITH_VAR:
18499512ac4SPeter Avalos 		last_token = op;
18599512ac4SPeter Avalos 		return noeval ? val->val : arith_lookupvarint(val->name);
18699512ac4SPeter Avalos 	case ARITH_ADD:
18799512ac4SPeter Avalos 		token = op;
18899512ac4SPeter Avalos 		*val = yylval;
18999512ac4SPeter Avalos 		op = yylex();
19099512ac4SPeter Avalos 		goto again;
19199512ac4SPeter Avalos 	case ARITH_SUB:
19299512ac4SPeter Avalos 		*val = yylval;
19399512ac4SPeter Avalos 		return -primary(op, val, yylex(), noeval);
19499512ac4SPeter Avalos 	case ARITH_NOT:
19599512ac4SPeter Avalos 		*val = yylval;
19699512ac4SPeter Avalos 		return !primary(op, val, yylex(), noeval);
19799512ac4SPeter Avalos 	case ARITH_BNOT:
19899512ac4SPeter Avalos 		*val = yylval;
19999512ac4SPeter Avalos 		return ~primary(op, val, yylex(), noeval);
20099512ac4SPeter Avalos 	default:
20199512ac4SPeter Avalos 		yyerror("expecting primary");
20299512ac4SPeter Avalos 	}
20399512ac4SPeter Avalos }
20499512ac4SPeter Avalos 
binop2(arith_t a,int op,int precedence,int noeval)20502d0b1ceSMatthew Dillon static arith_t binop2(arith_t a, int op, int precedence, int noeval)
20699512ac4SPeter Avalos {
20799512ac4SPeter Avalos 	for (;;) {
20899512ac4SPeter Avalos 		union yystype val;
20999512ac4SPeter Avalos 		arith_t b;
21099512ac4SPeter Avalos 		int op2;
21199512ac4SPeter Avalos 		int token;
21299512ac4SPeter Avalos 
21399512ac4SPeter Avalos 		token = yylex();
21499512ac4SPeter Avalos 		val = yylval;
21599512ac4SPeter Avalos 
21699512ac4SPeter Avalos 		b = primary(token, &val, yylex(), noeval);
21799512ac4SPeter Avalos 
21899512ac4SPeter Avalos 		op2 = last_token;
21999512ac4SPeter Avalos 		if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX &&
22099512ac4SPeter Avalos 		    higher_prec(op2, op)) {
22199512ac4SPeter Avalos 			b = binop2(b, op2, arith_prec(op), noeval);
22299512ac4SPeter Avalos 			op2 = last_token;
22399512ac4SPeter Avalos 		}
22499512ac4SPeter Avalos 
22599512ac4SPeter Avalos 		a = noeval ? b : do_binop(op, a, b);
22699512ac4SPeter Avalos 
22799512ac4SPeter Avalos 		if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX ||
228cb26c088SPeter Avalos 		    arith_prec(op2) >= precedence)
22999512ac4SPeter Avalos 			return a;
23099512ac4SPeter Avalos 
23199512ac4SPeter Avalos 		op = op2;
23299512ac4SPeter Avalos 	}
23399512ac4SPeter Avalos }
23499512ac4SPeter Avalos 
binop(int token,union yystype * val,int op,int noeval)23502d0b1ceSMatthew Dillon static arith_t binop(int token, union yystype *val, int op, int noeval)
23699512ac4SPeter Avalos {
23799512ac4SPeter Avalos 	arith_t a = primary(token, val, op, noeval);
23899512ac4SPeter Avalos 
23999512ac4SPeter Avalos 	op = last_token;
24099512ac4SPeter Avalos 	if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX)
24199512ac4SPeter Avalos 		return a;
24299512ac4SPeter Avalos 
24399512ac4SPeter Avalos 	return binop2(a, op, ARITH_MAX_PREC, noeval);
24499512ac4SPeter Avalos }
24599512ac4SPeter Avalos 
and(int token,union yystype * val,int op,int noeval)24602d0b1ceSMatthew Dillon static arith_t and(int token, union yystype *val, int op, int noeval)
24799512ac4SPeter Avalos {
24899512ac4SPeter Avalos 	arith_t a = binop(token, val, op, noeval);
24999512ac4SPeter Avalos 	arith_t b;
25099512ac4SPeter Avalos 
25199512ac4SPeter Avalos 	op = last_token;
25299512ac4SPeter Avalos 	if (op != ARITH_AND)
25399512ac4SPeter Avalos 		return a;
25499512ac4SPeter Avalos 
25599512ac4SPeter Avalos 	token = yylex();
25699512ac4SPeter Avalos 	*val = yylval;
25799512ac4SPeter Avalos 
25899512ac4SPeter Avalos 	b = and(token, val, yylex(), noeval | !a);
25999512ac4SPeter Avalos 
26099512ac4SPeter Avalos 	return a && b;
26199512ac4SPeter Avalos }
26299512ac4SPeter Avalos 
or(int token,union yystype * val,int op,int noeval)26302d0b1ceSMatthew Dillon static arith_t or(int token, union yystype *val, int op, int noeval)
26499512ac4SPeter Avalos {
26599512ac4SPeter Avalos 	arith_t a = and(token, val, op, noeval);
26699512ac4SPeter Avalos 	arith_t b;
26799512ac4SPeter Avalos 
26899512ac4SPeter Avalos 	op = last_token;
26999512ac4SPeter Avalos 	if (op != ARITH_OR)
27099512ac4SPeter Avalos 		return a;
27199512ac4SPeter Avalos 
27299512ac4SPeter Avalos 	token = yylex();
27399512ac4SPeter Avalos 	*val = yylval;
27499512ac4SPeter Avalos 
27599512ac4SPeter Avalos 	b = or(token, val, yylex(), noeval | !!a);
27699512ac4SPeter Avalos 
27799512ac4SPeter Avalos 	return a || b;
27899512ac4SPeter Avalos }
27999512ac4SPeter Avalos 
cond(int token,union yystype * val,int op,int noeval)28002d0b1ceSMatthew Dillon static arith_t cond(int token, union yystype *val, int op, int noeval)
28199512ac4SPeter Avalos {
28299512ac4SPeter Avalos 	arith_t a = or(token, val, op, noeval);
28399512ac4SPeter Avalos 	arith_t b;
28499512ac4SPeter Avalos 	arith_t c;
28599512ac4SPeter Avalos 
28699512ac4SPeter Avalos 	if (last_token != ARITH_QMARK)
28799512ac4SPeter Avalos 		return a;
28899512ac4SPeter Avalos 
28999512ac4SPeter Avalos 	b = assignment(yylex(), noeval | !a);
29099512ac4SPeter Avalos 
29199512ac4SPeter Avalos 	if (last_token != ARITH_COLON)
29299512ac4SPeter Avalos 		yyerror("expecting ':'");
29399512ac4SPeter Avalos 
29499512ac4SPeter Avalos 	token = yylex();
29599512ac4SPeter Avalos 	*val = yylval;
29699512ac4SPeter Avalos 
29799512ac4SPeter Avalos 	c = cond(token, val, yylex(), noeval | !!a);
29899512ac4SPeter Avalos 
29999512ac4SPeter Avalos 	return a ? b : c;
30099512ac4SPeter Avalos }
30199512ac4SPeter Avalos 
assignment(int var,int noeval)30202d0b1ceSMatthew Dillon static arith_t assignment(int var, int noeval)
30399512ac4SPeter Avalos {
30499512ac4SPeter Avalos 	union yystype val = yylval;
30599512ac4SPeter Avalos 	int op = yylex();
30699512ac4SPeter Avalos 	arith_t result;
30799512ac4SPeter Avalos 	char sresult[DIGITS(result) + 1];
30899512ac4SPeter Avalos 
30999512ac4SPeter Avalos 	if (var != ARITH_VAR)
31099512ac4SPeter Avalos 		return cond(var, &val, op, noeval);
31199512ac4SPeter Avalos 
31299512ac4SPeter Avalos 	if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX))
31399512ac4SPeter Avalos 		return cond(var, &val, op, noeval);
31499512ac4SPeter Avalos 
31599512ac4SPeter Avalos 	result = assignment(yylex(), noeval);
31699512ac4SPeter Avalos 	if (noeval)
31799512ac4SPeter Avalos 		return result;
31899512ac4SPeter Avalos 
31999512ac4SPeter Avalos 	if (op != ARITH_ASS)
32099512ac4SPeter Avalos 		result = do_binop(op - 11, arith_lookupvarint(val.name), result);
32199512ac4SPeter Avalos 	snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result);
32299512ac4SPeter Avalos 	setvar(val.name, sresult, 0);
32399512ac4SPeter Avalos 	return result;
32499512ac4SPeter Avalos }
32599512ac4SPeter Avalos 
arith(const char * s)32602d0b1ceSMatthew Dillon arith_t arith(const char *s)
32799512ac4SPeter Avalos {
32899512ac4SPeter Avalos 	struct stackmark smark;
32999512ac4SPeter Avalos 	arith_t result;
33099512ac4SPeter Avalos 
33199512ac4SPeter Avalos 	setstackmark(&smark);
33299512ac4SPeter Avalos 
33399512ac4SPeter Avalos 	arith_buf = arith_startbuf = s;
33499512ac4SPeter Avalos 
33599512ac4SPeter Avalos 	result = assignment(yylex(), 0);
33699512ac4SPeter Avalos 
33799512ac4SPeter Avalos 	if (last_token)
33899512ac4SPeter Avalos 		yyerror("expecting EOF");
33999512ac4SPeter Avalos 
34099512ac4SPeter Avalos 	popstackmark(&smark);
34199512ac4SPeter Avalos 
34299512ac4SPeter Avalos 	return result;
34399512ac4SPeter Avalos }
34499512ac4SPeter Avalos 
34599512ac4SPeter Avalos /*
34699512ac4SPeter Avalos  *  The exp(1) builtin.
34799512ac4SPeter Avalos  */
34899512ac4SPeter Avalos int
letcmd(int argc,char ** argv)3492b2de9a9SPeter Avalos letcmd(int argc, char **argv)
35099512ac4SPeter Avalos {
35199512ac4SPeter Avalos 	const char *p;
35299512ac4SPeter Avalos 	char *concat;
35399512ac4SPeter Avalos 	char **ap;
35499512ac4SPeter Avalos 	arith_t i;
35599512ac4SPeter Avalos 
35699512ac4SPeter Avalos 	if (argc > 1) {
35799512ac4SPeter Avalos 		p = argv[1];
35899512ac4SPeter Avalos 		if (argc > 2) {
35999512ac4SPeter Avalos 			/*
36099512ac4SPeter Avalos 			 * Concatenate arguments.
36199512ac4SPeter Avalos 			 */
36299512ac4SPeter Avalos 			STARTSTACKSTR(concat);
36399512ac4SPeter Avalos 			ap = argv + 2;
36499512ac4SPeter Avalos 			for (;;) {
36599512ac4SPeter Avalos 				while (*p)
36699512ac4SPeter Avalos 					STPUTC(*p++, concat);
36799512ac4SPeter Avalos 				if ((p = *ap++) == NULL)
36899512ac4SPeter Avalos 					break;
36999512ac4SPeter Avalos 				STPUTC(' ', concat);
37099512ac4SPeter Avalos 			}
37199512ac4SPeter Avalos 			STPUTC('\0', concat);
37299512ac4SPeter Avalos 			p = grabstackstr(concat);
37399512ac4SPeter Avalos 		}
37499512ac4SPeter Avalos 	} else
37599512ac4SPeter Avalos 		p = "";
37699512ac4SPeter Avalos 
37799512ac4SPeter Avalos 	i = arith(p);
37899512ac4SPeter Avalos 
37999512ac4SPeter Avalos 	out1fmt(ARITH_FORMAT_STR "\n", i);
38099512ac4SPeter Avalos 	return !i;
38199512ac4SPeter Avalos }
382