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