Resync patch with contrib.
[dragonfly.git] / bin / sh / arith.y
bloba245ecc8627011dd23ad1005b15f387ead4dc09e
1 %{
2 /*-
3 * Copyright (c) 1993
4 * The Regents of the University of California. All rights reserved.
6 * This code is derived from software contributed to Berkeley by
7 * Kenneth Almquist.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Berkeley and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
37 * @(#)arith.y 8.3 (Berkeley) 5/4/95
38 * $FreeBSD: src/bin/sh/arith.y,v 1.21 2005/08/13 07:59:46 stefanf Exp $
39 * $DragonFly: src/bin/sh/arith.y,v 1.5 2007/01/04 14:06:21 pavalos Exp $
42 #include <limits.h>
43 #include <stdio.h>
45 #include "arith.h"
46 #include "shell.h"
47 #include "var.h"
49 %union {
50 arith_t l_value;
51 char* s_value;
53 %token <l_value> ARITH_NUM ARITH_LPAREN ARITH_RPAREN
54 %token <s_value> ARITH_VAR
56 %type <l_value> expr
57 %right ARITH_ASSIGN
58 %right ARITH_ADDASSIGN ARITH_SUBASSIGN
59 %right ARITH_MULASSIGN ARITH_DIVASSIGN ARITH_REMASSIGN
60 %right ARITH_RSHASSIGN ARITH_LSHASSIGN
61 %right ARITH_BANDASSIGN ARITH_BXORASSIGN ARITH_BORASSIGN
62 %left ARITH_OR
63 %left ARITH_AND
64 %left ARITH_BOR
65 %left ARITH_BXOR
66 %left ARITH_BAND
67 %left ARITH_EQ ARITH_NE
68 %left ARITH_LT ARITH_GT ARITH_GE ARITH_LE
69 %left ARITH_LSHIFT ARITH_RSHIFT
70 %left ARITH_ADD ARITH_SUB
71 %left ARITH_MUL ARITH_DIV ARITH_REM
72 %left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT
75 exp:
76 expr
77 { return ($1); }
80 expr:
81 ARITH_LPAREN expr ARITH_RPAREN
82 { $$ = $2; } |
83 expr ARITH_OR expr
84 { $$ = $1 ? $1 : $3 ? $3 : 0; } |
85 expr ARITH_AND expr
86 { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; } |
87 expr ARITH_BOR expr
88 { $$ = $1 | $3; } |
89 expr ARITH_BXOR expr
90 { $$ = $1 ^ $3; } |
91 expr ARITH_BAND expr
92 { $$ = $1 & $3; } |
93 expr ARITH_EQ expr
94 { $$ = $1 == $3; } |
95 expr ARITH_GT expr
96 { $$ = $1 > $3; } |
97 expr ARITH_GE expr
98 { $$ = $1 >= $3; } |
99 expr ARITH_LT expr
100 { $$ = $1 < $3; } |
101 expr ARITH_LE expr
102 { $$ = $1 <= $3; } |
103 expr ARITH_NE expr
104 { $$ = $1 != $3; } |
105 expr ARITH_LSHIFT expr
106 { $$ = $1 << $3; } |
107 expr ARITH_RSHIFT expr
108 { $$ = $1 >> $3; } |
109 expr ARITH_ADD expr
110 { $$ = $1 + $3; } |
111 expr ARITH_SUB expr
112 { $$ = $1 - $3; } |
113 expr ARITH_MUL expr
114 { $$ = $1 * $3; } |
115 expr ARITH_DIV expr
117 if ($3 == 0)
118 yyerror("division by zero");
119 $$ = $1 / $3;
121 expr ARITH_REM expr
123 if ($3 == 0)
124 yyerror("division by zero");
125 $$ = $1 % $3;
127 ARITH_NOT expr
128 { $$ = !($2); } |
129 ARITH_BNOT expr
130 { $$ = ~($2); } |
131 ARITH_SUB expr %prec ARITH_UNARYMINUS
132 { $$ = -($2); } |
133 ARITH_ADD expr %prec ARITH_UNARYPLUS
134 { $$ = $2; } |
135 ARITH_NUM |
136 ARITH_VAR
138 char *p;
139 arith_t arith_val;
140 char *str_val;
142 if (lookupvar($1) == NULL)
143 setvarsafe($1, "0", 0);
144 str_val = lookupvar($1);
145 arith_val = strtoarith_t(str_val, &p, 0);
147 * Conversion is successful only in case
148 * we've converted _all_ characters.
150 if (*p != '\0')
151 yyerror("variable conversion error");
152 $$ = arith_val;
154 ARITH_VAR ARITH_ASSIGN expr
156 if (arith_assign($1, $3) != 0)
157 yyerror("variable assignment error");
158 $$ = $3;
160 ARITH_VAR ARITH_ADDASSIGN expr
162 arith_t value;
164 value = atoarith_t(lookupvar($1)) + $3;
165 if (arith_assign($1, value) != 0)
166 yyerror("variable assignment error");
167 $$ = value;
169 ARITH_VAR ARITH_SUBASSIGN expr
171 arith_t value;
173 value = atoarith_t(lookupvar($1)) - $3;
174 if (arith_assign($1, value) != 0)
175 yyerror("variable assignment error");
176 $$ = value;
178 ARITH_VAR ARITH_MULASSIGN expr
180 arith_t value;
182 value = atoarith_t(lookupvar($1)) * $3;
183 if (arith_assign($1, value) != 0)
184 yyerror("variable assignment error");
185 $$ = value;
187 ARITH_VAR ARITH_DIVASSIGN expr
189 arith_t value;
191 if ($3 == 0)
192 yyerror("division by zero");
194 value = atoarith_t(lookupvar($1)) / $3;
195 if (arith_assign($1, value) != 0)
196 yyerror("variable assignment error");
197 $$ = value;
199 ARITH_VAR ARITH_REMASSIGN expr
201 arith_t value;
203 if ($3 == 0)
204 yyerror("division by zero");
206 value = atoarith_t(lookupvar($1)) % $3;
207 if (arith_assign($1, value) != 0)
208 yyerror("variable assignment error");
209 $$ = value;
211 ARITH_VAR ARITH_RSHASSIGN expr
213 arith_t value;
215 value = atoarith_t(lookupvar($1)) >> $3;
216 if (arith_assign($1, value) != 0)
217 yyerror("variable assignment error");
218 $$ = value;
220 ARITH_VAR ARITH_LSHASSIGN expr
222 arith_t value;
224 value = atoarith_t(lookupvar($1)) << $3;
225 if (arith_assign($1, value) != 0)
226 yyerror("variable assignment error");
227 $$ = value;
229 ARITH_VAR ARITH_BANDASSIGN expr
231 arith_t value;
233 value = atoarith_t(lookupvar($1)) & $3;
234 if (arith_assign($1, value) != 0)
235 yyerror("variable assignment error");
236 $$ = value;
238 ARITH_VAR ARITH_BXORASSIGN expr
240 arith_t value;
242 value = atoarith_t(lookupvar($1)) ^ $3;
243 if (arith_assign($1, value) != 0)
244 yyerror("variable assignment error");
245 $$ = value;
247 ARITH_VAR ARITH_BORASSIGN expr
249 arith_t value;
251 value = atoarith_t(lookupvar($1)) | $3;
252 if (arith_assign($1, value) != 0)
253 yyerror("variable assignment error");
254 $$ = value;
257 #include "error.h"
258 #include "output.h"
259 #include "memalloc.h"
261 #define lstrlen(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3)
263 const char *arith_buf, *arith_startbuf;
265 int yylex(void);
266 int yyparse(void);
267 static void yyerror(const char *s);
269 static int
270 arith_assign(char *name, arith_t value)
272 char *str;
273 int ret;
275 str = (char *)ckmalloc(lstrlen(value));
276 sprintf(str, ARITH_FORMAT_STR, value);
277 ret = setvarsafe(name, str, 0);
278 free(str);
279 return (ret);
283 arith(const char *s)
285 long result;
287 arith_buf = arith_startbuf = s;
289 INTOFF;
290 result = yyparse();
291 arith_lex_reset(); /* Reprime lex. */
292 INTON;
294 return (result);
297 static void
298 yyerror(const char *s)
301 yyerrok;
302 yyclearin;
303 arith_lex_reset(); /* Reprime lex. */
304 error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
308 * The exp(1) builtin.
311 expcmd(int argc, char **argv)
313 const char *p;
314 char *concat;
315 char **ap;
316 long i;
318 if (argc > 1) {
319 p = argv[1];
320 if (argc > 2) {
322 * Concatenate arguments.
324 STARTSTACKSTR(concat);
325 ap = argv + 2;
326 for (;;) {
327 while (*p)
328 STPUTC(*p++, concat);
329 if ((p = *ap++) == NULL)
330 break;
331 STPUTC(' ', concat);
333 STPUTC('\0', concat);
334 p = grabstackstr(concat);
336 } else
337 p = "";
339 i = arith(p);
341 out1fmt("%ld\n", i);
342 return (! i);
345 /*************************/
346 #ifdef TEST_ARITH
347 #include <stdio.h>
348 main(int argc, char *argv[])
350 printf("%d\n", exp(argv[1]));
353 error(char *s)
355 fprintf(stderr, "exp: %s\n", s);
356 exit(1);
358 #endif