1 |
/* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tcl_base/regc_lex.c,v 1.1.1.1 2001/06/13 04:31:50 dtashley Exp $ */
|
2 |
|
3 |
/*
|
4 |
* lexical analyzer
|
5 |
* This file is #included by regcomp.c.
|
6 |
*
|
7 |
* Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
|
8 |
*
|
9 |
* Development of this software was funded, in part, by Cray Research Inc.,
|
10 |
* UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
|
11 |
* Corporation, none of whom are responsible for the results. The author
|
12 |
* thanks all of them.
|
13 |
*
|
14 |
* Redistribution and use in source and binary forms -- with or without
|
15 |
* modification -- are permitted for any purpose, provided that
|
16 |
* redistributions in source form retain this entire copyright notice and
|
17 |
* indicate the origin and nature of any modifications.
|
18 |
*
|
19 |
* I'd appreciate being given credit for this package in the documentation
|
20 |
* of software which uses it, but that is not a requirement.
|
21 |
*
|
22 |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
23 |
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
24 |
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
25 |
* HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
26 |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
27 |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
28 |
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
29 |
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
30 |
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
31 |
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32 |
*
|
33 |
*/
|
34 |
|
35 |
/* scanning macros (know about v) */
|
36 |
#define ATEOS() (v->now >= v->stop)
|
37 |
#define HAVE(n) (v->stop - v->now >= (n))
|
38 |
#define NEXT1(c) (!ATEOS() && *v->now == CHR(c))
|
39 |
#define NEXT2(a,b) (HAVE(2) && *v->now == CHR(a) && *(v->now+1) == CHR(b))
|
40 |
#define NEXT3(a,b,c) (HAVE(3) && *v->now == CHR(a) && \
|
41 |
*(v->now+1) == CHR(b) && \
|
42 |
*(v->now+2) == CHR(c))
|
43 |
#define SET(c) (v->nexttype = (c))
|
44 |
#define SETV(c, n) (v->nexttype = (c), v->nextvalue = (n))
|
45 |
#define RET(c) return (SET(c), 1)
|
46 |
#define RETV(c, n) return (SETV(c, n), 1)
|
47 |
#define FAILW(e) return (ERR(e), 0) /* ERR does SET(EOS) */
|
48 |
#define LASTTYPE(t) (v->lasttype == (t))
|
49 |
|
50 |
/* lexical contexts */
|
51 |
#define L_ERE 1 /* mainline ERE/ARE */
|
52 |
#define L_BRE 2 /* mainline BRE */
|
53 |
#define L_Q 3 /* REG_QUOTE */
|
54 |
#define L_EBND 4 /* ERE/ARE bound */
|
55 |
#define L_BBND 5 /* BRE bound */
|
56 |
#define L_BRACK 6 /* brackets */
|
57 |
#define L_CEL 7 /* collating element */
|
58 |
#define L_ECL 8 /* equivalence class */
|
59 |
#define L_CCL 9 /* character class */
|
60 |
#define INTOCON(c) (v->lexcon = (c))
|
61 |
#define INCON(con) (v->lexcon == (con))
|
62 |
|
63 |
/* construct pointer past end of chr array */
|
64 |
#define ENDOF(array) ((array) + sizeof(array)/sizeof(chr))
|
65 |
|
66 |
/*
|
67 |
- lexstart - set up lexical stuff, scan leading options
|
68 |
^ static VOID lexstart(struct vars *);
|
69 |
*/
|
70 |
static VOID
|
71 |
lexstart(v)
|
72 |
struct vars *v;
|
73 |
{
|
74 |
prefixes(v); /* may turn on new type bits etc. */
|
75 |
NOERR();
|
76 |
|
77 |
if (v->cflags®_QUOTE) {
|
78 |
assert(!(v->cflags&(REG_ADVANCED|REG_EXPANDED|REG_NEWLINE)));
|
79 |
INTOCON(L_Q);
|
80 |
} else if (v->cflags®_EXTENDED) {
|
81 |
assert(!(v->cflags®_QUOTE));
|
82 |
INTOCON(L_ERE);
|
83 |
} else {
|
84 |
assert(!(v->cflags&(REG_QUOTE|REG_ADVF)));
|
85 |
INTOCON(L_BRE);
|
86 |
}
|
87 |
|
88 |
v->nexttype = EMPTY; /* remember we were at the start */
|
89 |
next(v); /* set up the first token */
|
90 |
}
|
91 |
|
92 |
/*
|
93 |
- prefixes - implement various special prefixes
|
94 |
^ static VOID prefixes(struct vars *);
|
95 |
*/
|
96 |
static VOID
|
97 |
prefixes(v)
|
98 |
struct vars *v;
|
99 |
{
|
100 |
/* literal string doesn't get any of this stuff */
|
101 |
if (v->cflags®_QUOTE)
|
102 |
return;
|
103 |
|
104 |
/* initial "***" gets special things */
|
105 |
if (HAVE(4) && NEXT3('*', '*', '*'))
|
106 |
switch (*(v->now + 3)) {
|
107 |
case CHR('?'): /* "***?" error, msg shows version */
|
108 |
ERR(REG_BADPAT);
|
109 |
return; /* proceed no further */
|
110 |
break;
|
111 |
case CHR('='): /* "***=" shifts to literal string */
|
112 |
NOTE(REG_UNONPOSIX);
|
113 |
v->cflags |= REG_QUOTE;
|
114 |
v->cflags &= ~(REG_ADVANCED|REG_EXPANDED|REG_NEWLINE);
|
115 |
v->now += 4;
|
116 |
return; /* and there can be no more prefixes */
|
117 |
break;
|
118 |
case CHR(':'): /* "***:" shifts to AREs */
|
119 |
NOTE(REG_UNONPOSIX);
|
120 |
v->cflags |= REG_ADVANCED;
|
121 |
v->now += 4;
|
122 |
break;
|
123 |
default: /* otherwise *** is just an error */
|
124 |
ERR(REG_BADRPT);
|
125 |
return;
|
126 |
break;
|
127 |
}
|
128 |
|
129 |
/* BREs and EREs don't get embedded options */
|
130 |
if ((v->cflags®_ADVANCED) != REG_ADVANCED)
|
131 |
return;
|
132 |
|
133 |
/* embedded options (AREs only) */
|
134 |
if (HAVE(3) && NEXT2('(', '?') && iscalpha(*(v->now + 2))) {
|
135 |
NOTE(REG_UNONPOSIX);
|
136 |
v->now += 2;
|
137 |
for (; !ATEOS() && iscalpha(*v->now); v->now++)
|
138 |
switch (*v->now) {
|
139 |
case CHR('b'): /* BREs (but why???) */
|
140 |
v->cflags &= ~(REG_ADVANCED|REG_QUOTE);
|
141 |
break;
|
142 |
case CHR('c'): /* case sensitive */
|
143 |
v->cflags &= ~REG_ICASE;
|
144 |
break;
|
145 |
case CHR('e'): /* plain EREs */
|
146 |
v->cflags |= REG_EXTENDED;
|
147 |
v->cflags &= ~(REG_ADVF|REG_QUOTE);
|
148 |
break;
|
149 |
case CHR('i'): /* case insensitive */
|
150 |
v->cflags |= REG_ICASE;
|
151 |
break;
|
152 |
case CHR('m'): /* Perloid synonym for n */
|
153 |
case CHR('n'): /* \n affects ^ $ . [^ */
|
154 |
v->cflags |= REG_NEWLINE;
|
155 |
break;
|
156 |
case CHR('p'): /* ~Perl, \n affects . [^ */
|
157 |
v->cflags |= REG_NLSTOP;
|
158 |
v->cflags &= ~REG_NLANCH;
|
159 |
break;
|
160 |
case CHR('q'): /* literal string */
|
161 |
v->cflags |= REG_QUOTE;
|
162 |
v->cflags &= ~REG_ADVANCED;
|
163 |
break;
|
164 |
case CHR('s'): /* single line, \n ordinary */
|
165 |
v->cflags &= ~REG_NEWLINE;
|
166 |
break;
|
167 |
case CHR('t'): /* tight syntax */
|
168 |
v->cflags &= ~REG_EXPANDED;
|
169 |
break;
|
170 |
case CHR('w'): /* weird, \n affects ^ $ only */
|
171 |
v->cflags &= ~REG_NLSTOP;
|
172 |
v->cflags |= REG_NLANCH;
|
173 |
break;
|
174 |
case CHR('x'): /* expanded syntax */
|
175 |
v->cflags |= REG_EXPANDED;
|
176 |
break;
|
177 |
default:
|
178 |
ERR(REG_BADOPT);
|
179 |
return;
|
180 |
}
|
181 |
if (!NEXT1(')')) {
|
182 |
ERR(REG_BADOPT);
|
183 |
return;
|
184 |
}
|
185 |
v->now++;
|
186 |
if (v->cflags®_QUOTE)
|
187 |
v->cflags &= ~(REG_EXPANDED|REG_NEWLINE);
|
188 |
}
|
189 |
}
|
190 |
|
191 |
/*
|
192 |
- lexnest - "call a subroutine", interpolating string at the lexical level
|
193 |
* Note, this is not a very general facility. There are a number of
|
194 |
* implicit assumptions about what sorts of strings can be subroutines.
|
195 |
^ static VOID lexnest(struct vars *, chr *, chr *);
|
196 |
*/
|
197 |
static VOID
|
198 |
lexnest(v, beginp, endp)
|
199 |
struct vars *v;
|
200 |
chr *beginp; /* start of interpolation */
|
201 |
chr *endp; /* one past end of interpolation */
|
202 |
{
|
203 |
assert(v->savenow == NULL); /* only one level of nesting */
|
204 |
v->savenow = v->now;
|
205 |
v->savestop = v->stop;
|
206 |
v->now = beginp;
|
207 |
v->stop = endp;
|
208 |
}
|
209 |
|
210 |
/*
|
211 |
* string constants to interpolate as expansions of things like \d
|
212 |
*/
|
213 |
static chr backd[] = { /* \d */
|
214 |
CHR('['), CHR('['), CHR(':'),
|
215 |
CHR('d'), CHR('i'), CHR('g'), CHR('i'), CHR('t'),
|
216 |
CHR(':'), CHR(']'), CHR(']')
|
217 |
};
|
218 |
static chr backD[] = { /* \D */
|
219 |
CHR('['), CHR('^'), CHR('['), CHR(':'),
|
220 |
CHR('d'), CHR('i'), CHR('g'), CHR('i'), CHR('t'),
|
221 |
CHR(':'), CHR(']'), CHR(']')
|
222 |
};
|
223 |
static chr brbackd[] = { /* \d within brackets */
|
224 |
CHR('['), CHR(':'),
|
225 |
CHR('d'), CHR('i'), CHR('g'), CHR('i'), CHR('t'),
|
226 |
CHR(':'), CHR(']')
|
227 |
};
|
228 |
static chr backs[] = { /* \s */
|
229 |
CHR('['), CHR('['), CHR(':'),
|
230 |
CHR('s'), CHR('p'), CHR('a'), CHR('c'), CHR('e'),
|
231 |
CHR(':'), CHR(']'), CHR(']')
|
232 |
};
|
233 |
static chr backS[] = { /* \S */
|
234 |
CHR('['), CHR('^'), CHR('['), CHR(':'),
|
235 |
CHR('s'), CHR('p'), CHR('a'), CHR('c'), CHR('e'),
|
236 |
CHR(':'), CHR(']'), CHR(']')
|
237 |
};
|
238 |
static chr brbacks[] = { /* \s within brackets */
|
239 |
CHR('['), CHR(':'),
|
240 |
CHR('s'), CHR('p'), CHR('a'), CHR('c'), CHR('e'),
|
241 |
CHR(':'), CHR(']')
|
242 |
};
|
243 |
static chr backw[] = { /* \w */
|
244 |
CHR('['), CHR('['), CHR(':'),
|
245 |
CHR('a'), CHR('l'), CHR('n'), CHR('u'), CHR('m'),
|
246 |
CHR(':'), CHR(']'), CHR('_'), CHR(']')
|
247 |
};
|
248 |
static chr backW[] = { /* \W */
|
249 |
CHR('['), CHR('^'), CHR('['), CHR(':'),
|
250 |
CHR('a'), CHR('l'), CHR('n'), CHR('u'), CHR('m'),
|
251 |
CHR(':'), CHR(']'), CHR('_'), CHR(']')
|
252 |
};
|
253 |
static chr brbackw[] = { /* \w within brackets */
|
254 |
CHR('['), CHR(':'),
|
255 |
CHR('a'), CHR('l'), CHR('n'), CHR('u'), CHR('m'),
|
256 |
CHR(':'), CHR(']'), CHR('_')
|
257 |
};
|
258 |
|
259 |
/*
|
260 |
- lexword - interpolate a bracket expression for word characters
|
261 |
* Possibly ought to inquire whether there is a "word" character class.
|
262 |
^ static VOID lexword(struct vars *);
|
263 |
*/
|
264 |
static VOID
|
265 |
lexword(v)
|
266 |
struct vars *v;
|
267 |
{
|
268 |
lexnest(v, backw, ENDOF(backw));
|
269 |
}
|
270 |
|
271 |
/*
|
272 |
- next - get next token
|
273 |
^ static int next(struct vars *);
|
274 |
*/
|
275 |
static int /* 1 normal, 0 failure */
|
276 |
next(v)
|
277 |
struct vars *v;
|
278 |
{
|
279 |
chr c;
|
280 |
|
281 |
/* errors yield an infinite sequence of failures */
|
282 |
if (ISERR())
|
283 |
return 0; /* the error has set nexttype to EOS */
|
284 |
|
285 |
/* remember flavor of last token */
|
286 |
v->lasttype = v->nexttype;
|
287 |
|
288 |
/* REG_BOSONLY */
|
289 |
if (v->nexttype == EMPTY && (v->cflags®_BOSONLY)) {
|
290 |
/* at start of a REG_BOSONLY RE */
|
291 |
RETV(SBEGIN, 0); /* same as \A */
|
292 |
}
|
293 |
|
294 |
/* if we're nested and we've hit end, return to outer level */
|
295 |
if (v->savenow != NULL && ATEOS()) {
|
296 |
v->now = v->savenow;
|
297 |
v->stop = v->savestop;
|
298 |
v->savenow = v->savestop = NULL;
|
299 |
}
|
300 |
|
301 |
/* skip white space etc. if appropriate (not in literal or []) */
|
302 |
if (v->cflags®_EXPANDED)
|
303 |
switch (v->lexcon) {
|
304 |
case L_ERE:
|
305 |
case L_BRE:
|
306 |
case L_EBND:
|
307 |
case L_BBND:
|
308 |
skip(v);
|
309 |
break;
|
310 |
}
|
311 |
|
312 |
/* handle EOS, depending on context */
|
313 |
if (ATEOS()) {
|
314 |
switch (v->lexcon) {
|
315 |
case L_ERE:
|
316 |
case L_BRE:
|
317 |
case L_Q:
|
318 |
RET(EOS);
|
319 |
break;
|
320 |
case L_EBND:
|
321 |
case L_BBND:
|
322 |
FAILW(REG_EBRACE);
|
323 |
break;
|
324 |
case L_BRACK:
|
325 |
case L_CEL:
|
326 |
case L_ECL:
|
327 |
case L_CCL:
|
328 |
FAILW(REG_EBRACK);
|
329 |
break;
|
330 |
}
|
331 |
assert(NOTREACHED);
|
332 |
}
|
333 |
|
334 |
/* okay, time to actually get a character */
|
335 |
c = *v->now++;
|
336 |
|
337 |
/* deal with the easy contexts, punt EREs to code below */
|
338 |
switch (v->lexcon) {
|
339 |
case L_BRE: /* punt BREs to separate function */
|
340 |
return brenext(v, c);
|
341 |
break;
|
342 |
case L_ERE: /* see below */
|
343 |
break;
|
344 |
case L_Q: /* literal strings are easy */
|
345 |
RETV(PLAIN, c);
|
346 |
break;
|
347 |
case L_BBND: /* bounds are fairly simple */
|
348 |
case L_EBND:
|
349 |
switch (c) {
|
350 |
case CHR('0'): case CHR('1'): case CHR('2'): case CHR('3'):
|
351 |
case CHR('4'): case CHR('5'): case CHR('6'): case CHR('7'):
|
352 |
case CHR('8'): case CHR('9'):
|
353 |
RETV(DIGIT, (chr)DIGITVAL(c));
|
354 |
break;
|
355 |
case CHR(','):
|
356 |
RET(',');
|
357 |
break;
|
358 |
case CHR('}'): /* ERE bound ends with } */
|
359 |
if (INCON(L_EBND)) {
|
360 |
INTOCON(L_ERE);
|
361 |
if ((v->cflags®_ADVF) && NEXT1('?')) {
|
362 |
v->now++;
|
363 |
NOTE(REG_UNONPOSIX);
|
364 |
RETV('}', 0);
|
365 |
}
|
366 |
RETV('}', 1);
|
367 |
} else
|
368 |
FAILW(REG_BADBR);
|
369 |
break;
|
370 |
case CHR('\\'): /* BRE bound ends with \} */
|
371 |
if (INCON(L_BBND) && NEXT1('}')) {
|
372 |
v->now++;
|
373 |
INTOCON(L_BRE);
|
374 |
RET('}');
|
375 |
} else
|
376 |
FAILW(REG_BADBR);
|
377 |
break;
|
378 |
default:
|
379 |
FAILW(REG_BADBR);
|
380 |
break;
|
381 |
}
|
382 |
assert(NOTREACHED);
|
383 |
break;
|
384 |
case L_BRACK: /* brackets are not too hard */
|
385 |
switch (c) {
|
386 |
case CHR(']'):
|
387 |
if (LASTTYPE('['))
|
388 |
RETV(PLAIN, c);
|
389 |
else {
|
390 |
INTOCON((v->cflags®_EXTENDED) ?
|
391 |
L_ERE : L_BRE);
|
392 |
RET(']');
|
393 |
}
|
394 |
break;
|
395 |
case CHR('\\'):
|
396 |
NOTE(REG_UBBS);
|
397 |
if (!(v->cflags®_ADVF))
|
398 |
RETV(PLAIN, c);
|
399 |
NOTE(REG_UNONPOSIX);
|
400 |
if (ATEOS())
|
401 |
FAILW(REG_EESCAPE);
|
402 |
(DISCARD)lexescape(v);
|
403 |
switch (v->nexttype) { /* not all escapes okay here */
|
404 |
case PLAIN:
|
405 |
return 1;
|
406 |
break;
|
407 |
case CCLASS:
|
408 |
switch (v->nextvalue) {
|
409 |
case 'd':
|
410 |
lexnest(v, brbackd, ENDOF(brbackd));
|
411 |
break;
|
412 |
case 's':
|
413 |
lexnest(v, brbacks, ENDOF(brbacks));
|
414 |
break;
|
415 |
case 'w':
|
416 |
lexnest(v, brbackw, ENDOF(brbackw));
|
417 |
break;
|
418 |
default:
|
419 |
FAILW(REG_EESCAPE);
|
420 |
break;
|
421 |
}
|
422 |
/* lexnest done, back up and try again */
|
423 |
v->nexttype = v->lasttype;
|
424 |
return next(v);
|
425 |
break;
|
426 |
}
|
427 |
/* not one of the acceptable escapes */
|
428 |
FAILW(REG_EESCAPE);
|
429 |
break;
|
430 |
case CHR('-'):
|
431 |
if (LASTTYPE('[') || NEXT1(']'))
|
432 |
RETV(PLAIN, c);
|
433 |
else
|
434 |
RETV(RANGE, c);
|
435 |
break;
|
436 |
case CHR('['):
|
437 |
if (ATEOS())
|
438 |
FAILW(REG_EBRACK);
|
439 |
switch (*v->now++) {
|
440 |
case CHR('.'):
|
441 |
INTOCON(L_CEL);
|
442 |
/* might or might not be locale-specific */
|
443 |
RET(COLLEL);
|
444 |
break;
|
445 |
case CHR('='):
|
446 |
INTOCON(L_ECL);
|
447 |
NOTE(REG_ULOCALE);
|
448 |
RET(ECLASS);
|
449 |
break;
|
450 |
case CHR(':'):
|
451 |
INTOCON(L_CCL);
|
452 |
NOTE(REG_ULOCALE);
|
453 |
RET(CCLASS);
|
454 |
break;
|
455 |
default: /* oops */
|
456 |
v->now--;
|
457 |
RETV(PLAIN, c);
|
458 |
break;
|
459 |
}
|
460 |
assert(NOTREACHED);
|
461 |
break;
|
462 |
default:
|
463 |
RETV(PLAIN, c);
|
464 |
break;
|
465 |
}
|
466 |
assert(NOTREACHED);
|
467 |
break;
|
468 |
case L_CEL: /* collating elements are easy */
|
469 |
if (c == CHR('.') && NEXT1(']')) {
|
470 |
v->now++;
|
471 |
INTOCON(L_BRACK);
|
472 |
RETV(END, '.');
|
473 |
} else
|
474 |
RETV(PLAIN, c);
|
475 |
break;
|
476 |
case L_ECL: /* ditto equivalence classes */
|
477 |
if (c == CHR('=') && NEXT1(']')) {
|
478 |
v->now++;
|
479 |
INTOCON(L_BRACK);
|
480 |
RETV(END, '=');
|
481 |
} else
|
482 |
RETV(PLAIN, c);
|
483 |
break;
|
484 |
case L_CCL: /* ditto character classes */
|
485 |
if (c == CHR(':') && NEXT1(']')) {
|
486 |
v->now++;
|
487 |
INTOCON(L_BRACK);
|
488 |
RETV(END, ':');
|
489 |
} else
|
490 |
RETV(PLAIN, c);
|
491 |
break;
|
492 |
default:
|
493 |
assert(NOTREACHED);
|
494 |
break;
|
495 |
}
|
496 |
|
497 |
/* that got rid of everything except EREs and AREs */
|
498 |
assert(INCON(L_ERE));
|
499 |
|
500 |
/* deal with EREs and AREs, except for backslashes */
|
501 |
switch (c) {
|
502 |
case CHR('|'):
|
503 |
RET('|');
|
504 |
break;
|
505 |
case CHR('*'):
|
506 |
if ((v->cflags®_ADVF) && NEXT1('?')) {
|
507 |
v->now++;
|
508 |
NOTE(REG_UNONPOSIX);
|
509 |
RETV('*', 0);
|
510 |
}
|
511 |
RETV('*', 1);
|
512 |
break;
|
513 |
case CHR('+'):
|
514 |
if ((v->cflags®_ADVF) && NEXT1('?')) {
|
515 |
v->now++;
|
516 |
NOTE(REG_UNONPOSIX);
|
517 |
RETV('+', 0);
|
518 |
}
|
519 |
RETV('+', 1);
|
520 |
break;
|
521 |
case CHR('?'):
|
522 |
if ((v->cflags®_ADVF) && NEXT1('?')) {
|
523 |
v->now++;
|
524 |
NOTE(REG_UNONPOSIX);
|
525 |
RETV('?', 0);
|
526 |
}
|
527 |
RETV('?', 1);
|
528 |
break;
|
529 |
case CHR('{'): /* bounds start or plain character */
|
530 |
if (v->cflags®_EXPANDED)
|
531 |
skip(v);
|
532 |
if (ATEOS() || !iscdigit(*v->now)) {
|
533 |
NOTE(REG_UBRACES);
|
534 |
NOTE(REG_UUNSPEC);
|
535 |
RETV(PLAIN, c);
|
536 |
} else {
|
537 |
NOTE(REG_UBOUNDS);
|
538 |
INTOCON(L_EBND);
|
539 |
RET('{');
|
540 |
}
|
541 |
assert(NOTREACHED);
|
542 |
break;
|
543 |
case CHR('('): /* parenthesis, or advanced extension */
|
544 |
if ((v->cflags®_ADVF) && NEXT1('?')) {
|
545 |
NOTE(REG_UNONPOSIX);
|
546 |
v->now++;
|
547 |
switch (*v->now++) {
|
548 |
case CHR(':'): /* non-capturing paren */
|
549 |
RETV('(', 0);
|
550 |
break;
|
551 |
case CHR('#'): /* comment */
|
552 |
while (!ATEOS() && *v->now != CHR(')'))
|
553 |
v->now++;
|
554 |
if (!ATEOS())
|
555 |
v->now++;
|
556 |
assert(v->nexttype == v->lasttype);
|
557 |
return next(v);
|
558 |
break;
|
559 |
case CHR('='): /* positive lookahead */
|
560 |
NOTE(REG_ULOOKAHEAD);
|
561 |
RETV(LACON, 1);
|
562 |
break;
|
563 |
case CHR('!'): /* negative lookahead */
|
564 |
NOTE(REG_ULOOKAHEAD);
|
565 |
RETV(LACON, 0);
|
566 |
break;
|
567 |
default:
|
568 |
FAILW(REG_BADRPT);
|
569 |
break;
|
570 |
}
|
571 |
assert(NOTREACHED);
|
572 |
}
|
573 |
if (v->cflags®_NOSUB)
|
574 |
RETV('(', 0); /* all parens non-capturing */
|
575 |
else
|
576 |
RETV('(', 1);
|
577 |
break;
|
578 |
case CHR(')'):
|
579 |
if (LASTTYPE('(')) {
|
580 |
NOTE(REG_UUNSPEC);
|
581 |
}
|
582 |
RETV(')', c);
|
583 |
break;
|
584 |
case CHR('['): /* easy except for [[:<:]] and [[:>:]] */
|
585 |
if (HAVE(6) && *(v->now+0) == CHR('[') &&
|
586 |
*(v->now+1) == CHR(':') &&
|
587 |
(*(v->now+2) == CHR('<') ||
|
588 |
*(v->now+2) == CHR('>')) &&
|
589 |
*(v->now+3) == CHR(':') &&
|
590 |
*(v->now+4) == CHR(']') &&
|
591 |
*(v->now+5) == CHR(']')) {
|
592 |
c = *(v->now+2);
|
593 |
v->now += 6;
|
594 |
NOTE(REG_UNONPOSIX);
|
595 |
RET((c == CHR('<')) ? '<' : '>');
|
596 |
}
|
597 |
INTOCON(L_BRACK);
|
598 |
if (NEXT1('^')) {
|
599 |
v->now++;
|
600 |
RETV('[', 0);
|
601 |
}
|
602 |
RETV('[', 1);
|
603 |
break;
|
604 |
case CHR('.'):
|
605 |
RET('.');
|
606 |
break;
|
607 |
case CHR('^'):
|
608 |
RET('^');
|
609 |
break;
|
610 |
case CHR('$'):
|
611 |
RET('$');
|
612 |
break;
|
613 |
case CHR('\\'): /* mostly punt backslashes to code below */
|
614 |
if (ATEOS())
|
615 |
FAILW(REG_EESCAPE);
|
616 |
break;
|
617 |
default: /* ordinary character */
|
618 |
RETV(PLAIN, c);
|
619 |
break;
|
620 |
}
|
621 |
|
622 |
/* ERE/ARE backslash handling; backslash already eaten */
|
623 |
assert(!ATEOS());
|
624 |
if (!(v->cflags®_ADVF)) { /* only AREs have non-trivial escapes */
|
625 |
if (iscalnum(*v->now)) {
|
626 |
NOTE(REG_UBSALNUM);
|
627 |
NOTE(REG_UUNSPEC);
|
628 |
}
|
629 |
RETV(PLAIN, *v->now++);
|
630 |
}
|
631 |
(DISCARD)lexescape(v);
|
632 |
if (ISERR())
|
633 |
FAILW(REG_EESCAPE);
|
634 |
if (v->nexttype == CCLASS) { /* fudge at lexical level */
|
635 |
switch (v->nextvalue) {
|
636 |
case 'd': lexnest(v, backd, ENDOF(backd)); break;
|
637 |
case 'D': lexnest(v, backD, ENDOF(backD)); break;
|
638 |
case 's': lexnest(v, backs, ENDOF(backs)); break;
|
639 |
case 'S': lexnest(v, backS, ENDOF(backS)); break;
|
640 |
case 'w': lexnest(v, backw, ENDOF(backw)); break;
|
641 |
case 'W': lexnest(v, backW, ENDOF(backW)); break;
|
642 |
default:
|
643 |
assert(NOTREACHED);
|
644 |
FAILW(REG_ASSERT);
|
645 |
break;
|
646 |
}
|
647 |
/* lexnest done, back up and try again */
|
648 |
v->nexttype = v->lasttype;
|
649 |
return next(v);
|
650 |
}
|
651 |
/* otherwise, lexescape has already done the work */
|
652 |
return !ISERR();
|
653 |
}
|
654 |
|
655 |
/*
|
656 |
- lexescape - parse an ARE backslash escape (backslash already eaten)
|
657 |
* Note slightly nonstandard use of the CCLASS type code.
|
658 |
^ static int lexescape(struct vars *);
|
659 |
*/
|
660 |
static int /* not actually used, but convenient for RETV */
|
661 |
lexescape(v)
|
662 |
struct vars *v;
|
663 |
{
|
664 |
chr c;
|
665 |
static chr alert[] = {
|
666 |
CHR('a'), CHR('l'), CHR('e'), CHR('r'), CHR('t')
|
667 |
};
|
668 |
static chr esc[] = {
|
669 |
CHR('E'), CHR('S'), CHR('C')
|
670 |
};
|
671 |
chr *save;
|
672 |
|
673 |
assert(v->cflags®_ADVF);
|
674 |
|
675 |
assert(!ATEOS());
|
676 |
c = *v->now++;
|
677 |
if (!iscalnum(c))
|
678 |
RETV(PLAIN, c);
|
679 |
|
680 |
NOTE(REG_UNONPOSIX);
|
681 |
switch (c) {
|
682 |
case CHR('a'):
|
683 |
RETV(PLAIN, chrnamed(v, alert, ENDOF(alert), CHR('\007')));
|
684 |
break;
|
685 |
case CHR('A'):
|
686 |
RETV(SBEGIN, 0);
|
687 |
break;
|
688 |
case CHR('b'):
|
689 |
RETV(PLAIN, CHR('\b'));
|
690 |
break;
|
691 |
case CHR('B'):
|
692 |
RETV(PLAIN, CHR('\\'));
|
693 |
break;
|
694 |
case CHR('c'):
|
695 |
NOTE(REG_UUNPORT);
|
696 |
if (ATEOS())
|
697 |
FAILW(REG_EESCAPE);
|
698 |
RETV(PLAIN, (chr)(*v->now++ & 037));
|
699 |
break;
|
700 |
case CHR('d'):
|
701 |
NOTE(REG_ULOCALE);
|
702 |
RETV(CCLASS, 'd');
|
703 |
break;
|
704 |
case CHR('D'):
|
705 |
NOTE(REG_ULOCALE);
|
706 |
RETV(CCLASS, 'D');
|
707 |
break;
|
708 |
case CHR('e'):
|
709 |
NOTE(REG_UUNPORT);
|
710 |
RETV(PLAIN, chrnamed(v, esc, ENDOF(esc), CHR('\033')));
|
711 |
break;
|
712 |
case CHR('f'):
|
713 |
RETV(PLAIN, CHR('\f'));
|
714 |
break;
|
715 |
case CHR('m'):
|
716 |
RET('<');
|
717 |
break;
|
718 |
case CHR('M'):
|
719 |
RET('>');
|
720 |
break;
|
721 |
case CHR('n'):
|
722 |
RETV(PLAIN, CHR('\n'));
|
723 |
break;
|
724 |
case CHR('r'):
|
725 |
RETV(PLAIN, CHR('\r'));
|
726 |
break;
|
727 |
case CHR('s'):
|
728 |
NOTE(REG_ULOCALE);
|
729 |
RETV(CCLASS, 's');
|
730 |
break;
|
731 |
case CHR('S'):
|
732 |
NOTE(REG_ULOCALE);
|
733 |
RETV(CCLASS, 'S');
|
734 |
break;
|
735 |
case CHR('t'):
|
736 |
RETV(PLAIN, CHR('\t'));
|
737 |
break;
|
738 |
case CHR('u'):
|
739 |
c = lexdigits(v, 16, 4, 4);
|
740 |
if (ISERR())
|
741 |
FAILW(REG_EESCAPE);
|
742 |
RETV(PLAIN, c);
|
743 |
break;
|
744 |
case CHR('U'):
|
745 |
c = lexdigits(v, 16, 8, 8);
|
746 |
if (ISERR())
|
747 |
FAILW(REG_EESCAPE);
|
748 |
RETV(PLAIN, c);
|
749 |
break;
|
750 |
case CHR('v'):
|
751 |
RETV(PLAIN, CHR('\v'));
|
752 |
break;
|
753 |
case CHR('w'):
|
754 |
NOTE(REG_ULOCALE);
|
755 |
RETV(CCLASS, 'w');
|
756 |
break;
|
757 |
case CHR('W'):
|
758 |
NOTE(REG_ULOCALE);
|
759 |
RETV(CCLASS, 'W');
|
760 |
break;
|
761 |
case CHR('x'):
|
762 |
NOTE(REG_UUNPORT);
|
763 |
c = lexdigits(v, 16, 1, 255); /* REs >255 long outside spec */
|
764 |
if (ISERR())
|
765 |
FAILW(REG_EESCAPE);
|
766 |
RETV(PLAIN, c);
|
767 |
break;
|
768 |
case CHR('y'):
|
769 |
NOTE(REG_ULOCALE);
|
770 |
RETV(WBDRY, 0);
|
771 |
break;
|
772 |
case CHR('Y'):
|
773 |
NOTE(REG_ULOCALE);
|
774 |
RETV(NWBDRY, 0);
|
775 |
break;
|
776 |
case CHR('Z'):
|
777 |
RETV(SEND, 0);
|
778 |
break;
|
779 |
case CHR('1'): case CHR('2'): case CHR('3'): case CHR('4'):
|
780 |
case CHR('5'): case CHR('6'): case CHR('7'): case CHR('8'):
|
781 |
case CHR('9'):
|
782 |
save = v->now;
|
783 |
v->now--; /* put first digit back */
|
784 |
c = lexdigits(v, 10, 1, 255); /* REs >255 long outside spec */
|
785 |
if (ISERR())
|
786 |
FAILW(REG_EESCAPE);
|
787 |
/* ugly heuristic (first test is "exactly 1 digit?") */
|
788 |
if (v->now - save == 0 || (int)c <= v->nsubexp) {
|
789 |
NOTE(REG_UBACKREF);
|
790 |
RETV(BACKREF, (chr)c);
|
791 |
}
|
792 |
/* oops, doesn't look like it's a backref after all... */
|
793 |
v->now = save;
|
794 |
/* and fall through into octal number */
|
795 |
case CHR('0'):
|
796 |
NOTE(REG_UUNPORT);
|
797 |
v->now--; /* put first digit back */
|
798 |
c = lexdigits(v, 8, 1, 3);
|
799 |
if (ISERR())
|
800 |
FAILW(REG_EESCAPE);
|
801 |
RETV(PLAIN, c);
|
802 |
break;
|
803 |
default:
|
804 |
assert(iscalpha(c));
|
805 |
FAILW(REG_EESCAPE); /* unknown alphabetic escape */
|
806 |
break;
|
807 |
}
|
808 |
assert(NOTREACHED);
|
809 |
}
|
810 |
|
811 |
/*
|
812 |
- lexdigits - slurp up digits and return chr value
|
813 |
^ static chr lexdigits(struct vars *, int, int, int);
|
814 |
*/
|
815 |
static chr /* chr value; errors signalled via ERR */
|
816 |
lexdigits(v, base, minlen, maxlen)
|
817 |
struct vars *v;
|
818 |
int base;
|
819 |
int minlen;
|
820 |
int maxlen;
|
821 |
{
|
822 |
uchr n; /* unsigned to avoid overflow misbehavior */
|
823 |
int len;
|
824 |
chr c;
|
825 |
int d;
|
826 |
CONST uchr ub = (uchr) base;
|
827 |
|
828 |
n = 0;
|
829 |
for (len = 0; len < maxlen && !ATEOS(); len++) {
|
830 |
c = *v->now++;
|
831 |
switch (c) {
|
832 |
case CHR('0'): case CHR('1'): case CHR('2'): case CHR('3'):
|
833 |
case CHR('4'): case CHR('5'): case CHR('6'): case CHR('7'):
|
834 |
case CHR('8'): case CHR('9'):
|
835 |
d = DIGITVAL(c);
|
836 |
break;
|
837 |
case CHR('a'): case CHR('A'): d = 10; break;
|
838 |
case CHR('b'): case CHR('B'): d = 11; break;
|
839 |
case CHR('c'): case CHR('C'): d = 12; break;
|
840 |
case CHR('d'): case CHR('D'): d = 13; break;
|
841 |
case CHR('e'): case CHR('E'): d = 14; break;
|
842 |
case CHR('f'): case CHR('F'): d = 15; break;
|
843 |
default:
|
844 |
v->now--; /* oops, not a digit at all */
|
845 |
d = -1;
|
846 |
break;
|
847 |
}
|
848 |
|
849 |
if (d >= base) { /* not a plausible digit */
|
850 |
v->now--;
|
851 |
d = -1;
|
852 |
}
|
853 |
if (d < 0)
|
854 |
break; /* NOTE BREAK OUT */
|
855 |
n = n*ub + (uchr)d;
|
856 |
}
|
857 |
if (len < minlen)
|
858 |
ERR(REG_EESCAPE);
|
859 |
|
860 |
return (chr)n;
|
861 |
}
|
862 |
|
863 |
/*
|
864 |
- brenext - get next BRE token
|
865 |
* This is much like EREs except for all the stupid backslashes and the
|
866 |
* context-dependency of some things.
|
867 |
^ static int brenext(struct vars *, pchr);
|
868 |
*/
|
869 |
static int /* 1 normal, 0 failure */
|
870 |
brenext(v, pc)
|
871 |
struct vars *v;
|
872 |
pchr pc;
|
873 |
{
|
874 |
chr c = (chr)pc;
|
875 |
|
876 |
switch (c) {
|
877 |
case CHR('*'):
|
878 |
if (LASTTYPE(EMPTY) || LASTTYPE('(') || LASTTYPE('^'))
|
879 |
RETV(PLAIN, c);
|
880 |
RET('*');
|
881 |
break;
|
882 |
case CHR('['):
|
883 |
if (HAVE(6) && *(v->now+0) == CHR('[') &&
|
884 |
*(v->now+1) == CHR(':') &&
|
885 |
(*(v->now+2) == CHR('<') ||
|
886 |
*(v->now+2) == CHR('>')) &&
|
887 |
*(v->now+3) == CHR(':') &&
|
888 |
*(v->now+4) == CHR(']') &&
|
889 |
*(v->now+5) == CHR(']')) {
|
890 |
c = *(v->now+2);
|
891 |
v->now += 6;
|
892 |
NOTE(REG_UNONPOSIX);
|
893 |
RET((c == CHR('<')) ? '<' : '>');
|
894 |
}
|
895 |
INTOCON(L_BRACK);
|
896 |
if (NEXT1('^')) {
|
897 |
v->now++;
|
898 |
RETV('[', 0);
|
899 |
}
|
900 |
RETV('[', 1);
|
901 |
break;
|
902 |
case CHR('.'):
|
903 |
RET('.');
|
904 |
break;
|
905 |
case CHR('^'):
|
906 |
if (LASTTYPE(EMPTY))
|
907 |
RET('^');
|
908 |
if (LASTTYPE('(')) {
|
909 |
NOTE(REG_UUNSPEC);
|
910 |
RET('^');
|
911 |
}
|
912 |
RETV(PLAIN, c);
|
913 |
break;
|
914 |
case CHR('$'):
|
915 |
if (v->cflags®_EXPANDED)
|
916 |
skip(v);
|
917 |
if (ATEOS())
|
918 |
RET('$');
|
919 |
if (NEXT2('\\', ')')) {
|
920 |
NOTE(REG_UUNSPEC);
|
921 |
RET('$');
|
922 |
}
|
923 |
RETV(PLAIN, c);
|
924 |
break;
|
925 |
case CHR('\\'):
|
926 |
break; /* see below */
|
927 |
default:
|
928 |
RETV(PLAIN, c);
|
929 |
break;
|
930 |
}
|
931 |
|
932 |
assert(c == CHR('\\'));
|
933 |
|
934 |
if (ATEOS())
|
935 |
FAILW(REG_EESCAPE);
|
936 |
|
937 |
c = *v->now++;
|
938 |
switch (c) {
|
939 |
case CHR('{'):
|
940 |
INTOCON(L_BBND);
|
941 |
NOTE(REG_UBOUNDS);
|
942 |
RET('{');
|
943 |
break;
|
944 |
case CHR('('):
|
945 |
RETV('(', 1);
|
946 |
break;
|
947 |
case CHR(')'):
|
948 |
RETV(')', c);
|
949 |
break;
|
950 |
case CHR('<'):
|
951 |
NOTE(REG_UNONPOSIX);
|
952 |
RET('<');
|
953 |
break;
|
954 |
case CHR('>'):
|
955 |
NOTE(REG_UNONPOSIX);
|
956 |
RET('>');
|
957 |
break;
|
958 |
case CHR('1'): case CHR('2'): case CHR('3'): case CHR('4'):
|
959 |
case CHR('5'): case CHR('6'): case CHR('7'): case CHR('8'):
|
960 |
case CHR('9'):
|
961 |
NOTE(REG_UBACKREF);
|
962 |
RETV(BACKREF, (chr)DIGITVAL(c));
|
963 |
break;
|
964 |
default:
|
965 |
if (iscalnum(c)) {
|
966 |
NOTE(REG_UBSALNUM);
|
967 |
NOTE(REG_UUNSPEC);
|
968 |
}
|
969 |
RETV(PLAIN, c);
|
970 |
break;
|
971 |
}
|
972 |
|
973 |
assert(NOTREACHED);
|
974 |
}
|
975 |
|
976 |
/*
|
977 |
- skip - skip white space and comments in expanded form
|
978 |
^ static VOID skip(struct vars *);
|
979 |
*/
|
980 |
static VOID
|
981 |
skip(v)
|
982 |
struct vars *v;
|
983 |
{
|
984 |
chr *start = v->now;
|
985 |
|
986 |
assert(v->cflags®_EXPANDED);
|
987 |
|
988 |
for (;;) {
|
989 |
while (!ATEOS() && iscspace(*v->now))
|
990 |
v->now++;
|
991 |
if (ATEOS() || *v->now != CHR('#'))
|
992 |
break; /* NOTE BREAK OUT */
|
993 |
assert(NEXT1('#'));
|
994 |
while (!ATEOS() && *v->now != CHR('\n'))
|
995 |
v->now++;
|
996 |
/* leave the newline to be picked up by the iscspace loop */
|
997 |
}
|
998 |
|
999 |
if (v->now != start)
|
1000 |
NOTE(REG_UNONPOSIX);
|
1001 |
}
|
1002 |
|
1003 |
/*
|
1004 |
- newline - return the chr for a newline
|
1005 |
* This helps confine use of CHR to this source file.
|
1006 |
^ static chr newline(NOPARMS);
|
1007 |
*/
|
1008 |
static chr
|
1009 |
newline()
|
1010 |
{
|
1011 |
return CHR('\n');
|
1012 |
}
|
1013 |
|
1014 |
/*
|
1015 |
- ch - return the chr sequence for regc_locale.c's fake collating element ch
|
1016 |
* This helps confine use of CHR to this source file. Beware that the caller
|
1017 |
* knows how long the sequence is.
|
1018 |
^ #ifdef REG_DEBUG
|
1019 |
^ static chr *ch(NOPARMS);
|
1020 |
^ #endif
|
1021 |
*/
|
1022 |
#ifdef REG_DEBUG
|
1023 |
static chr *
|
1024 |
ch()
|
1025 |
{
|
1026 |
static chr chstr[] = { CHR('c'), CHR('h'), CHR('\0') };
|
1027 |
|
1028 |
return chstr;
|
1029 |
}
|
1030 |
#endif
|
1031 |
|
1032 |
/*
|
1033 |
- chrnamed - return the chr known by a given (chr string) name
|
1034 |
* The code is a bit clumsy, but this routine gets only such specialized
|
1035 |
* use that it hardly matters.
|
1036 |
^ static chr chrnamed(struct vars *, chr *, chr *, pchr);
|
1037 |
*/
|
1038 |
static chr
|
1039 |
chrnamed(v, startp, endp, lastresort)
|
1040 |
struct vars *v;
|
1041 |
chr *startp; /* start of name */
|
1042 |
chr *endp; /* just past end of name */
|
1043 |
pchr lastresort; /* what to return if name lookup fails */
|
1044 |
{
|
1045 |
celt c;
|
1046 |
int errsave;
|
1047 |
int e;
|
1048 |
struct cvec *cv;
|
1049 |
|
1050 |
errsave = v->err;
|
1051 |
v->err = 0;
|
1052 |
c = element(v, startp, endp);
|
1053 |
e = v->err;
|
1054 |
v->err = errsave;
|
1055 |
|
1056 |
if (e != 0)
|
1057 |
return (chr)lastresort;
|
1058 |
|
1059 |
cv = range(v, c, c, 0);
|
1060 |
if (cv->nchrs == 0)
|
1061 |
return (chr)lastresort;
|
1062 |
return cv->chrs[0];
|
1063 |
}
|
1064 |
|
1065 |
/* $History: regc_lex.c $
|
1066 |
*
|
1067 |
* ***************** Version 1 *****************
|
1068 |
* User: Dtashley Date: 1/02/01 Time: 12:05a
|
1069 |
* Created in $/IjuScripter, IjuConsole/Source/Tcl Base
|
1070 |
* Initial check-in.
|
1071 |
*/
|
1072 |
|
1073 |
/* End of REGC_LEX.C */
|