Merge from vendor branch TCSH:
[dragonfly.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  * 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.
24  *
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.
36  *
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 $
40  */
41
42 #include <limits.h>
43 #include <stdio.h>
44
45 #include "arith.h"
46 #include "shell.h"
47 #include "var.h"
48 %}
49 %union {
50         arith_t l_value;
51         char* s_value;
52 }
53 %token <l_value> ARITH_NUM ARITH_LPAREN ARITH_RPAREN
54 %token <s_value> ARITH_VAR
55
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
73 %%
74
75 exp:
76         expr
77                 { return ($1); }
78         ;
79
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
116                 {
117                 if ($3 == 0)
118                         yyerror("division by zero");
119                 $$ = $1 / $3;
120                 } |
121         expr ARITH_REM expr
122                 {
123                 if ($3 == 0)
124                         yyerror("division by zero");
125                 $$ = $1 % $3;
126                 } |
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
137                 {
138                 char *p;
139                 arith_t arith_val;
140                 char *str_val;
141
142                 if (lookupvar($1) == NULL)
143                         setvarsafe($1, "0", 0);
144                 str_val = lookupvar($1);
145                 arith_val = strtoarith_t(str_val, &p, 0);
146                 /*
147                  * Conversion is successful only in case
148                  * we've converted _all_ characters.
149                  */
150                 if (*p != '\0')
151                         yyerror("variable conversion error");
152                 $$ = arith_val;
153                 } |
154         ARITH_VAR ARITH_ASSIGN expr
155                 {
156                 if (arith_assign($1, $3) != 0)
157                         yyerror("variable assignment error");
158                 $$ = $3;
159                 } |
160         ARITH_VAR ARITH_ADDASSIGN expr
161                 {
162                 arith_t value;
163
164                 value = atoarith_t(lookupvar($1)) + $3;
165                 if (arith_assign($1, value) != 0)
166                         yyerror("variable assignment error");
167                 $$ = value;
168                 } |
169         ARITH_VAR ARITH_SUBASSIGN expr
170                 {
171                 arith_t value;
172
173                 value = atoarith_t(lookupvar($1)) - $3;
174                 if (arith_assign($1, value) != 0)
175                         yyerror("variable assignment error");
176                 $$ = value;
177                 } |
178         ARITH_VAR ARITH_MULASSIGN expr
179                 {
180                 arith_t value;
181
182                 value = atoarith_t(lookupvar($1)) * $3;
183                 if (arith_assign($1, value) != 0)
184                         yyerror("variable assignment error");
185                 $$ = value;
186                 } |
187         ARITH_VAR ARITH_DIVASSIGN expr
188                 {
189                 arith_t value;
190
191                 if ($3 == 0)
192                         yyerror("division by zero");
193
194                 value = atoarith_t(lookupvar($1)) / $3;
195                 if (arith_assign($1, value) != 0)
196                         yyerror("variable assignment error");
197                 $$ = value;
198                 } |
199         ARITH_VAR ARITH_REMASSIGN expr
200                 {
201                 arith_t value;
202
203                 if ($3 == 0)
204                         yyerror("division by zero");
205
206                 value = atoarith_t(lookupvar($1)) % $3;
207                 if (arith_assign($1, value) != 0)
208                         yyerror("variable assignment error");
209                 $$ = value;
210                 } |
211         ARITH_VAR ARITH_RSHASSIGN expr
212                 {
213                 arith_t value;
214
215                 value = atoarith_t(lookupvar($1)) >> $3;
216                 if (arith_assign($1, value) != 0)
217                         yyerror("variable assignment error");
218                 $$ = value;
219                 } |
220         ARITH_VAR ARITH_LSHASSIGN expr
221                 {
222                 arith_t value;
223
224                 value = atoarith_t(lookupvar($1)) << $3;
225                 if (arith_assign($1, value) != 0)
226                         yyerror("variable assignment error");
227                 $$ = value;
228                 } |
229         ARITH_VAR ARITH_BANDASSIGN expr
230                 {
231                 arith_t value;
232
233                 value = atoarith_t(lookupvar($1)) & $3;
234                 if (arith_assign($1, value) != 0)
235                         yyerror("variable assignment error");
236                 $$ = value;
237                 } |
238         ARITH_VAR ARITH_BXORASSIGN expr
239                 {
240                 arith_t value;
241
242                 value = atoarith_t(lookupvar($1)) ^ $3;
243                 if (arith_assign($1, value) != 0)
244                         yyerror("variable assignment error");
245                 $$ = value;
246                 } |
247         ARITH_VAR ARITH_BORASSIGN expr
248                 {
249                 arith_t value;
250
251                 value = atoarith_t(lookupvar($1)) | $3;
252                 if (arith_assign($1, value) != 0)
253                         yyerror("variable assignment error");
254                 $$ = value;
255                 } ;
256 %%
257 #include "error.h"
258 #include "output.h"
259 #include "memalloc.h"
260
261 #define lstrlen(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3)
262
263 const char *arith_buf, *arith_startbuf;
264
265 int yylex(void);
266 int yyparse(void);
267 static void yyerror(const char *s);
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(const 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(const 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         const 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