3 * The Regents of the University of California. All rights reserved.
5 * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
44 #include "arith_yacc.h"
53 #if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
54 #error Arithmetic tokens are out of order.
57 static const char *arith_startbuf
;
59 const char *arith_buf
;
62 static int last_token
;
64 #define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec
66 static 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),
85 #define ARITH_MAX_PREC 8
87 int letcmd(int, char **);
89 static __dead2
void yyerror(const char *s
)
91 error("arithmetic expression: %s: \"%s\"", s
, arith_startbuf
);
95 static arith_t
arith_lookupvarint(char *varname
)
101 str
= lookupvar(varname
);
102 if (uflag
&& str
== NULL
)
103 yyerror("variable not set");
104 if (str
== NULL
|| *str
== '\0')
107 result
= strtoarith_t(str
, &p
, 0);
108 if (errno
!= 0 || *p
!= '\0')
109 yyerror("variable conversion error");
113 static inline int arith_prec(int op
)
115 return prec
[op
- ARITH_BINOP_MIN
];
118 static inline int higher_prec(int op1
, int op2
)
120 return arith_prec(op1
) < arith_prec(op2
);
123 static arith_t
do_binop(int op
, arith_t a
, arith_t b
)
131 yyerror("division by zero");
132 if (a
== ARITH_MIN
&& b
== -1)
133 yyerror("divide error");
134 return op
== ARITH_REM
? a
% b
: a
/ b
;
136 return (uintmax_t)a
* (uintmax_t)b
;
138 return (uintmax_t)a
+ (uintmax_t)b
;
140 return (uintmax_t)a
- (uintmax_t)b
;
142 return (uintmax_t)a
<< (b
& (sizeof(uintmax_t) * CHAR_BIT
- 1));
144 return a
>> (b
& (sizeof(uintmax_t) * CHAR_BIT
- 1));
166 static arith_t
assignment(int var
, int noeval
);
168 static arith_t
primary(int token
, union yystype
*val
, int op
, int noeval
)
175 result
= assignment(op
, noeval
);
176 if (last_token
!= ARITH_RPAREN
)
177 yyerror("expecting ')'");
178 last_token
= yylex();
185 return noeval
? val
->val
: arith_lookupvarint(val
->name
);
193 return -primary(op
, val
, yylex(), noeval
);
196 return !primary(op
, val
, yylex(), noeval
);
199 return ~primary(op
, val
, yylex(), noeval
);
201 yyerror("expecting primary");
205 static arith_t
binop2(arith_t a
, int op
, int precedence
, int noeval
)
216 b
= primary(token
, &val
, yylex(), noeval
);
219 if (op2
>= ARITH_BINOP_MIN
&& op2
< ARITH_BINOP_MAX
&&
220 higher_prec(op2
, op
)) {
221 b
= binop2(b
, op2
, arith_prec(op
), noeval
);
225 a
= noeval
? b
: do_binop(op
, a
, b
);
227 if (op2
< ARITH_BINOP_MIN
|| op2
>= ARITH_BINOP_MAX
||
228 arith_prec(op2
) >= precedence
)
235 static arith_t
binop(int token
, union yystype
*val
, int op
, int noeval
)
237 arith_t a
= primary(token
, val
, op
, noeval
);
240 if (op
< ARITH_BINOP_MIN
|| op
>= ARITH_BINOP_MAX
)
243 return binop2(a
, op
, ARITH_MAX_PREC
, noeval
);
246 static arith_t
and(int token
, union yystype
*val
, int op
, int noeval
)
248 arith_t a
= binop(token
, val
, op
, noeval
);
258 b
= and(token
, val
, yylex(), noeval
| !a
);
263 static arith_t
or(int token
, union yystype
*val
, int op
, int noeval
)
265 arith_t a
= and(token
, val
, op
, noeval
);
275 b
= or(token
, val
, yylex(), noeval
| !!a
);
280 static arith_t
cond(int token
, union yystype
*val
, int op
, int noeval
)
282 arith_t a
= or(token
, val
, op
, noeval
);
286 if (last_token
!= ARITH_QMARK
)
289 b
= assignment(yylex(), noeval
| !a
);
291 if (last_token
!= ARITH_COLON
)
292 yyerror("expecting ':'");
297 c
= cond(token
, val
, yylex(), noeval
| !!a
);
302 static arith_t
assignment(int var
, int noeval
)
304 union yystype val
= yylval
;
307 char sresult
[DIGITS(result
) + 1];
309 if (var
!= ARITH_VAR
)
310 return cond(var
, &val
, op
, noeval
);
312 if (op
!= ARITH_ASS
&& (op
< ARITH_ASS_MIN
|| op
>= ARITH_ASS_MAX
))
313 return cond(var
, &val
, op
, noeval
);
315 result
= assignment(yylex(), noeval
);
320 result
= do_binop(op
- 11, arith_lookupvarint(val
.name
), result
);
321 snprintf(sresult
, sizeof(sresult
), ARITH_FORMAT_STR
, result
);
322 setvar(val
.name
, sresult
, 0);
326 arith_t
arith(const char *s
)
328 struct stackmark smark
;
331 setstackmark(&smark
);
333 arith_buf
= arith_startbuf
= s
;
335 result
= assignment(yylex(), 0);
338 yyerror("expecting EOF");
340 popstackmark(&smark
);
346 * The exp(1) builtin.
349 letcmd(int argc
, char **argv
)
360 * Concatenate arguments.
362 STARTSTACKSTR(concat
);
366 STPUTC(*p
++, concat
);
367 if ((p
= *ap
++) == NULL
)
371 STPUTC('\0', concat
);
372 p
= grabstackstr(concat
);
379 out1fmt(ARITH_FORMAT_STR
"\n", i
);