|
|
1.1 root 1: /*
2: * Regular expression routines.
3: * These routines are currently used by grep but
4: * they are somewhat general and thus could be
5: * used elsewhere.
6: */
7:
8: #include <stdio.h>
9: #include <ctype.h>
10: #include "grep.h"
11:
12: char *newcc();
13: char *e_exec();
14:
15:
16: static char repri[] = {
17: 0 /* REEND */, 2 /* STEND */,
18: 3 /* OR */, 6 /* LPAR */,
19: 1 /* RPAR */, 5 /* CLOS */,
20: 5 /* NECLOS */, 5 /* ZORO */,
21: 4 /* CONC */
22: };
23:
24: RE **rebuild();
25: RE *renode();
26: static union rebit relval;
27: static char cc[NCLASS];
28: static (*reinf)();
29: static (*reunf)();
30: static char *rein;
31:
32: static char resyn[] = "Regular expression syntax error";
33: static char reoflo[] = "Regular expression overflow";
34: static char nospace[] = "Out of space";
35:
36: char *reerror; /* Erro code */
37: int redual; /* Set for dual-case comparisons */
38: int refull; /* Full expressions accepted */
39:
40: /*
41: * Lexical token reader for
42: * regular expressions.
43: */
44: static
45: relex(ec)
46: {
47: register c;
48:
49: if ((c = (*reinf)()) == ec)
50: return (REEND);
51: switch (c) {
52: case EOF:
53: case '\n':
54: reerror = "Non-terminated regular expression";
55: return (REEND);
56:
57: case '[':
58: return (cclass(ec));
59:
60: case '^':
61: return (BOL);
62:
63: case '$':
64: return (EOL);
65:
66: case '(':
67: if (!refull)
68: goto def;
69: return (LPAR);
70:
71: case ')':
72: if (!refull)
73: goto def;
74: return (RPAR);
75:
76: case '.':
77: return (ANY);
78:
79: case '|':
80: if (!refull)
81: goto def;
82: return (OR);
83:
84: case '*':
85: return (CLOS);
86:
87: case '?':
88: if (!refull)
89: goto def;
90: return (ZORO);
91:
92: case '+':
93: if (!refull)
94: goto def;
95: return (NECLOS);
96:
97: case '\\':
98: c = (*reinf)();
99: default:
100: def:
101: relval.u_ival = c;
102: return (redual ? DCONC : CONC);
103: }
104: }
105:
106: /*
107: * Read in a character class from
108: * an RE (called from relex).
109: */
110: static
111: cclass(ec)
112: int ec;
113: {
114: register c, i, pc;
115: int comp;
116:
117: for (i=0; i<sizeof cc; i++)
118: cc[i] = 0;
119: if ((c = (*reinf)()) != '^') {
120: comp = 0;
121: (*reunf)(c);
122: } else
123: comp = 1;
124: pc = ec;
125: while ((c = (*reinf)()) != ']') {
126: if (c == ec) {
127: reerror = "Non-terminated character class";
128: return (REEND);
129: }
130: if (c=='-' && pc!=ec) {
131: if ((c = (*reinf)()) == ']')
132: break;
133: for (i=pc; i<=c; i++)
134: cc[i/NBPC] |= 1<<(i%NBPC);
135: pc = ec;
136: } else {
137: cc[c/NBPC] |= 1<<(c%NBPC);
138: pc = c;
139: }
140: }
141: if (comp)
142: for (i=0; i<sizeof cc; i++)
143: cc[i] ^= -1;
144: if ((relval.u_cptr = newcc(cc)) == NULL)
145: return (REEND);
146: return (redual ? DCCLASS : CCLASS);
147: }
148:
149: /*
150: * Allocate space for a new character class
151: * and copy into it.
152: */
153: static char *
154: newcc(occ)
155: register char *occ;
156: {
157: register char *ncc;
158: register unsigned n;
159: char *rcc;
160:
161: n = NCLASS;
162: if ((rcc = ncc = malloc(n)) == NULL) {
163: reerror = nospace;
164: return (NULL);
165: }
166: do {
167: *ncc++ = *occ++;
168: } while (--n);
169: return (rcc);
170: }
171:
172: /*
173: * Parse a regular expression.
174: * The arguments are an input string to parse (`in'),
175: * the end character to terminated the expression (`ec'),
176: * and (if `in' is NULL) functions to get and unget characters,
177: * getf and ungetf, respectively.
178: */
179: RE *
180: reparse(in, ec, getf, ungetf)
181: char *in;
182: int (*getf)(), (*ungetf)();
183: {
184: RE *restk[NRE];
185: struct opstk {
186: char o_op;
187: char o_pri;
188: } opstk[NRE];
189: register struct opstk *osp;
190: register op;
191: register RE **rsp;
192: int concflg, op1, pri;
193:
194: if ((rein = in) != NULL) {
195: reinf = reget;
196: reunf = reunget;
197: } else {
198: reinf = getf;
199: reunf = ungetf;
200: }
201: reerror = NULL;
202: concflg = 0;
203: osp = opstk;
204: osp->o_op = STEND;
205: osp->o_pri = repri[STEND];
206: rsp = restk;
207: *rsp++ = NULL;
208:
209: for (;;) {
210: if (termop(op = relex(ec))) {
211: if ((*rsp++ = renode(op, relval.u_cptr, NULL)) == NULL)
212: return (NULL);
213: if (rsp >= &restk[NRE-1]) {
214: reerror = reoflo;
215: return (NULL);
216: }
217: if (!concflg) {
218: concflg++;
219: continue;
220: } else
221: op = CONC;
222: } else if (op == OR) {
223: if (!concflg) {
224: reerror = resyn;
225: return (NULL);
226: }
227: concflg = 0;
228: } else if (op==CLOS || op==NECLOS || op==ZORO) {
229: if (!concflg) {
230: reerror = resyn;
231: return (NULL);
232: }
233: } else if (op == LPAR) {
234: if (concflg) {
235: (++osp)->o_op = CONC;
236: osp->o_pri = repri[CONC];
237: concflg = 0;
238: }
239: }
240: pri = repri[op];
241: for (;;) {
242: if (reerror != NULL)
243: return (NULL);
244: if (pri>osp->o_pri || (op==CONC && osp->o_op==CONC)) {
245: if (op == LPAR)
246: pri = repri[RPAR];
247: if (osp >= &opstk[NRE-1]) {
248: reerror = reoflo;
249: return (NULL);
250: }
251: (++osp)->o_op = op;
252: osp->o_pri = pri;
253: if (!postop(op))
254: break;
255: else
256: pri = repri[REEND];
257: }
258: switch (op1 = (osp--)->o_op) {
259: case STEND:
260: if (op == REEND)
261: return (*--rsp);
262: osp++;
263: break;
264:
265: case LPAR:
266: if (op != RPAR) {
267: reerror = "Unbalanced parentheses";
268: return (NULL);
269: }
270: break;
271:
272: default:
273: rsp = rebuild(rsp, op1);
274: continue;
275: }
276: break;
277: }
278: }
279: }
280:
281:
282: static RE **
283: rebuild(rsp, op)
284: register RE **rsp;
285: {
286: register RE *left, *right;
287:
288: switch (op) {
289: case OR:
290: right = *--rsp;
291: left = *--rsp;
292: break;
293:
294: case CLOS:
295: case NECLOS:
296: case ZORO:
297: left = *--rsp;
298: right = NULL;
299: break;
300:
301: case CONC:
302: right = *--rsp;
303: left = *--rsp;
304: if (left->r_next == NULL)
305: left->r_next = right;
306: else {
307: for (; left->r_next->r_next!=NULL; left = left->r_next)
308: ;
309: left->r_next->r_next = right;
310: }
311: return (++rsp);
312:
313: default:
314: reerror = "RE botch in rebuild";
315: }
316: *rsp++ = renode(op, left, right);
317: return (rsp);
318: }
319:
320: /*
321: * Build regular expression node.
322: */
323: static RE *
324: renode(op, left, right)
325: RE *left, *right;
326: {
327: register RE *rep;
328:
329: if ((rep = (RE *)malloc(sizeof (RE))) == NULL) {
330: reerror = nospace;
331: return (NULL);
332: }
333: rep->r_next = (RE*)NULL;
334: rep->r_op = op;
335: rep->r_left.u_re = left;
336: rep->r_right.u_re = right;
337: return (rep);
338: }
339:
340: static char *sb; /* string beginning */
341:
342: /*
343: * User-callable driver for regular expression
344: * execution. Called with regular expression code and
345: * text string.
346: */
347: reinterp(rep, s)
348: RE *rep;
349: register char *s;
350: {
351: sb = s;
352: if (rep!=NULL && rep->r_op==BOL)
353: return(e_exec(rep, s) != NULL);
354: for (; *s!='\0'; s++)
355: if (e_exec(rep, s) != NULL)
356: return (1);
357: return (0);
358: }
359:
360: /*
361: * Internal regular expression
362: * execution routines
363: */
364: static char *
365: e_exec(rep, s)
366: register RE *rep;
367: register char *s;
368: {
369: register c;
370: char *ss, *es;
371:
372: for ( ; rep!=NULL; rep = rep->r_next)
373: switch (rep->r_op) {
374: case BOL:
375: if (s != sb)
376: return (NULL);
377: break;
378:
379: case EOL:
380: if (*s != '\0')
381: return (NULL);
382: break;
383:
384: case ANY:
385: if (*s++ == '\0')
386: return (NULL);
387: break;
388:
389: case CONC:
390: if (*s++ != rep->r_left.u_ival)
391: return (NULL);
392: break;
393:
394: case DCONC:
395: if (islower(rep->r_left.u_ival)) {
396: if (isupper(c = *s++))
397: c = tolower(c);
398: if (c != rep->r_left.u_ival)
399: return (NULL);
400: } else
401: if (*s++ != rep->r_left.u_ival)
402: return (NULL);
403: break;
404:
405: case CCLASS:
406: c = *s++;
407: if ((rep->r_left.u_cptr[c/NBPC] & (1<<(c%NBPC))) == 0)
408: return (NULL);
409: break;
410:
411: case DCCLASS:
412: if ((c = *s++)>='A' && c<='Z')
413: c |= 'a'-'A';
414: if ((rep->r_left.u_cptr[c/NBPC] & (1<<(c%NBPC))) == 0)
415: return (NULL);
416: break;
417:
418: case OR:
419: ss = s;
420: if ((s = e_exec(rep->r_left.u_re, s)) == NULL)
421: if ((s = e_exec(rep->r_right.u_re, ss))==NULL)
422: return (NULL);
423: break;
424:
425: case CLOS:
426: ss = s;
427: while ((es = e_exec(rep->r_left.u_re, s)) != NULL)
428: s = es;
429: while (s >= ss)
430: if ((es = e_exec(rep->r_next, s--))!=NULL)
431: return(es);
432: return (NULL);
433:
434: case NECLOS:
435: ss = s;
436: while ((es = e_exec(rep->r_left.u_re, s)) != NULL)
437: s = es;
438: while (s > ss)
439: if ((es = e_exec(rep->r_next, s--))!=NULL)
440: return (es);
441: return (NULL);
442:
443: case ZORO:
444: ss = s;
445: if ((es = e_exec(rep->r_left.u_re, s)) != NULL)
446: s = es;
447: while (s >= ss)
448: if ((es = e_exec(rep->r_next, s--))!=NULL)
449: return (es);
450: return (NULL);
451:
452: default:
453: fprintf(stderr, "Regular expression botch\n");
454: exit(2);
455: }
456: return (s);
457: }
458:
459: /*
460: * Default functions to get and unget
461: * characters from the regular expression.
462: */
463: static
464: reget()
465: {
466: return (*rein++);
467: }
468:
469: static
470: reunget(c)
471: {
472: --rein;
473: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.