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