]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - bin/sh/arith.y
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / bin / sh / arith.y
1 %{
2 /*-
3  * Copyright (c) 1993
4  *      The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Kenneth Almquist.
8  *
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  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #if 0
35 #ifndef lint
36 static char sccsid[] = "@(#)arith.y     8.3 (Berkeley) 5/4/95";
37 #endif
38 #endif /* not lint */
39
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD$");
42
43 #include <limits.h>
44 #include <stdio.h>
45
46 #include "arith.h"
47 #include "shell.h"
48 #include "var.h"
49 %}
50 %union {
51         arith_t l_value;
52         char* s_value;
53 }
54 %token <l_value> ARITH_NUM ARITH_LPAREN ARITH_RPAREN
55 %token <s_value> ARITH_VAR
56
57 %type <l_value> expr
58 %right ARITH_ASSIGN
59 %right ARITH_ADDASSIGN ARITH_SUBASSIGN
60 %right ARITH_MULASSIGN ARITH_DIVASSIGN ARITH_REMASSIGN
61 %right ARITH_RSHASSIGN ARITH_LSHASSIGN
62 %right ARITH_BANDASSIGN ARITH_BXORASSIGN ARITH_BORASSIGN
63 %left ARITH_OR
64 %left ARITH_AND
65 %left ARITH_BOR
66 %left ARITH_BXOR
67 %left ARITH_BAND
68 %left ARITH_EQ ARITH_NE
69 %left ARITH_LT ARITH_GT ARITH_GE ARITH_LE
70 %left ARITH_LSHIFT ARITH_RSHIFT
71 %left ARITH_ADD ARITH_SUB
72 %left ARITH_MUL ARITH_DIV ARITH_REM
73 %left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT
74 %%
75
76 exp:
77         expr
78                 {
79                 *YYPARSE_PARAM = $1;
80                 return (0);
81                 }
82         ;
83
84 expr:
85         ARITH_LPAREN expr ARITH_RPAREN
86                 { $$ = $2; } |
87         expr ARITH_OR expr
88                 { $$ = $1 ? $1 : $3 ? $3 : 0; } |
89         expr ARITH_AND expr
90                 { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; } |
91         expr ARITH_BOR expr
92                 { $$ = $1 | $3; } |
93         expr ARITH_BXOR expr
94                 { $$ = $1 ^ $3; } |
95         expr ARITH_BAND expr
96                 { $$ = $1 & $3; } |
97         expr ARITH_EQ expr
98                 { $$ = $1 == $3; } |
99         expr ARITH_GT expr
100                 { $$ = $1 > $3; } |
101         expr ARITH_GE expr
102                 { $$ = $1 >= $3; } |
103         expr ARITH_LT expr
104                 { $$ = $1 < $3; } |
105         expr ARITH_LE expr
106                 { $$ = $1 <= $3; } |
107         expr ARITH_NE expr
108                 { $$ = $1 != $3; } |
109         expr ARITH_LSHIFT expr
110                 { $$ = $1 << $3; } |
111         expr ARITH_RSHIFT expr
112                 { $$ = $1 >> $3; } |
113         expr ARITH_ADD expr
114                 { $$ = $1 + $3; } |
115         expr ARITH_SUB expr
116                 { $$ = $1 - $3; } |
117         expr ARITH_MUL expr
118                 { $$ = $1 * $3; } |
119         expr ARITH_DIV expr
120                 {
121                 if ($3 == 0)
122                         yyerror("division by zero");
123                 $$ = $1 / $3;
124                 } |
125         expr ARITH_REM expr
126                 {
127                 if ($3 == 0)
128                         yyerror("division by zero");
129                 $$ = $1 % $3;
130                 } |
131         ARITH_NOT expr
132                 { $$ = !($2); } |
133         ARITH_BNOT expr
134                 { $$ = ~($2); } |
135         ARITH_SUB expr %prec ARITH_UNARYMINUS
136                 { $$ = -($2); } |
137         ARITH_ADD expr %prec ARITH_UNARYPLUS
138                 { $$ = $2; } |
139         ARITH_NUM |
140         ARITH_VAR
141                 {
142                 char *p;
143                 arith_t arith_val;
144                 char *str_val;
145
146                 if (lookupvar($1) == NULL)
147                         setvarsafe($1, "0", 0);
148                 str_val = lookupvar($1);
149                 arith_val = strtoarith_t(str_val, &p, 0);
150                 /*
151                  * Conversion is successful only in case
152                  * we've converted _all_ characters.
153                  */
154                 if (*p != '\0')
155                         yyerror("variable conversion error");
156                 $$ = arith_val;
157                 } |
158         ARITH_VAR ARITH_ASSIGN expr
159                 {
160                 if (arith_assign($1, $3) != 0)
161                         yyerror("variable assignment error");
162                 $$ = $3;
163                 } |
164         ARITH_VAR ARITH_ADDASSIGN expr
165                 {
166                 arith_t value;
167
168                 value = atoarith_t(lookupvar($1)) + $3;
169                 if (arith_assign($1, value) != 0)
170                         yyerror("variable assignment error");
171                 $$ = value;
172                 } |
173         ARITH_VAR ARITH_SUBASSIGN expr
174                 {
175                 arith_t value;
176
177                 value = atoarith_t(lookupvar($1)) - $3;
178                 if (arith_assign($1, value) != 0)
179                         yyerror("variable assignment error");
180                 $$ = value;
181                 } |
182         ARITH_VAR ARITH_MULASSIGN expr
183                 {
184                 arith_t value;
185
186                 value = atoarith_t(lookupvar($1)) * $3;
187                 if (arith_assign($1, value) != 0)
188                         yyerror("variable assignment error");
189                 $$ = value;
190                 } |
191         ARITH_VAR ARITH_DIVASSIGN expr
192                 {
193                 arith_t value;
194
195                 if ($3 == 0)
196                         yyerror("division by zero");
197
198                 value = atoarith_t(lookupvar($1)) / $3;
199                 if (arith_assign($1, value) != 0)
200                         yyerror("variable assignment error");
201                 $$ = value;
202                 } |
203         ARITH_VAR ARITH_REMASSIGN expr
204                 {
205                 arith_t value;
206
207                 if ($3 == 0)
208                         yyerror("division by zero");
209
210                 value = atoarith_t(lookupvar($1)) % $3;
211                 if (arith_assign($1, value) != 0)
212                         yyerror("variable assignment error");
213                 $$ = value;
214                 } |
215         ARITH_VAR ARITH_RSHASSIGN expr
216                 {
217                 arith_t value;
218
219                 value = atoarith_t(lookupvar($1)) >> $3;
220                 if (arith_assign($1, value) != 0)
221                         yyerror("variable assignment error");
222                 $$ = value;
223                 } |
224         ARITH_VAR ARITH_LSHASSIGN expr
225                 {
226                 arith_t value;
227
228                 value = atoarith_t(lookupvar($1)) << $3;
229                 if (arith_assign($1, value) != 0)
230                         yyerror("variable assignment error");
231                 $$ = value;
232                 } |
233         ARITH_VAR ARITH_BANDASSIGN expr
234                 {
235                 arith_t value;
236
237                 value = atoarith_t(lookupvar($1)) & $3;
238                 if (arith_assign($1, value) != 0)
239                         yyerror("variable assignment error");
240                 $$ = value;
241                 } |
242         ARITH_VAR ARITH_BXORASSIGN expr
243                 {
244                 arith_t value;
245
246                 value = atoarith_t(lookupvar($1)) ^ $3;
247                 if (arith_assign($1, value) != 0)
248                         yyerror("variable assignment error");
249                 $$ = value;
250                 } |
251         ARITH_VAR ARITH_BORASSIGN expr
252                 {
253                 arith_t value;
254
255                 value = atoarith_t(lookupvar($1)) | $3;
256                 if (arith_assign($1, value) != 0)
257                         yyerror("variable assignment error");
258                 $$ = value;
259                 } ;
260 %%
261 #include "error.h"
262 #include "output.h"
263 #include "memalloc.h"
264
265 #define YYPARSE_PARAM_TYPE arith_t *
266 #define YYPARSE_PARAM result
267
268 char *arith_buf, *arith_startbuf;
269
270 int yylex(void);
271 int yyparse(YYPARSE_PARAM_TYPE);
272
273 static int
274 arith_assign(char *name, arith_t value)
275 {
276         char *str;
277         int ret;
278
279         str = (char *)ckmalloc(DIGITS(value));
280         sprintf(str, ARITH_FORMAT_STR, value);
281         ret = setvarsafe(name, str, 0);
282         free(str);
283         return ret;
284 }
285
286 arith_t
287 arith(char *s)
288 {
289         arith_t result;
290
291         arith_buf = arith_startbuf = s;
292
293         INTOFF;
294         yyparse(&result);
295         arith_lex_reset();      /* Reprime lex. */
296         INTON;
297
298         return result;
299 }
300
301 static void
302 yyerror(char *s)
303 {
304
305         yyerrok;
306         yyclearin;
307         arith_lex_reset();      /* Reprime lex. */
308         error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
309 }
310
311 /*
312  *  The exp(1) builtin.
313  */
314 int
315 expcmd(int argc, char **argv)
316 {
317         char *p;
318         char *concat;
319         char **ap;
320         arith_t i;
321
322         if (argc > 1) {
323                 p = argv[1];
324                 if (argc > 2) {
325                         /*
326                          * Concatenate arguments.
327                          */
328                         STARTSTACKSTR(concat);
329                         ap = argv + 2;
330                         for (;;) {
331                                 while (*p)
332                                         STPUTC(*p++, concat);
333                                 if ((p = *ap++) == NULL)
334                                         break;
335                                 STPUTC(' ', concat);
336                         }
337                         STPUTC('\0', concat);
338                         p = grabstackstr(concat);
339                 }
340         } else
341                 p = "";
342
343         i = arith(p);
344
345         out1fmt(ARITH_FORMAT_STR "\n", i);
346         return !i;
347 }
348
349 /*************************/
350 #ifdef TEST_ARITH
351 #include <stdio.h>
352 main(int argc, char *argv[])
353 {
354         printf("%d\n", exp(argv[1]));
355 }
356
357 error(char *s)
358 {
359         fprintf(stderr, "exp: %s\n", s);
360         exit(1);
361 }
362 #endif