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