xref: /minix/bin/sh/arith.y (revision 9f988b79)
1 %{
2 /*	$NetBSD: arith.y,v 1.22 2012/03/20 18:42:29 matt Exp $	*/
3 
4 /*-
5  * Copyright (c) 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Kenneth Almquist.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)arith.y	8.3 (Berkeley) 5/4/95";
40 #else
41 __RCSID("$NetBSD: arith.y,v 1.22 2012/03/20 18:42:29 matt Exp $");
42 #endif
43 #endif /* not lint */
44 
45 #include <stdlib.h>
46 #include "expand.h"
47 #include "builtins.h"
48 #include "shell.h"
49 #include "error.h"
50 #include "output.h"
51 #include "memalloc.h"
52 
53 typedef intmax_t YYSTYPE;
54 #define YYSTYPE YYSTYPE
55 
56 intmax_t arith_result;
57 const char *arith_buf, *arith_startbuf;
58 
59 __dead static void yyerror(const char *);
60 #ifdef TESTARITH
61 int main(int , char *[]);
62 int error(char *);
63 #endif
64 
65 %}
66 %token ARITH_NUM ARITH_LPAREN ARITH_RPAREN
67 
68 %left ARITH_OR
69 %left ARITH_AND
70 %left ARITH_BOR
71 %left ARITH_BXOR
72 %left ARITH_BAND
73 %left ARITH_EQ ARITH_NE
74 %left ARITH_LT ARITH_GT ARITH_GE ARITH_LE
75 %left ARITH_LSHIFT ARITH_RSHIFT
76 %left ARITH_ADD ARITH_SUB
77 %left ARITH_MUL ARITH_DIV ARITH_REM
78 %left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT
79 %%
80 
81 exp:	expr {
82 			/*
83 			 * yyparse() returns int, so we have to save
84 			 * the desired result elsewhere.
85 			 */
86 			arith_result = $1;
87 		}
88 	;
89 
90 
91 expr:	ARITH_LPAREN expr ARITH_RPAREN { $$ = $2; }
92 	| expr ARITH_OR expr	{ $$ = $1 ? $1 : $3 ? $3 : 0; }
93 	| expr ARITH_AND expr	{ $$ = $1 ? ( $3 ? $3 : 0 ) : 0; }
94 	| expr ARITH_BOR expr	{ $$ = $1 | $3; }
95 	| expr ARITH_BXOR expr	{ $$ = $1 ^ $3; }
96 	| expr ARITH_BAND expr	{ $$ = $1 & $3; }
97 	| expr ARITH_EQ expr	{ $$ = $1 == $3; }
98 	| expr ARITH_GT expr	{ $$ = $1 > $3; }
99 	| expr ARITH_GE expr	{ $$ = $1 >= $3; }
100 	| expr ARITH_LT expr	{ $$ = $1 < $3; }
101 	| expr ARITH_LE expr	{ $$ = $1 <= $3; }
102 	| expr ARITH_NE expr	{ $$ = $1 != $3; }
103 	| expr ARITH_LSHIFT expr { $$ = $1 << $3; }
104 	| expr ARITH_RSHIFT expr { $$ = $1 >> $3; }
105 	| expr ARITH_ADD expr	{ $$ = $1 + $3; }
106 	| expr ARITH_SUB expr	{ $$ = $1 - $3; }
107 	| expr ARITH_MUL expr	{ $$ = $1 * $3; }
108 	| expr ARITH_DIV expr	{
109 			if ($3 == 0)
110 				yyerror("division by zero");
111 			$$ = $1 / $3;
112 			}
113 	| expr ARITH_REM expr   {
114 			if ($3 == 0)
115 				yyerror("division by zero");
116 			$$ = $1 % $3;
117 			}
118 	| ARITH_NOT expr	{ $$ = !($2); }
119 	| ARITH_BNOT expr	{ $$ = ~($2); }
120 	| ARITH_SUB expr %prec ARITH_UNARYMINUS { $$ = -($2); }
121 	| ARITH_ADD expr %prec ARITH_UNARYPLUS { $$ = $2; }
122 	| ARITH_NUM
123 	;
124 %%
125 intmax_t
126 arith(const char *s)
127 {
128 	intmax_t result;
129 
130 	arith_buf = arith_startbuf = s;
131 
132 	INTOFF;
133 	(void) yyparse();
134 	result = arith_result;
135 	arith_lex_reset();	/* reprime lex */
136 	INTON;
137 
138 	return (result);
139 }
140 
141 
142 /*
143  *  The exp(1) builtin.
144  */
145 int
146 expcmd(int argc, char **argv)
147 {
148 	const char *p;
149 	char *concat;
150 	char **ap;
151 	intmax_t i;
152 
153 	if (argc > 1) {
154 		p = argv[1];
155 		if (argc > 2) {
156 			/*
157 			 * concatenate arguments
158 			 */
159 			STARTSTACKSTR(concat);
160 			ap = argv + 2;
161 			for (;;) {
162 				while (*p)
163 					STPUTC(*p++, concat);
164 				if ((p = *ap++) == NULL)
165 					break;
166 				STPUTC(' ', concat);
167 			}
168 			STPUTC('\0', concat);
169 			p = grabstackstr(concat);
170 		}
171 	} else
172 		p = "";
173 
174 	(void)arith(p);
175 	i = arith_result;
176 
177 	out1fmt("%"PRIdMAX"\n", i);
178 	return (! i);
179 }
180 
181 /*************************/
182 #ifdef TEST_ARITH
183 #include <stdio.h>
184 main(argc, argv)
185 	char *argv[];
186 {
187 	printf("%"PRIdMAX"\n", exp(argv[1]));
188 }
189 error(s)
190 	char *s;
191 {
192 	fprintf(stderr, "exp: %s\n", s);
193 	exit(1);
194 }
195 #endif
196 
197 static void
198 yyerror(const char *s)
199 {
200 
201 	yyerrok;
202 	yyclearin;
203 	arith_lex_reset();	/* reprime lex */
204 	error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
205 	/* NOTREACHED */
206 }
207