xref: /original-bsd/bin/expr/expr.y (revision 89a39cb6)
1 /* Yacc productions for "expr" command: */
2 %{
3 typedef char *yystype;
4 #define	YYSTYPE yystype
5 %}
6 
7 %token OR AND ADD SUBT MULT DIV REM EQ GT GEQ LT LEQ NEQ
8 %token A_STRING SUBSTR LENGTH INDEX NOARG MATCH
9 
10 /* operators listed below in increasing precedence: */
11 %left OR
12 %left AND
13 %left EQ LT GT GEQ LEQ NEQ
14 %left ADD SUBT
15 %left MULT DIV REM
16 %left MCH
17 %left MATCH
18 %left SUBSTR
19 %left LENGTH INDEX
20 %%
21 
22 /* a single `expression' is evaluated and printed: */
23 
24 expression:	expr NOARG = {
25 			printf("%s\n", $1);
26 			exit((!strcmp($1,"0")||!strcmp($1,"\0"))? 1: 0);
27 			}
28 	;
29 
30 
31 expr:	'(' expr ')' = { $$ = $2; }
32 	| expr OR expr   = { $$ = conj(OR, $1, $3); }
33 	| expr AND expr   = { $$ = conj(AND, $1, $3); }
34 	| expr EQ expr   = { $$ = rel(EQ, $1, $3); }
35 	| expr GT expr   = { $$ = rel(GT, $1, $3); }
36 	| expr GEQ expr   = { $$ = rel(GEQ, $1, $3); }
37 	| expr LT expr   = { $$ = rel(LT, $1, $3); }
38 	| expr LEQ expr   = { $$ = rel(LEQ, $1, $3); }
39 	| expr NEQ expr   = { $$ = rel(NEQ, $1, $3); }
40 	| expr ADD expr   = { $$ = arith(ADD, $1, $3); }
41 	| expr SUBT expr   = { $$ = arith(SUBT, $1, $3); }
42 	| expr MULT expr   = { $$ = arith(MULT, $1, $3); }
43 	| expr DIV expr   = { $$ = arith(DIV, $1, $3); }
44 	| expr REM expr   = { $$ = arith(REM, $1, $3); }
45 	| expr MCH expr	 = { $$ = match($1, $3); }
46 	| MATCH expr expr = { $$ = match($2, $3); }
47 	| SUBSTR expr expr expr = { $$ = substr($2, $3, $4); }
48 	| LENGTH expr       = { $$ = length($2); }
49 	| INDEX expr expr = { $$ = index($2, $3); }
50 	| A_STRING
51 	;
52 %%
53 /*	expression command */
54 #include <stdio.h>
55 #define ESIZE	256
56 #define error(c)	errxx(c)
57 #define EQL(x,y) !strcmp(x,y)
58 long atol();
59 char	**Av;
60 int	Ac;
61 int	Argi;
62 
63 char Mstring[1][128];
64 char *malloc();
65 extern int nbra;
66 
67 main(argc, argv) char **argv; {
68 	Ac = argc;
69 	Argi = 1;
70 	Av = argv;
71 	yyparse();
72 }
73 
74 char *operators[] = { "|", "&", "+", "-", "*", "/", "%", ":",
75 	"=", "==", "<", "<=", ">", ">=", "!=",
76 	"match", "substr", "length", "index", "\0" };
77 int op[] = { OR, AND, ADD,  SUBT, MULT, DIV, REM, MCH,
78 	EQ, EQ, LT, LEQ, GT, GEQ, NEQ,
79 	MATCH, SUBSTR, LENGTH, INDEX };
80 yylex() {
81 	register char *p;
82 	register i;
83 
84 	if(Argi >= Ac) return NOARG;
85 
86 	p = Av[Argi++];
87 
88 	if(*p == '(' || *p == ')')
89 		return (int)*p;
90 	for(i = 0; *operators[i]; ++i)
91 		if(EQL(operators[i], p))
92 			return op[i];
93 
94 	yylval = p;
95 	return A_STRING;
96 }
97 
98 char *rel(op, r1, r2) register char *r1, *r2; {
99 	register long i;
100 
101 	if(ematch(r1, "-*[0-9]*$") && ematch(r2, "[0-9]*$"))
102 		i = atol(r1) - atol(r2);
103 	else
104 		i = strcmp(r1, r2);
105 	switch(op) {
106 	case EQ: i = i==0; break;
107 	case GT: i = i>0; break;
108 	case GEQ: i = i>=0; break;
109 	case LT: i = i<0; break;
110 	case LEQ: i = i<=0; break;
111 	case NEQ: i = i!=0; break;
112 	}
113 	return i? "1": "0";
114 }
115 
116 char *arith(op, r1, r2) char *r1, *r2; {
117 	long i1, i2;
118 	register char *rv;
119 
120 	if(!((ematch(r1, "[0-9]*$") || ematch(r1, "-[0-9]*$")) &&
121 	     (ematch(r2, "[0-9]*$") || ematch(r2, "-[0-9]*$"))))
122 		yyerror("non-numeric argument");
123 	i1 = atol(r1);
124 	i2 = atol(r2);
125 
126 	switch(op) {
127 	case ADD: i1 = i1 + i2; break;
128 	case SUBT: i1 = i1 - i2; break;
129 	case MULT: i1 = i1 * i2; break;
130 	case DIV: i1 = i1 / i2; break;
131 	case REM: i1 = i1 % i2; break;
132 	}
133 	rv = malloc(16);
134 	(void)sprintf(rv, "%ld", i1);
135 	return rv;
136 }
137 char *conj(op, r1, r2) char *r1, *r2; {
138 	register char *rv;
139 
140 	switch(op) {
141 
142 	case OR:
143 		if(EQL(r1, "0")
144 		|| EQL(r1, ""))
145 			if(EQL(r2, "0")
146 			|| EQL(r2, ""))
147 				rv = "0";
148 			else
149 				rv = r2;
150 		else
151 			rv = r1;
152 		break;
153 	case AND:
154 		if(EQL(r1, "0")
155 		|| EQL(r1, ""))
156 			rv = "0";
157 		else if(EQL(r2, "0")
158 		|| EQL(r2, ""))
159 			rv = "0";
160 		else
161 			rv = r1;
162 		break;
163 	}
164 	return rv;
165 }
166 
167 char *substr(v, s, w) char *v, *s, *w; {
168 register si, wi;
169 register char *res;
170 
171 	si = atol(s);
172 	wi = atol(w);
173 	while(--si) if(*v) ++v;
174 
175 	res = v;
176 
177 	while(wi--) if(*v) ++v;
178 
179 	*v = '\0';
180 	return res;
181 }
182 
183 char *length(s) register char *s; {
184 	register i = 0;
185 	register char *rv;
186 
187 	while(*s++) ++i;
188 
189 	rv = malloc(8);
190 	(void)sprintf(rv, "%d", i);
191 	return rv;
192 }
193 
194 char *index(s, t) char *s, *t; {
195 	register i, j;
196 	register char *rv;
197 
198 	for(i = 0; s[i] ; ++i)
199 		for(j = 0; t[j] ; ++j)
200 			if(s[i]==t[j]) {
201 				(void)sprintf(rv = malloc(8), "%d", ++i);
202 				return rv;
203 			}
204 	return "0";
205 }
206 
207 char *match(s, p)
208 {
209 	register char *rv;
210 
211 	(void)sprintf(rv = malloc(8), "%d", ematch(s, p));
212 	if(nbra) {
213 		rv = malloc(strlen(Mstring[0])+1);
214 		strcpy(rv, Mstring[0]);
215 	}
216 	return rv;
217 }
218 
219 #define INIT	register char *sp = instring;
220 #define GETC()		(*sp++)
221 #define PEEKC()		(*sp)
222 #define UNGETC(c)	(--sp)
223 #define RETURN(c)	return
224 #define ERROR(c)	errxx(c)
225 
226 
227 ematch(s, p)
228 char *s;
229 register char *p;
230 {
231 	static char expbuf[ESIZE];
232 	char *compile();
233 	register num;
234 	extern char *braslist[], *braelist[], *loc2;
235 
236 	compile(p, expbuf, &expbuf[ESIZE], 0);
237 	if(nbra > 1)
238 		yyerror("Too many '\\('s");
239 	if(advance(s, expbuf)) {
240 		if(nbra == 1) {
241 			p = braslist[0];
242 			num = braelist[0] - p;
243 			strncpy(Mstring[0], p, num);
244 			Mstring[0][num] = '\0';
245 		}
246 		return(loc2-s);
247 	}
248 	return(0);
249 }
250 
251 errxx(c)
252 {
253 	yyerror("RE error");
254 }
255 
256 #define	CBRA	2
257 #define	CCHR	4
258 #define	CDOT	8
259 #define	CCL	12
260 #define	CDOL	20
261 #define	CEOF	22
262 #define	CKET	24
263 #define	CBACK	36
264 
265 #define	STAR	01
266 #define RNGE	03
267 
268 #define	NBRA	9
269 
270 #define PLACE(c)	ep[c >> 3] |= bittab[c & 07]
271 #define ISTHERE(c)	(ep[c >> 3] & bittab[c & 07])
272 
273 char	*braslist[NBRA];
274 char	*braelist[NBRA];
275 int	nbra;
276 char *loc1, *loc2, *locs;
277 int	sed;
278 
279 int	circf;
280 int	low;
281 int	size;
282 
283 char	bittab[] = {
284 	1,
285 	2,
286 	4,
287 	8,
288 	16,
289 	32,
290 	64,
291 	128
292 };
293 
294 char *
295 compile(instring, ep, endbuf, seof)
296 register char *ep;
297 char *instring, *endbuf;
298 {
299 	INIT	/* Dependent declarations and initializations */
300 	register c;
301 	register eof = seof;
302 	char *lastep = instring;
303 	int cclcnt;
304 	char bracket[NBRA], *bracketp;
305 	int closed;
306 	char neg;
307 	int lc;
308 	int i, cflg;
309 
310 	lastep = 0;
311 	if((c = GETC()) == eof) {
312 		if(*ep == 0 && !sed)
313 			ERROR(41);
314 		RETURN(ep);
315 	}
316 	bracketp = bracket;
317 	circf = closed = nbra = 0;
318 	if (c == '^')
319 		circf++;
320 	else
321 		UNGETC(c);
322 	for (;;) {
323 		if (ep >= endbuf)
324 			ERROR(50);
325 		if((c = GETC()) != '*' && ((c != '\\') || (PEEKC() != '{')))
326 			lastep = ep;
327 		if (c == eof) {
328 			*ep++ = CEOF;
329 			RETURN(ep);
330 		}
331 		switch (c) {
332 
333 		case '.':
334 			*ep++ = CDOT;
335 			continue;
336 
337 		case '\n':
338 			ERROR(36);
339 		case '*':
340 			if (lastep==0 || *lastep==CBRA || *lastep==CKET)
341 				goto defchar;
342 			*lastep |= STAR;
343 			continue;
344 
345 		case '$':
346 			if(PEEKC() != eof)
347 				goto defchar;
348 			*ep++ = CDOL;
349 			continue;
350 
351 		case '[':
352 			if(&ep[17] >= endbuf)
353 				ERROR(50);
354 
355 			*ep++ = CCL;
356 			lc = 0;
357 			for(i = 0; i < 16; i++)
358 				ep[i] = 0;
359 
360 			neg = 0;
361 			if((c = GETC()) == '^') {
362 				neg = 1;
363 				c = GETC();
364 			}
365 
366 			do {
367 				if(c == '\0' || c == '\n')
368 					ERROR(49);
369 				if(c == '-' && lc != 0) {
370 					if ((c = GETC()) == ']') {
371 						PLACE('-');
372 						break;
373 					}
374 					while(lc < c) {
375 						PLACE(lc);
376 						lc++;
377 					}
378 				}
379 				lc = c;
380 				PLACE(c);
381 			} while((c = GETC()) != ']');
382 			if(neg) {
383 				for(cclcnt = 0; cclcnt < 16; cclcnt++)
384 					ep[cclcnt] ^= -1;
385 				ep[0] &= 0376;
386 			}
387 
388 			ep += 16;
389 
390 			continue;
391 
392 		case '\\':
393 			switch(c = GETC()) {
394 
395 			case '(':
396 				if(nbra >= NBRA)
397 					ERROR(43);
398 				*bracketp++ = nbra;
399 				*ep++ = CBRA;
400 				*ep++ = nbra++;
401 				continue;
402 
403 			case ')':
404 				if(bracketp <= bracket)
405 					ERROR(42);
406 				*ep++ = CKET;
407 				*ep++ = *--bracketp;
408 				closed++;
409 				continue;
410 
411 			case '{':
412 				if(lastep == (char *) (0))
413 					goto defchar;
414 				*lastep |= RNGE;
415 				cflg = 0;
416 			nlim:
417 				c = GETC();
418 				i = 0;
419 				do {
420 					if ('0' <= c && c <= '9')
421 						i = 10 * i + c - '0';
422 					else
423 						ERROR(16);
424 				} while(((c = GETC()) != '\\') && (c != ','));
425 				if (i > 255)
426 					ERROR(11);
427 				*ep++ = i;
428 				if (c == ',') {
429 					if(cflg++)
430 						ERROR(44);
431 					if((c = GETC()) == '\\')
432 						*ep++ = 255;
433 					else {
434 						UNGETC(c);
435 						goto nlim; /* get 2'nd number */
436 					}
437 				}
438 				if(GETC() != '}')
439 					ERROR(45);
440 				if(!cflg)	/* one number */
441 					*ep++ = i;
442 				else if((ep[-1] & 0377) < (ep[-2] & 0377))
443 					ERROR(46);
444 				continue;
445 
446 			case '\n':
447 				ERROR(36);
448 
449 			case 'n':
450 				c = '\n';
451 				goto defchar;
452 
453 			default:
454 				if(c >= '1' && c <= '9') {
455 					if((c -= '1') >= closed)
456 						ERROR(25);
457 					*ep++ = CBACK;
458 					*ep++ = c;
459 					continue;
460 				}
461 			}
462 			/* Drop through to default to use \ to turn off special chars */
463 
464 		defchar:
465 		default:
466 			lastep = ep;
467 			*ep++ = CCHR;
468 			*ep++ = c;
469 		}
470 	}
471 }
472 
473 step(p1, p2)
474 register char *p1, *p2;
475 {
476 	register c;
477 
478 	if (circf) {
479 		loc1 = p1;
480 		return(advance(p1, p2));
481 	}
482 	/* fast check for first character */
483 	if (*p2==CCHR) {
484 		c = p2[1];
485 		do {
486 			if (*p1 != c)
487 				continue;
488 			if (advance(p1, p2)) {
489 				loc1 = p1;
490 				return(1);
491 			}
492 		} while (*p1++);
493 		return(0);
494 	}
495 		/* regular algorithm */
496 	do {
497 		if (advance(p1, p2)) {
498 			loc1 = p1;
499 			return(1);
500 		}
501 	} while (*p1++);
502 	return(0);
503 }
504 
505 advance(lp, ep)
506 register char *lp, *ep;
507 {
508 	register char *curlp;
509 	char c;
510 	char *bbeg;
511 	int ct;
512 
513 	for (;;) switch (*ep++) {
514 
515 	case CCHR:
516 		if (*ep++ == *lp++)
517 			continue;
518 		return(0);
519 
520 	case CDOT:
521 		if (*lp++)
522 			continue;
523 		return(0);
524 
525 	case CDOL:
526 		if (*lp==0)
527 			continue;
528 		return(0);
529 
530 	case CEOF:
531 		loc2 = lp;
532 		return(1);
533 
534 	case CCL:
535 		c = *lp++ & 0177;
536 		if(ISTHERE(c)) {
537 			ep += 16;
538 			continue;
539 		}
540 		return(0);
541 	case CBRA:
542 		braslist[*ep++] = lp;
543 		continue;
544 
545 	case CKET:
546 		braelist[*ep++] = lp;
547 		continue;
548 
549 	case CCHR|RNGE:
550 		c = *ep++;
551 		getrnge(ep);
552 		while(low--)
553 			if(*lp++ != c)
554 				return(0);
555 		curlp = lp;
556 		while(size--)
557 			if(*lp++ != c)
558 				break;
559 		if(size < 0)
560 			lp++;
561 		ep += 2;
562 		goto star;
563 
564 	case CDOT|RNGE:
565 		getrnge(ep);
566 		while(low--)
567 			if(*lp++ == '\0')
568 				return(0);
569 		curlp = lp;
570 		while(size--)
571 			if(*lp++ == '\0')
572 				break;
573 		if(size < 0)
574 			lp++;
575 		ep += 2;
576 		goto star;
577 
578 	case CCL|RNGE:
579 		getrnge(ep + 16);
580 		while(low--) {
581 			c = *lp++ & 0177;
582 			if(!ISTHERE(c))
583 				return(0);
584 		}
585 		curlp = lp;
586 		while(size--) {
587 			c = *lp++ & 0177;
588 			if(!ISTHERE(c))
589 				break;
590 		}
591 		if(size < 0)
592 			lp++;
593 		ep += 18;		/* 16 + 2 */
594 		goto star;
595 
596 	case CBACK:
597 		bbeg = braslist[*ep];
598 		ct = braelist[*ep++] - bbeg;
599 
600 		if(ecmp(bbeg, lp, ct)) {
601 			lp += ct;
602 			continue;
603 		}
604 		return(0);
605 
606 	case CBACK|STAR:
607 		bbeg = braslist[*ep];
608 		ct = braelist[*ep++] - bbeg;
609 		curlp = lp;
610 		while(ecmp(bbeg, lp, ct))
611 			lp += ct;
612 
613 		while(lp >= curlp) {
614 			if(advance(lp, ep))	return(1);
615 			lp -= ct;
616 		}
617 		return(0);
618 
619 
620 	case CDOT|STAR:
621 		curlp = lp;
622 		while (*lp++);
623 		goto star;
624 
625 	case CCHR|STAR:
626 		curlp = lp;
627 		while (*lp++ == *ep);
628 		ep++;
629 		goto star;
630 
631 	case CCL|STAR:
632 		curlp = lp;
633 		do {
634 			c = *lp++ & 0177;
635 		} while(ISTHERE(c));
636 		ep += 16;
637 		goto star;
638 
639 	star:
640 		do {
641 			if(--lp == locs)
642 				break;
643 			if (advance(lp, ep))
644 				return(1);
645 		} while (lp > curlp);
646 		return(0);
647 
648 	}
649 }
650 
651 getrnge(str)
652 register char *str;
653 {
654 	low = *str++ & 0377;
655 	size = (*str & 0377) == 255 ? 20000 : (*str & 0377) - low;
656 }
657 
658 ecmp(a, b, count)
659 register char	*a, *b;
660 register	count;
661 {
662 	if(a == b) /* should have been caught in compile() */
663 		error(51);
664 	while(count--)
665 		if(*a++ != *b++)	return(0);
666 	return(1);
667 }
668 
669 static char *sccsid = "@(#)expr.y	4.8 (Berkeley) 06/24/90";
670 yyerror(s)
671 
672 {
673 	fprintf(stderr, "%s\n", s);
674 	exit(2);
675 }
676