Commit | Line | Data |
---|---|---|
9c79dca0 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; *operator[i]; ++i) | |
87 | if(EQL(operator[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 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 | yyerror(s) | |
665 | ||
666 | { | |
667 | fprintf(stderr, "%s\n", s); | |
668 | exit(2); | |
669 | } |