BSD 4 release
[unix-history] / usr / src / cmd / expr.y
CommitLineData
e95afa8a
BJ
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
20expression: expr NOARG = {
21 printf("%s\n", $1);
22 exit((!strcmp($1,"0")||!strcmp($1,"\0"))? 1: 0);
23 }
24 ;
25
26
27expr: '(' 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)
54long atol();
55char **Av;
56int Ac;
57int Argi;
58
59char Mstring[1][128];
60char *malloc();
61extern int nbra;
62
63main(argc, argv) char **argv; {
64 Ac = argc;
65 Argi = 1;
66 Av = argv;
67 yyparse();
68}
69
70char *operators[] = { "|", "&", "+", "-", "*", "/", "%", ":",
71 "=", "==", "<", "<=", ">", ">=", "!=",
72 "match", "substr", "length", "index", "\0" };
73int op[] = { OR, AND, ADD, SUBT, MULT, DIV, REM, MCH,
74 EQ, EQ, LT, LEQ, GT, GEQ, NEQ,
75 MATCH, SUBSTR, LENGTH, INDEX };
76yylex() {
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
94char *rel(op, r1, r2) register char *r1, *r2; {
95 register 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
112char *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}
132char *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
162char *substr(v, s, w) char *v, *s, *w; {
163register si, wi;
164register 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
178char *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
189char *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
202char *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
222ematch(s, p)
223char *s;
224register 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
246errxx(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
268char *braslist[NBRA];
269char *braelist[NBRA];
270int nbra;
271char *loc1, *loc2, *locs;
272int sed;
273
274int circf;
275int low;
276int size;
277
278char bittab[] = {
279 1,
280 2,
281 4,
282 8,
283 16,
284 32,
285 64,
286 128
287};
288
289char *
290compile(instring, ep, endbuf, seof)
291register char *ep;
292char *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
468step(p1, p2)
469register 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
500advance(lp, ep)
501register 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
646getrnge(str)
647register char *str;
648{
649 low = *str++ & 0377;
650 size = *str == 255 ? 20000 : (*str &0377) - low;
651}
652
653ecmp(a, b, count)
654register char *a, *b;
655register 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
31cef89c 664static char *sccsid = "@(#)expr.y 4.1 (Berkeley) 10/1/80";
e95afa8a
BJ
665yyerror(s)
666
667{
668 fprintf(stderr, "%s\n", s);
669 exit(2);
670}