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