xref: /titanic_52/usr/src/ucbcmd/expr/expr.y (revision 84ab085a13f931bc78e7415e7ce921dbaa14fcb3)
1 %{
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License, Version 1.0 only
7  * (the "License").  You may not use this file except in compliance
8  * with the License.
9  *
10  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11  * or http://www.opensolaris.org/os/licensing.
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 %}
24 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
25 /*	  All Rights Reserved	*/
26 
27 %{
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 %}
30 
31 /* Yacc productions for "expr" command: */
32 
33 %{
34 typedef	char *yystype;
35 #define	YYSTYPE	yystype
36 %}
37 
38 %token OR AND ADD SUBT MULT DIV REM EQ GT GEQ LT LEQ NEQ
39 %token A_STRING SUBSTR LENGTH INDEX NOARG MATCH
40 
41 /* operators listed below in increasing precedence: */
42 %left OR
43 %left AND
44 %left EQ LT GT GEQ LEQ NEQ
45 %left ADD SUBT
46 %left MULT DIV REM
47 %left MCH
48 %left MATCH
49 %left SUBSTR
50 %left LENGTH INDEX
51 %%
52 
53 /* a single `expression' is evaluated and printed: */
54 
55 expression:	expr NOARG = {
56 			printf("%s\n", $1);
57 			exit((!strcmp($1,"0")||!strcmp($1,"\0"))? 1: 0);
58 			}
59 	;
60 
61 
62 expr:	'(' expr ')' = { $$ = $2; }
63 	| expr OR expr   = { $$ = conj(OR, $1, $3); }
64 	| expr AND expr   = { $$ = conj(AND, $1, $3); }
65 	| expr EQ expr   = { $$ = rel(EQ, $1, $3); }
66 	| expr GT expr   = { $$ = rel(GT, $1, $3); }
67 	| expr GEQ expr   = { $$ = rel(GEQ, $1, $3); }
68 	| expr LT expr   = { $$ = rel(LT, $1, $3); }
69 	| expr LEQ expr   = { $$ = rel(LEQ, $1, $3); }
70 	| expr NEQ expr   = { $$ = rel(NEQ, $1, $3); }
71 	| expr ADD expr   = { $$ = arith(ADD, $1, $3); }
72 	| expr SUBT expr   = { $$ = arith(SUBT, $1, $3); }
73 	| expr MULT expr   = { $$ = arith(MULT, $1, $3); }
74 	| expr DIV expr   = { $$ = arith(DIV, $1, $3); }
75 	| expr REM expr   = { $$ = arith(REM, $1, $3); }
76 	| expr MCH expr	 = { $$ = match($1, $3); }
77 	| MATCH expr expr = { $$ = match($2, $3); }
78 	| SUBSTR expr expr expr = { $$ = substr($2, $3, $4); }
79 	| LENGTH expr       = { $$ = length($2); }
80 	| INDEX expr expr = { $$ = index($2, $3); }
81 	| A_STRING
82 	;
83 %%
84 
85 #define ESIZE	256
86 #define EQL(x,y) !strcmp(x,y)
87 
88 #define INIT	register char *sp = instring;
89 #define GETC()		(*sp++)
90 #define PEEKC()		(*sp)
91 #define UNGETC(c)	(--sp)
92 #define RETURN(c)	return
93 #define ERROR(c)	errxx(c)
94 #include  <regexp.h>
95 #include  <malloc.h>
96 
97 long atol();
98 char *ltoa(), *strcpy(), *strncpy();
99 void exit();
100 char	**Av;
101 int	Ac;
102 int	Argi;
103 
104 char Mstring[1][128];
105 
106 
107 char *operator[] = {
108 	"|", "&", "+", "-", "*", "/", "%", ":",
109 	"=", "==", "<", "<=", ">", ">=", "!=",
110 	"match", "substr", "length", "index", "\0" };
111 int op[] = {
112 	OR, AND, ADD,  SUBT, MULT, DIV, REM, MCH,
113 	EQ, EQ, LT, LEQ, GT, GEQ, NEQ,
114 	MATCH, SUBSTR, LENGTH, INDEX };
115 yylex() {
116 	register char *p;
117 	register i;
118 
119 	if(Argi >= Ac) return NOARG;
120 
121 	p = Av[Argi++];
122 
123 	if((*p == '(' || *p == ')') && p[1] == '\0' )
124 		return (int)*p;
125 	for(i = 0; *operator[i]; ++i)
126 		if(EQL(operator[i], p))
127 			return op[i];
128 
129 	yylval = p;
130 	return A_STRING;
131 }
132 
133 char *rel(oper, r1, r2) register char *r1, *r2;
134 {
135 	register long i;
136 
137 	if(ematch(r1, "-\\{0,1\\}[0-9]*$") && ematch(r2, "-\\{0,1\\}[0-9]*$"))
138 		i = atol(r1) - atol(r2);
139 	else
140 		i = strcmp(r1, r2);
141 	switch(oper) {
142 	case EQ:
143 		i = i==0;
144 		break;
145 	case GT:
146 		i = i>0;
147 		break;
148 	case GEQ:
149 		i = i>=0;
150 		break;
151 	case LT:
152 		i = i<0;
153 		break;
154 	case LEQ:
155 		i = i<=0;
156 		break;
157 	case NEQ:
158 		i = i!=0;
159 		break;
160 	}
161 	return i? "1": "0";
162 }
163 
164 char *arith(oper, r1, r2) char *r1, *r2;
165 {
166 	long i1, i2;
167 	register char *rv;
168 
169 	if(!(ematch(r1, "-\\{0,1\\}[0-9]*$") && ematch(r2, "-\\{0,1\\}[0-9]*$")))
170 		yyerror("non-numeric argument");
171 	i1 = atol(r1);
172 	i2 = atol(r2);
173 
174 	switch(oper) {
175 	case ADD:
176 		i1 = i1 + i2;
177 		break;
178 	case SUBT:
179 		i1 = i1 - i2;
180 		break;
181 	case MULT:
182 		i1 = i1 * i2;
183 		break;
184 	case DIV:
185 		if (i2 == 0)
186 			yyerror("division by zero");
187 		i1 = i1 / i2;
188 		break;
189 	case REM:
190 		if (i2 == 0)
191 			yyerror("division by zero");
192 		i1 = i1 % i2;
193 		break;
194 	}
195 	rv = malloc(16);
196 	(void) strcpy(rv, ltoa(i1));
197 	return rv;
198 }
199 char *conj(oper, r1, r2) char *r1, *r2;
200 {
201 	register char *rv;
202 
203 	switch(oper) {
204 
205 	case OR:
206 		if(EQL(r1, "0")
207 		    || EQL(r1, ""))
208 			if(EQL(r2, "0")
209 			    || EQL(r2, ""))
210 				rv = "0";
211 			else
212 				rv = r2;
213 		else
214 			rv = r1;
215 		break;
216 	case AND:
217 		if(EQL(r1, "0")
218 		    || EQL(r1, ""))
219 			rv = "0";
220 		else if(EQL(r2, "0")
221 		    || EQL(r2, ""))
222 			rv = "0";
223 		else
224 			rv = r1;
225 		break;
226 	}
227 	return rv;
228 }
229 
230 char *substr(v, s, w) char *v, *s, *w; {
231 register si, wi;
232 register char *res;
233 
234 	si = atol(s);
235 	wi = atol(w);
236 	while(--si) if(*v) ++v;
237 
238 	res = v;
239 
240 	while(wi--) if(*v) ++v;
241 
242 	*v = '\0';
243 	return res;
244 }
245 
246 char *index(s, t) char *s, *t; {
247 	register long i, j;
248 	register char *rv;
249 
250 	for(i = 0; s[i] ; ++i)
251 		for(j = 0; t[j] ; ++j)
252 			if(s[i]==t[j]) {
253 				(void) strcpy(rv = malloc(8), ltoa(++i));
254 				return rv;
255 			}
256 	return "0";
257 }
258 
259 char *length(s) register char *s; {
260 	register long i = 0;
261 	register char *rv;
262 
263 	while(*s++) ++i;
264 
265 	rv = malloc(8);
266 	(void) strcpy(rv, ltoa(i));
267 	return rv;
268 }
269 
270 char *match(s, p)
271 char *s, *p;
272 {
273 	register char *rv;
274 
275 	(void) strcpy(rv=malloc(8), ltoa((long)ematch(s, p)));
276 	if(nbra) {
277 		rv = malloc((unsigned) strlen(Mstring[0]) + 1);
278 		(void) strcpy(rv, Mstring[0]);
279 	}
280 	return rv;
281 }
282 
283 ematch(s, p)
284 char *s;
285 register char *p;
286 {
287 	static char expbuf[ESIZE];
288 	char *compile();
289 	register num;
290 	extern char *braslist[], *braelist[], *loc2;
291 
292 	compile(p, expbuf, &expbuf[ESIZE], 0);
293 	if(nbra > 1)
294 		yyerror("Too many '\\('s");
295 	if(advance(s, expbuf)) {
296 		if(nbra == 1) {
297 			p = braslist[0];
298 			num = braelist[0] - p;
299 			if ((num > 127) || (num < 0)) yyerror("Paren problem");
300 			(void) strncpy(Mstring[0], p, num);
301 			Mstring[0][num] = '\0';
302 		}
303 		return(loc2-s);
304 	}
305 	return(0);
306 }
307 
308 errxx(err)
309 register err;
310 {
311 	register char *message;
312 
313 	switch(err) {
314 		case 11:
315 			message = "Range endpoint too large";
316 			break;
317 		case 16:
318 			message = "Bad number";
319 			break;
320 		case 25:
321 			message = "``\\digit'' out of range";
322 			break;
323 		case 36:
324 			message = "Illegal or missing delimiter";
325 			break;
326 		case 41:
327 			message = "No remembered search string";
328 			break;
329 		case 42:
330 			message = "\\( \\) imbalance";
331 			break;
332 		case 43:
333 			message = "Too many \\(";
334 			break;
335 		case 44:
336 			message = "More than 2 numbers given in \\{ \\}";
337 			break;
338 		case 45:
339 			message = "} expected after \\";
340 			break;
341 		case 46:
342 			message = "First number exceeds second in \\{ \\}";
343 			break;
344 		case 49:
345 			message = "[ ] imbalance";
346 			break;
347 		case 50:
348 			message = "Regular expression too long";
349 			break;
350 		default:
351 			message = "Unknown regexp error code!!";
352 			break;
353 	}
354 	yyerror(message);
355 }
356 
357 yyerror(s)
358 char *s;
359 {
360 	(void) write(2, "expr: ", 6);
361 	(void) write(2, s, (unsigned) strlen(s));
362 	(void) write(2, "\n", 1);
363 	exit(2);
364 }
365 
366 char *ltoa(l)
367 long l;
368 {
369 	static char str[20];
370 	register char *sp;
371 	register i;
372 	register neg;
373 
374 	if(l == 0x80000000L)
375 		return "-2147483648";
376 	neg = 0;
377 	if(l < 0)
378 		++neg, l = -l;
379 	sp = &str[20];
380 	*--sp = '\0';
381 	do {
382 		i = l % 10;
383 		*--sp = '0' + i;
384 		l /= 10;
385 	}
386 	while(l);
387 	if(neg)
388 		*--sp = '-';
389 	return sp;
390 }
391 
392 main(argc, argv) char **argv;
393 {
394 	Ac = argc;
395 	Argi = 1;
396 	Av = argv;
397 	yyparse();
398 }
399