Commit | Line | Data |
---|---|---|
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 | ||
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; { | |
b940afc0 | 95 | register long i; |
e95afa8a BJ |
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; | |
df3e00cc | 106 | case LEQ: i = i<=0; break; |
e95afa8a BJ |
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 | ||
e1d6f378 KB |
116 | if(!((ematch(r1, "[0-9]*$") || ematch(r1, "-[0-9]*$")) && |
117 | (ematch(r2, "[0-9]*$") || ematch(r2, "-[0-9]*$")))) | |
e95afa8a BJ |
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); | |
6521d648 | 130 | (void)sprintf(rv, "%ld", i1); |
e95afa8a BJ |
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); | |
6521d648 | 186 | (void)sprintf(rv, "%d", i); |
e95afa8a BJ |
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]) { | |
6521d648 | 197 | (void)sprintf(rv = malloc(8), "%d", ++i); |
e95afa8a BJ |
198 | return rv; |
199 | } | |
200 | return "0"; | |
201 | } | |
202 | ||
203 | char *match(s, p) | |
204 | { | |
205 | register char *rv; | |
206 | ||
6521d648 | 207 | (void)sprintf(rv = malloc(8), "%d", ematch(s, p)); |
e95afa8a BJ |
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 | ||
6ee2a9ff | 232 | compile(p, expbuf, &expbuf[ESIZE], 0); |
e95afa8a BJ |
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; | |
15bd6011 | 651 | size = (*str & 0377) == 255 ? 20000 : (*str & 0377) - low; |
e95afa8a BJ |
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 | ||
15bd6011 | 665 | static char *sccsid = "@(#)expr.y 4.7 (Berkeley) %G%"; |
e95afa8a BJ |
666 | yyerror(s) |
667 | ||
668 | { | |
669 | fprintf(stderr, "%s\n", s); | |
670 | exit(2); | |
671 | } |