|
|
1.1 root 1: /*
2: * lex2.c
3: * lexical analyser and utilities
4: */
5: #include "lex.h"
6: #define CMAX 3
7:
8: char cbuf[CMAX];
9: int bufc = 0;
10: int lstchr = '\n';
11: int line = 0;
12:
13: char *
14: alloc(n)
15: register n;
16: {
17: register char *pc;
18:
19: if ((pc=malloc(n)) == NULL)
20: error(outmem);
21: return (pc);
22: }
23:
24: char *
25: ralloc(pc, n)
26: char *pc;
27: {
28: if ((pc=realloc(pc, n)) == NULL)
29: error(outmem);
30: return (pc);
31: }
32:
33: /*
34: * lexical ananlyser for regular expressions
35: */
36: yylex()
37: {
38: switch (yylval = next()) {
39: case '\\':
40: yylval = escape();
41: return (LX_CHAR);
42: case '"':
43: inquotes = 1-inquotes;
44: return (LX_OPER);
45: case EOF:
46: error(eoferr);
47: default:
48: if (inquotes)
49: if (yylval == '\n')
50: error("%s in quoted string", illnln);
51: else
52: return (LX_CHAR);
53: }
54: switch (yylval) {
55: case '[':
56: yylval = getclas();
57: return (LX_CLAS);
58: case '.':
59: return (LX_ANYC);
60: case ' ':
61: case '\t':
62: case '\n':
63: return (LX_TERM);
64: case '/':
65: return (indefs? LX_OPER : LX_TERM);
66: case '$':
67: if (!indefs && isspace(look(0)))
68: return (LX_TERM);
69: case '^':
70: case '<':
71: case '(':
72: case ')':
73: case '{':
74: case '*':
75: case '?':
76: case '+':
77: case '|':
78: return (LX_OPER);
79: default:
80: if (!isascii(yylval) || iscntrl(yylval))
81: error("%s in regular expression", illchr);
82: return (LX_CHAR);
83: }
84: }
85:
86: /*
87: * get a backslashed character
88: */
89: escape()
90: {
91: register c, i;
92:
93: switch (c = next()) {
94: case 'b':
95: return ('\b');
96: case 'f':
97: return ('\f');
98: case 'n':
99: return ('\n');
100: case 'r':
101: return ('\r');
102: case 't':
103: return ('\t');
104: default:
105: if (isoctl(c)) {
106: for (i=0; c-='0', i<2 && isoctl(look(0)); ++i)
107: c = c * 8 + next();
108: if (c > MAXUCHAR)
109: error(illoct);
110: }
111: return (c);
112: }
113: }
114:
115: /*
116: * read and store a class specification
117: */
118: getclas()
119: {
120: register unsigned c,d;
121: register unsigned char *index;
122: register bit;
123: register invert;
124:
125: if (clas == 0) {
126: classptr = alloc(MAXUCHAR+1);
127: index = classptr + (c = MAXUCHAR + 1);
128: while (c--)
129: *--index = 0;
130: } else if ((clas % NBCHAR) == 0) {
131: c = classindex(clas + NBCHAR);
132: classptr = ralloc(classptr, c);
133: index = classptr + c;
134: c = MAXUCHAR + 1;
135: while (c--)
136: *--index = 0;
137: } else
138: index = classptr + classindex(clas);
139: bit = classbit(clas);
140: if (look(0) == '^') {
141: invert = 1;
142: next();
143: } else
144: invert = 0;
145: while ((c=next()) != ']') {
146: if (iscntrl(c))
147: error("%s in class", illchr);
148: if (c == EOF)
149: error(eoferr);
150: if (c == '.') {
151: c = index['\n'] & bit;
152: for (d=0; d<=MAXUCHAR; ++d)
153: index[d] |= bit;
154: if (!c)
155: index['\n'] ^= bit;
156: } else {
157: if (c == '\\')
158: c = escape();
159: d = c;
160: if (look(0) == '-')
161: if (next(), look(0) != ']') {
162: if ((d=next()) == '\\')
163: d = escape();
164: if (d < c)
165: error(illrng);
166: } else
167: index['-'] |= bit;
168: do {
169: index[c] |= bit;
170: } while (c++ < d);
171: }
172: }
173: if (invert) {
174: for (d=0; d<=MAXUCHAR; ++d)
175: index[d] ^= bit;
176: }
177: return (clas++);
178: }
179:
180: /*
181: * get next character from input
182: */
183: next()
184: {
185: static l = '\n';
186: register c, i;
187:
188: if (l == '\n')
189: ++line;
190: if (bufc == 0)
191: c = lstchr = getc(filein);
192: else {
193: c = cbuf[0];
194: for (i=1; i < bufc; i++)
195: cbuf[i-1] = cbuf[i];
196: --bufc;
197: }
198: return (l=c);
199: }
200:
201: /*
202: * look into input for the n+1th character
203: * practically, n never exceeds 2
204: */
205: look(n)
206: register n;
207: {
208: while (bufc <= n)
209: cbuf[bufc++] = lstchr = getc(filein);
210: return (cbuf[n]);
211: }
212:
213: /*
214: * delete input up to and including the next newline
215: */
216: dnl()
217: {
218: while (next() != '\n')
219: ;
220: setltype();
221: }
222:
223: /*
224: * eat up white space
225: */
226: eatspc()
227: {
228: register c;
229:
230: while (c=look(0), c==' ' || c=='\t')
231: next();
232: if (c == EOF)
233: error(eoferr);
234: }
235:
236: /*
237: * eat input until white space
238: */
239: eatlbl()
240: {
241: register c;
242:
243: while (c=look(0), !isspace(c))
244: next();
245: if (c == '\n')
246: return (1);
247: return (0);
248: }
249:
250: /*
251: * copy an input line to the output file
252: */
253: lcopy()
254: {
255: register c;
256:
257: do {
258: putc(c=next(), fileout);
259: } while (c != '\n');
260: setltype();
261: }
262:
263: /*
264: * set external variable ltype to the type of the next line
265: */
266: setltype()
267: {
268: ltype = getltype();
269: }
270:
271: /*
272: * return line type based on the first couple of characters
273: */
274: getltype()
275: {
276: switch (look(0)) {
277: case '\t':
278: case '\n':
279: case ' ':
280: return (LN_LSPC);
281: case EOF:
282: return (LN_EOFL);
283: case '%':
284: switch (look(1)) {
285: case '%':
286: return (LN_DLIM);
287: case '{':
288: return (LN_LCOM);
289: case '}':
290: return (LN_RCOM);
291: case 's':
292: case 'S':
293: return (LN_SCON);
294: case 'c':
295: case 'C':
296: return (LN_CTXT);
297: case 'x':
298: case 'X':
299: return (LN_OPTN);
300: }
301: }
302: return (LN_DFLT);
303: }
304:
305: /*
306: * put out a #line command for the C preprocessor
307: */
308: outlnum(i)
309: {
310: loutput(0, "#line %d", line+i);
311: }
312:
313: /*
314: * copy a user-specified action to the output
315: */
316: getactn()
317: {
318: enum cstate { /* states of c source */
319: start, slash, comment, star, bsl, dquote, squote
320: } pstate;
321: register enum cstate state;
322: register c;
323: int bct;
324:
325: for (state = start, bct = 0;;) {
326: if (EOF == (c = next()))
327: error(eoferr);
328: putc(c, fileout);
329:
330: switch (state) {
331: case slash: /* maybe a comment */
332: if ('*' == c) {
333: state = comment;
334: break;
335: }
336: state = start;
337: case start: /* normal text state */
338: switch (c) {
339: case '/':
340: state = slash;
341: break;
342: case '\\':
343: pstate = state;
344: state = bsl;
345: break;
346: case '"':
347: state = dquote;
348: break;
349: case '\'':
350: state = squote;
351: break;
352: case '{':
353: bct++;
354: break;
355: case '}':
356: if (--bct < 0)
357: error(actsyn);
358: break;
359: case '\n':
360: if (!bct) {
361: setltype();
362: return;
363: }
364: }
365: break;
366: case star: /* saw * in comment */
367: if ('/' == c) {
368: state = start;
369: break;
370: }
371: state = comment;
372: case comment: /* in comment */
373: if ('*' == c)
374: state = star;
375: break;
376: case bsl: /* char after backslash */
377: state = pstate;
378: break;
379: case dquote: /* in double quoted string */
380: case squote: /* in single quoted string */
381: switch (c) {
382: case '"':
383: if (dquote == state)
384: state = start;
385: break;
386: case '\'':
387: if (squote == state)
388: state = start;
389: break;
390: case '\n':
391: error(actsyn);
392: break;
393: case '\\':
394: pstate = state;
395: state = bsl;
396: }
397: }
398: }
399: }
400:
401: /*
402: * read an identifier
403: */
404: char *
405: getident()
406: {
407: register c, i = 0;
408: register char *pc;
409:
410: eatspc();
411: pc = alloc(NCBLK);
412: while (c=look(0), isalnum(c) || c=='_') {
413: pc[i++] = next();
414: if (i%NCBLK == 0)
415: pc = ralloc((char *)pc, i+NCBLK);
416: }
417: pc[i] = '\0';
418: eatspc();
419: return (pc);
420: }
421:
422: /*
423: * interpret an identifier as the name of a
424: * start condition, try to return its value
425: */
426: getstart()
427: {
428: register struct def *pd;
429: register char *pc;
430:
431: pd = scnstart;
432: pc = getident();
433: do {
434: if (strcmp(pc, pd->d_name) == 0) {
435: free(pc);
436: return (pd->d_data);
437: }
438: } while ((pd=pd->d_next) != NULL);
439: error(undstc);
440: }
441:
442: /*
443: * add a string of identifiers to the start condition
444: * list, numbering them as we go, too bad if they
445: * are duplicates
446: */
447: addstart()
448: {
449: register struct def *pd;
450:
451: if (eatlbl())
452: return;
453: pd = scnstart;
454: while (look(0) != '\n') {
455: pd->d_next = alloc(sizeof(struct def));
456: pd->d_next->d_data = pd->d_data + 1;
457: pd = pd->d_next;
458: pd->d_next = NULL;
459: pd->d_name = getident();
460: }
461: }
462:
463: /*
464: * like addstart, except with names of contexts
465: */
466: addcontext()
467: {
468: register struct def *pd;
469:
470: if (eatlbl())
471: return;
472: pd = ctxstart;
473: while (pd->d_next != NULL)
474: pd = pd->d_next;
475: pd->d_next = alloc(sizeof(struct def));
476: pd = pd->d_next;
477: for (;;) {
478: pd->d_name = getident();
479: pd->d_data = 0;
480: if (look(0) == '\n') {
481: pd->d_next = NULL;
482: break;
483: } else {
484: pd->d_next = alloc(sizeof(struct def));
485: pd = pd->d_next;
486: }
487: }
488: }
489:
490: /*
491: * this is called to mark the context name with its
492: * associated section of the nfa
493: */
494: markcontext(t)
495: {
496: register char *pc;
497: register struct def *pd;
498:
499: eatlbl();
500: pc = getident();
501: pd = ctxstart;
502: while ((pd=pd->d_next) != NULL)
503: if (strcmp(pc, pd->d_name) == 0) {
504: pd->d_data = t;
505: free(pc);
506: return;
507: }
508: error(undctx);
509: }
510:
511: /*
512: * read the name of the definition, try
513: * to return where it starts
514: */
515: getdefn()
516: {
517: register char *pc;
518: register struct def *pd;
519:
520: pc = getident();
521: if (look(0) == '}')
522: next();
523: else
524: error("%s in definition name", illchr);
525: for (pd=defstart; pd!=NULL; pd=pd->d_next)
526: if (strcmp(pc, pd->d_name) == 0) {
527: free(pc);
528: return (pd->d_data);
529: }
530: error(unddef);
531: }
532:
533: /*
534: * recursive, costly but elegant
535: */
536: freedef(pd)
537: register struct def *pd;
538: {
539: if (pd != NULL) {
540: freedef(pd->d_next);
541: if (pd->d_name != NULL)
542: free(pd->d_name);
543: free((char *)pd);
544: }
545: }
546:
547: /*
548: * cleanup and abort
549: */
550: /* VARARGS */
551: error(s)
552: {
553: fprintf(stderr, "lex: ");
554: if (line)
555: fprintf(stderr, "%d: ", line);
556: fprintf(stderr, "%r\n", &s);
557: if (filein == stdin)
558: while (lstchr!='\n' && lstchr!=EOF)
559: next();
560: if (fileout != stdout)
561: unlink(OUTFILE);
562: exit (1);
563: }
564:
565: usage()
566: {
567: fprintf(stderr, "Usage: lex [-tv] [filename]\n");
568: exit (1);
569: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.