]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - bin/sh/arith.y
This commit was generated by cvs2svn to compensate for changes in r159609,
[FreeBSD/FreeBSD.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                 { return ($1); }
79         ;
80
81 expr:
82         ARITH_LPAREN expr ARITH_RPAREN
83                 { $$ = $2; } |
84         expr ARITH_OR expr
85                 { $$ = $1 ? $1 : $3 ? $3 : 0; } |
86         expr ARITH_AND expr
87                 { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; } |
88         expr ARITH_BOR expr
89                 { $$ = $1 | $3; } |
90         expr ARITH_BXOR expr
91                 { $$ = $1 ^ $3; } |
92         expr ARITH_BAND expr
93                 { $$ = $1 & $3; } |
94         expr ARITH_EQ expr
95                 { $$ = $1 == $3; } |
96         expr ARITH_GT expr
97                 { $$ = $1 > $3; } |
98         expr ARITH_GE expr
99                 { $$ = $1 >= $3; } |
100         expr ARITH_LT expr
101                 { $$ = $1 < $3; } |
102         expr ARITH_LE expr
103                 { $$ = $1 <= $3; } |
104         expr ARITH_NE expr
105                 { $$ = $1 != $3; } |
106         expr ARITH_LSHIFT expr
107                 { $$ = $1 << $3; } |
108         expr ARITH_RSHIFT expr
109                 { $$ = $1 >> $3; } |
110         expr ARITH_ADD expr
111                 { $$ = $1 + $3; } |
112         expr ARITH_SUB expr
113                 { $$ = $1 - $3; } |
114         expr ARITH_MUL expr
115                 { $$ = $1 * $3; } |
116         expr ARITH_DIV expr
117                 {
118                 if ($3 == 0)
119                         yyerror("division by zero");
120                 $$ = $1 / $3;
121                 } |
122         expr ARITH_REM expr
123                 {
124                 if ($3 == 0)
125                         yyerror("division by zero");
126                 $$ = $1 % $3;
127                 } |
128         ARITH_NOT expr
129                 { $$ = !($2); } |
130         ARITH_BNOT expr
131                 { $$ = ~($2); } |
132         ARITH_SUB expr %prec ARITH_UNARYMINUS
133                 { $$ = -($2); } |
134         ARITH_ADD expr %prec ARITH_UNARYPLUS
135                 { $$ = $2; } |
136         ARITH_NUM |
137         ARITH_VAR
138                 {
139                 char *p;
140                 arith_t arith_val;
141                 char *str_val;
142
143                 if (lookupvar($1) == NULL)
144                         setvarsafe($1, "0", 0);
145                 str_val = lookupvar($1);
146                 arith_val = strtoarith_t(str_val, &p, 0);
147                 /*
148                  * Conversion is successful only in case
149                  * we've converted _all_ characters.
150                  */
151                 if (*p != '\0')
152                         yyerror("variable conversion error");
153                 $$ = arith_val;
154                 } |
155         ARITH_VAR ARITH_ASSIGN expr
156                 {
157                 if (arith_assign($1, $3) != 0)
158                         yyerror("variable assignment error");
159                 $$ = $3;
160                 } |
161         ARITH_VAR ARITH_ADDASSIGN expr
162                 {
163                 arith_t value;
164
165                 value = atoarith_t(lookupvar($1)) + $3;
166                 if (arith_assign($1, value) != 0)
167                         yyerror("variable assignment error");
168                 $$ = value;
169                 } |
170         ARITH_VAR ARITH_SUBASSIGN expr
171                 {
172                 arith_t value;
173
174                 value = atoarith_t(lookupvar($1)) - $3;
175                 if (arith_assign($1, value) != 0)
176                         yyerror("variable assignment error");
177                 $$ = value;
178                 } |
179         ARITH_VAR ARITH_MULASSIGN expr
180                 {
181                 arith_t value;
182
183                 value = atoarith_t(lookupvar($1)) * $3;
184                 if (arith_assign($1, value) != 0)
185                         yyerror("variable assignment error");
186                 $$ = value;
187                 } |
188         ARITH_VAR ARITH_DIVASSIGN expr
189                 {
190                 arith_t value;
191
192                 if ($3 == 0)
193                         yyerror("division by zero");
194
195                 value = atoarith_t(lookupvar($1)) / $3;
196                 if (arith_assign($1, value) != 0)
197                         yyerror("variable assignment error");
198                 $$ = value;
199                 } |
200         ARITH_VAR ARITH_REMASSIGN expr
201                 {
202                 arith_t value;
203
204                 if ($3 == 0)
205                         yyerror("division by zero");
206
207                 value = atoarith_t(lookupvar($1)) % $3;
208                 if (arith_assign($1, value) != 0)
209                         yyerror("variable assignment error");
210                 $$ = value;
211                 } |
212         ARITH_VAR ARITH_RSHASSIGN expr
213                 {
214                 arith_t value;
215
216                 value = atoarith_t(lookupvar($1)) >> $3;
217                 if (arith_assign($1, value) != 0)
218                         yyerror("variable assignment error");
219                 $$ = value;
220                 } |
221         ARITH_VAR ARITH_LSHASSIGN expr
222                 {
223                 arith_t value;
224
225                 value = atoarith_t(lookupvar($1)) << $3;
226                 if (arith_assign($1, value) != 0)
227                         yyerror("variable assignment error");
228                 $$ = value;
229                 } |
230         ARITH_VAR ARITH_BANDASSIGN expr
231                 {
232                 arith_t value;
233
234                 value = atoarith_t(lookupvar($1)) & $3;
235                 if (arith_assign($1, value) != 0)
236                         yyerror("variable assignment error");
237                 $$ = value;
238                 } |
239         ARITH_VAR ARITH_BXORASSIGN expr
240                 {
241                 arith_t value;
242
243                 value = atoarith_t(lookupvar($1)) ^ $3;
244                 if (arith_assign($1, value) != 0)
245                         yyerror("variable assignment error");
246                 $$ = value;
247                 } |
248         ARITH_VAR ARITH_BORASSIGN expr
249                 {
250                 arith_t value;
251
252                 value = atoarith_t(lookupvar($1)) | $3;
253                 if (arith_assign($1, value) != 0)
254                         yyerror("variable assignment error");
255                 $$ = value;
256                 } ;
257 %%
258 #include "error.h"
259 #include "output.h"
260 #include "memalloc.h"
261
262 #define lstrlen(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3)
263
264 char *arith_buf, *arith_startbuf;
265
266 int yylex(void);
267 int yyparse(void);
268
269 static int
270 arith_assign(char *name, arith_t value)
271 {
272         char *str;
273         int ret;
274
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;
280 }
281
282 int
283 arith(char *s)
284 {
285         long result;
286
287         arith_buf = arith_startbuf = s;
288
289         INTOFF;
290         result = yyparse();
291         arith_lex_reset();      /* Reprime lex. */
292         INTON;
293
294         return result;
295 }
296
297 static void
298 yyerror(char *s)
299 {
300
301         yyerrok;
302         yyclearin;
303         arith_lex_reset();      /* Reprime lex. */
304         error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
305 }
306
307 /*
308  *  The exp(1) builtin.
309  */
310 int
311 expcmd(int argc, char **argv)
312 {
313         char *p;
314         char *concat;
315         char **ap;
316         long i;
317
318         if (argc > 1) {
319                 p = argv[1];
320                 if (argc > 2) {
321                         /*
322                          * Concatenate arguments.
323                          */
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);
332                         }
333                         STPUTC('\0', concat);
334                         p = grabstackstr(concat);
335                 }
336         } else
337                 p = "";
338
339         i = arith(p);
340
341         out1fmt("%ld\n", i);
342         return !i;
343 }
344
345 /*************************/
346 #ifdef TEST_ARITH
347 #include <stdio.h>
348 main(int argc, char *argv[])
349 {
350         printf("%d\n", exp(argv[1]));
351 }
352
353 error(char *s)
354 {
355         fprintf(stderr, "exp: %s\n", s);
356         exit(1);
357 }
358 #endif