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