|
|
1.1 root 1: /*
2: * The lexical analyzer.
3: */
4:
5: #include "itran.h"
6: #include "token.h"
7: #include "lex.h"
8: #include "char.h"
9: #include "tree.h"
10:
11: int tline;
12: int tcol;
13:
14: /*
15: * yylex - find the next token in the input stream, and return its token
16: * type and value to the parser.
17: *
18: * Variables of interest:
19: *
20: * cc - character following last token.
21: * comflag - set if in a comment.
22: * nlflag - set if a newline was between the last token and the current token
23: * lastend - set if the last token was an Ender.
24: * lastval - when a semicolon is inserted and returned, lastval gets the
25: * token value that would have been returned if the semicolon hadn't
26: * been inserted.
27: */
28:
29: yylex()
30: {
31: register struct toktab *t;
32: register int c;
33: int nlflag;
34: int comflag;
35: static struct toktab *lasttok = NULL;
36: static nodeptr lastval;
37: static int lastend = 0;
38: static int eofflag = 0;
39: static int lastline = 0;
40: static int cc = '\n';
41: extern struct toktab *getident(), *getnum(), *getstring(), *getop();
42:
43: if (lasttok != NULL) {
44: /*
45: * A semicolon was inserted and returned on the last call to yylex,
46: * instead of going to the input, return lasttok and set the
47: * appropriate variables.
48: */
49: yylval = lastval;
50: tline = Line(lastval);
51: tcol = Col(lastval);
52: t = lasttok;
53: goto ret;
54: }
55: nlflag = 0;
56: comflag = 0;
57: loop:
58: c = cc;
59: /*
60: * Skip whitespace and comments.
61: */
62: while (c != EOF && (comflag || c == Comment || isspace(c))) {
63: if (c == '\n') {
64: nlflag++;
65: comflag = 0;
66: }
67: else if (c == Comment)
68: comflag++;
69: c = NextChar;
70: }
71: /*
72: * A token is the next thing in the input. Record the last line number
73: * and set tline and tcol to the current line and column.
74: */
75: lastline = tline;
76: tline = inline;
77: tcol = incol;
78:
79: if (c == EOF) {
80: /*
81: * End of file has been reached. Set eofflag, return T_Eof, and
82: * set cc to EOF so that any subsequent scans also return T_Eof.
83: */
84: if (eofflag++) {
85: eofflag = 0;
86: cc = '\n';
87: return (int) (yylval = 0);
88: }
89: cc = EOF;
90: t = T_Eof;
91: yylval = 0;
92: goto ret;
93: }
94:
95: /*
96: * Look at current input character to determine what class of token
97: * is next and take the appropriate action. Note that the various
98: * token gathering routines write a value into cc.
99: */
100: c = ctran[c];
101: if (isalpha(c)) { /* gather ident or reserved word */
102: if ((t = getident(c, &cc)) == NULL)
103: goto loop;
104: }
105: else if (isdigit(c)) { /* gather numeric literal */
106: if ((t = getnum(c, &cc)) == NULL)
107: goto loop;
108: }
109: else if (c == '"' || c == '\'') { /* gather string or cset literal */
110: if ((t = getstring(c, &cc)) == NULL)
111: goto loop;
112: }
113: else { /* gather longest legal operator */
114: if ((t = getop(c, &cc)) == NULL)
115: goto loop;
116: yylval = OpNode(t->t_type);
117: }
118: if (nlflag && lastend && (t->t_flags & Beginner)) {
119: /*
120: * A newline was encountered between the current token and the last,
121: * the last token was an Ender, and the current token is a Beginner.
122: * Return a semicolon and save the current token in lastval.
123: */
124: lastval = yylval;
125: lasttok = t;
126: tline = lastline;
127: tcol = 0;
128: yylval = OpNode(SEMICOL);
129: return SEMICOL;
130: }
131: ret:
132: /*
133: * Clear lasttok, set lastend if the token being returned is an
134: * Ender, and return the token.
135: */
136: lasttok = 0;
137: lastend = t->t_flags & Ender;
138: return (t->t_type);
139: }
140:
141: /*
142: * getident - gather an identifier beginning with ac. The character
143: * following identifier goes in cc.
144: */
145:
146: struct toktab *getident(ac, cc)
147: char ac;
148: int *cc;
149: {
150: register c;
151: register char *p;
152: register struct toktab *t;
153: extern char *putident();
154: extern struct toktab *findres();
155:
156: c = ac;
157: p = strfree;
158: /*
159: * Copy characters into string space until a non-alphanumeric character
160: * is found.
161: */
162: do {
163: if (p >= send)
164: syserr("out of string space");
165: *p++ = c;
166: c = ctran[NextChar];
167: } while (isalnum(c));
168: if (p >= send)
169: syserr("out of string space");
170: *p++ = 0;
171: *cc = c;
172: /*
173: * If the identifier is a reserved word, make a ResNode for it and return
174: * the token value. Otherwise, install it with putident, make an
175: * IdNode for it, and return.
176: */
177: if ((t = findres()) != NULL) {
178: yylval = ResNode(t->t_type);
179: return t;
180: }
181: else {
182: yylval = IdNode((int)putident(p-strfree));
183: return T_Ident;
184: }
185: }
186:
187: /*
188: * findres - if the string just copied into the string space by getident
189: * is a reserved word, return a pointer to its entry in the token table.
190: * Return NULL if the string isn't a reserved word.
191: */
192:
193: struct toktab *findres()
194: {
195: register struct toktab *t;
196: register char c, *p;
197:
198: p = strfree;
199: c = *p;
200: if (!islower(c))
201: return NULL;
202: /*
203: * Point t at first reserved word that starts with c (if any).
204: */
205: if ((t = restab[c - '_']) == NULL)
206: return NULL;
207: /*
208: * Search through reserved words, stopping when a match is found
209: * or when the current reserved word doesn't start with c.
210: */
211: while (t->t_word[0] == c) {
212: if (strcmp(t->t_word, p) == 0)
213: return t;
214: t++;
215: }
216: return NULL;
217: }
218:
219: /*
220: * getnum - gather a numeric literal starting with ac and put the
221: * character following the literal into *cc.
222: */
223:
224: struct toktab *getnum(ac, cc)
225: char ac;
226: int *cc;
227: {
228: register c;
229: register r;
230: register state;
231: char *p;
232: int realflag;
233: extern char *putident();
234:
235: c = ac;
236: r = tonum(c);
237: p = strfree;
238: state = 0;
239: realflag = 0;
240: for (;;) {
241: if (p >= send)
242: syserr("out of string space");
243: *p++ = c;
244: c = ctran[NextChar];
245: switch (state) {
246: case 0: /* integer part */
247: if (isdigit(c)) { r = r * 10 + tonum(c); continue; }
248: if (c == '.') { state = 1; realflag++; continue; }
249: if (tolower(c) == 'e') { state = 2; realflag++; continue; }
250: if (tolower(c) == 'r') {
251: state = 5;
252: if (r < 2 || r > 36)
253: err("invalid radix for integer literal", 0);
254: continue;
255: }
256: break;
257: case 1: /* fractional part */
258: if (isdigit(c)) continue;
259: if (tolower(c) == 'e') { state = 2; continue; }
260: break;
261: case 2: /* optional exponent sign */
262: if (c == '+' || c == '-') { state = 3; continue; }
263: case 3: /* first digit after e, e+, or e- */
264: if (isdigit(c)) { state = 4; continue; }
265: err("invalid real literal", 0);
266: break;
267: case 4: /* remaining digits after e */
268: if (isdigit(c)) continue;
269: break;
270: case 5: /* first digit after r */
271: if ((isdigit(c) || isletter(c)) && tonum(c) < r)
272: { state = 6; continue; }
273: err("invalid integer literal", 0);
274: break;
275: case 6: /* remaining digits after r */
276: if (isdigit(c) || isletter(c)) {
277: if (tonum(c) >= r) { /* illegal digit for radix r */
278: err("invalid digit in integer literal", 0);
279: r = tonum('z'); /* prevent more messages */
280: }
281: continue;
282: }
283: break;
284: }
285: break;
286: }
287: if (p >= send)
288: syserr("out of string space");
289: *p++ = 0;
290: *cc = c;
291: if (realflag) {
292: yylval = RealNode((int)putident(p-strfree));
293: return T_Real;
294: }
295: yylval = IntNode((int)putident(p-strfree));
296: return T_Int;
297: }
298:
299: /*
300: * getstring - gather a string literal starting with ac and place the
301: * character following the literal in *cc.
302: */
303:
304: struct toktab *getstring(ac, cc)
305: char ac;
306: int *cc;
307: {
308: register c, sc;
309: register char *p;
310: char *lc;
311: extern char *putident();
312: int len;
313:
314: sc = c = ac;
315: p = strfree;
316: lc = 0;
317: while ((c = NextChar) != sc && c != '\n' && c != EOF) {
318: contin:
319: if (c == '_')
320: lc = p;
321: else if (!isspace(c))
322: lc = 0;
323: if (ctran[c] == Escape) {
324: c = NextChar;
325: if (isoctal(c))
326: c = octesc(c);
327: else if (ctran[c] == 'x')
328: c = hexesc();
329: else if (ctran[c] == '^')
330: c = ctlesc();
331: else
332: c = esctab[c];
333: if (c == EOF)
334: goto noquote;
335: }
336: if (p >= send)
337: syserr("out of string space");
338: *p++ = c;
339: }
340: if (p >= send)
341: syserr("out of string space");
342: *p++ = 0;
343: if (c == sc)
344: *cc = ' ';
345: else {
346: if (c == '\n' && lc) {
347: p = lc;
348: while ((c = NextChar) != EOF && isspace(c)) ;
349: if (c != EOF)
350: goto contin;
351: }
352: noquote:
353: err("unclosed quote", 0);
354: *cc = c;
355: }
356: if (ac == '"') { /* a string literal */
357: len = p - strfree;
358: yylval = StrNode((int)putident(len), len);
359: return T_String;
360: }
361: else { /* a cset literal */
362: len = p - strfree;
363: yylval = CsetNode((int)putident(len), len);
364: return T_Cset;
365: }
366: }
367:
368: /*
369: * ctlesc - translate a control escape -- backslash followed by
370: * caret and one character.
371: */
372:
373: ctlesc()
374: {
375: register c;
376:
377: c = NextChar;
378: if (c == EOF)
379: return EOF;
380: return (c & 037);
381: }
382:
383: /*
384: * octesc - translate an octal escape -- backslash followed by
385: * one, two, or three octal digits.
386: */
387:
388: octesc(ac)
389: char ac;
390: {
391: register c, nc, i;
392:
393: c = 0;
394: nc = ac;
395: i = 1;
396: do {
397: c = (c << 3) | (nc - '0');
398: nc = NextChar;
399: if (nc == EOF)
400: return EOF;
401: } while (isoctal(nc) && i++ < 3);
402: PushChar(nc);
403: return (c & 0377);
404: }
405:
406: /*
407: * hexesc - translate a hexadecimal escape -- backslash-x
408: * followed by one or two hexadecimal digits.
409: */
410:
411: hexesc()
412: {
413: register c, nc, i;
414:
415: c = 0;
416: i = 0;
417: while (i++ < 2) {
418: nc = NextChar;
419: if (nc == EOF)
420: return EOF;
421: if (nc >= 'a' && nc <= 'f')
422: nc -= 'a' - 10;
423: else if (nc >= 'A' && nc <= 'F')
424: nc -= 'A' - 10;
425: else if (isdigit(nc))
426: nc -= '0';
427: else {
428: PushChar(nc);
429: break;
430: }
431: c = (c << 4) | nc;
432: }
433: return c;
434: }
435:
436: /*
437: * getop - find the longest legal operator and return a pointer
438: * to its entry in the token table. The tour describes the
439: * operator recognition process in detail.
440: */
441:
442: struct toktab *getop(ac, cc)
443: char ac;
444: int *cc;
445: {
446: register struct optab *state;
447: register char c, i;
448:
449: state = state0;
450: c = ac;
451: for (;;) {
452: while ((i = state->o_input) && c != i)
453: state++;
454: switch (state->o_action) {
455: case A_Goto:
456: state = (struct optab *) state->o_val;
457: c = ctran[NextChar];
458: continue;
459: case A_Error:
460: err("invalid character", 0);
461: *cc = ' ';
462: return NULL;
463: case A_Return:
464: *cc = c;
465: return (struct toktab *) (state->o_val);
466: case A_Immret:
467: *cc = ' ';
468: return (struct toktab *) (state->o_val);
469: }
470: }
471: }
472:
473: /*
474: * nextchar - return the next character in the input.
475: */
476:
477: nextchar()
478: {
479: register int c;
480:
481: if (c = peekc) {
482: peekc = 0;
483: return c;
484: }
485: c = getc(infile);
486: switch (c) {
487: case EOF:
488: if (incol) {
489: c = '\n';
490: inline++;
491: incol = 0;
492: peekc = EOF;
493: break;
494: }
495: else {
496: inline = 0;
497: incol = 0;
498: break;
499: }
500: case '\n':
501: inline++;
502: incol = 0;
503: break;
504: case '\t':
505: incol = (incol | 7) + 1;
506: break;
507: case '\b':
508: if (incol)
509: incol--;
510: break;
511: default:
512: incol++;
513: }
514: return c;
515: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.