|
|
1.1 root 1: /*
2: * This file contains all of the lexical analysis routines
3: * for the portable C compiler.
4: */
5: #ifdef vax
6: #include "INC$LIB:cc0.h"
7: #else
8: #include "cc0.h"
9: #endif
10:
11: /*
12: * Character classes.
13: * Indexed by ASCII character code.
14: */
15: unsigned char ct[] = {
16: JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK,
17: JUNK, SKIP, SKIP, SKIP, SKIP, SKIP, JUNK, JUNK,
18: JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK,
19: JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK, JUNK,
20: SKIP, NOT, STRING, SHARP, JUNK, REM, AND, QUOTE,
21: LPAREN, RPAREN, MUL, ADD, COMMA, SUB, DOT, DIV,
22: CON, CON, CON, CON, CON, CON, CON, CON,
23: CON, CON, COLON, SEMI, LT, ASSIGN, GT, QUEST,
24: JUNK, ID, ID, ID, ID, ID, ID, ID,
25: ID, ID, ID, ID, ID, ID, ID, ID,
26: ID, ID, ID, ID, ID, ID, ID, ID,
27: ID, ID, ID, LBRACK, BACKDIV,RBRACK, XOR, ID,
28: JUNK, ID, ID, ID, ID, ID, ID, ID,
29: ID, ID, ID, ID, ID, ID, ID, ID,
30: ID, ID, ID, ID, ID, ID, ID, ID,
31: ID, ID, ID, LBRACE, OR, RBRACE, COM, JUNK,
32: HIGH0, HIGH0, HIGH0, HIGH0, HIGH0, HIGH0, HIGH0, HIGH0,
33: HIGH0, HIGH0, HIGH0, HIGH0, HIGH0, HIGH0, HIGH0, HIGH0,
34: HIGH0, HIGH0, HIGH0, HIGH0, HIGH0, HIGH0, HIGH0, HIGH0,
35: HIGH0, HIGH0, HIGH0, HIGH0, HIGH0, HIGH0, HIGH0, HIGH0,
36: HIGH1, HIGH1, HIGH1, HIGH1, HIGH1, HIGH1, HIGH1, HIGH1,
37: HIGH1, HIGH1, HIGH1, HIGH1, HIGH1, HIGH1, HIGH1, HIGH1,
38: HIGH1, HIGH1, HIGH1, HIGH1, HIGH1, HIGH1, HIGH1, HIGH1,
39: HIGH1, HIGH1, HIGH1, HIGH1, HIGH1, HIGH1, HIGH1, HIGH1,
40: HIGH2, HIGH2, HIGH2, HIGH2, HIGH2, HIGH2, HIGH2, HIGH2,
41: HIGH2, HIGH2, HIGH2, HIGH2, HIGH2, HIGH2, HIGH2, HIGH2,
42: HIGH2, HIGH2, HIGH2, HIGH2, HIGH2, HIGH2, HIGH2, HIGH2,
43: HIGH2, HIGH2, HIGH2, HIGH2, HIGH2, HIGH2, HIGH2, HIGH2,
44: HIGH3, HIGH3, HIGH3, HIGH3, HIGH3, HIGH3, HIGH3, HIGH3,
45: HIGH3, HIGH3, HIGH3, HIGH3, HIGH3, HIGH3, HIGH3, HIGH3,
46: HIGH3, HIGH3, HIGH3, HIGH3, HIGH3, HIGH3, HIGH3, HIGH3,
47: HIGH3, HIGH3, HIGH3, HIGH3, HIGH3, HIGH3, HIGH3, HIGH3
48: };
49:
50: /*
51: * Read and decode the next token of the input.
52: * The token is returned and stored in 's'.
53: * Identifiers are packed into 'id'
54: * and their hash table slot is stashed in 'idhash'.
55: * Integers are returned in 'ival',
56: * long integers in 'lval' and doubles in 'dval'.
57: */
58: lex()
59: {
60: register SYM *sp;
61: register int c;
62: register int n;
63:
64: for (;;) {
65: if ((c=get()) < 0)
66: return (s = EOF);
67: switch (s = ct[c]) {
68:
69: case SKIP:
70: continue;
71:
72: case QUOTE:
73: n = 0;
74: lval = 0;
75: while ((c = getmap('\'')) >= 0) {
76: lval <<= 8;
77: lval |= c;
78: ++n;
79: }
80: ival = lval;
81: tval = T_INT;
82: s = ICON;
83: #if 0
84: switch (n) {
85: case 0:
86: cwarn("empty character constant");
87: break;
88: case 2:
89: cwarn("multiple character constant");
90: tval = T_INT;
91: break;
92: case 1:
93: break;
94: case 3:
95: case 4:
96: cwarn("character constant promoted to long");
97: tval = T_LONG;
98: s = LCON;
99: break;
100: default:
101: cerror("character constant overflows long");
102: tval = T_LONG;
103: s = LCON;
104: break;
105: }
106: #else
107: if (n != 1)
108: cerror("multiple character constant");
109: #endif
110: break;
111:
112: case ADD:
113: if (nextis('+'))
114: s = INCBEF;
115: break;
116:
117: case SUB:
118: if (nextis('-'))
119: s = DECBEF;
120: else if (nextis('>'))
121: s = ARROW;
122: break;
123:
124: case LT:
125: if (nextis('='))
126: s = LE;
127: else if (nextis('<'))
128: s = SHL;
129: break;
130:
131: case GT:
132: if (nextis('='))
133: s = GE;
134: else if (nextis('>'))
135: s = SHR;
136: break;
137:
138: case ASSIGN:
139: if (nextis('='))
140: s = EQ;
141: break;
142:
143: case NOT:
144: if (nextis('='))
145: s = NE;
146: break;
147:
148: case AND:
149: if (nextis('&'))
150: s = ANDAND;
151: break;
152:
153: case OR:
154: if (nextis('|'))
155: s = OROR;
156: break;
157:
158: case DOT:
159: c = get();
160: if (c<0 || ct[c]!=CON) {
161: unget(c);
162: break;
163: }
164: getnum(c, 1);
165: break;
166:
167: case CON:
168: getnum(c, 0);
169: break;
170:
171: case ID:
172: if (expand(c))
173: continue;
174: for (sp = idp->t_sym; sp != NULL; sp = sp->s_sp)
175: if (sp->s_slevel == SL_KEY) {
176: s = sp->s_value;
177: break;
178: }
179: break;
180:
181: case JUNK:
182: case HIGH0:
183: case HIGH1:
184: case HIGH2:
185: case HIGH3:
186: cerror("illegal character (%d decimal)", c);
187: continue;
188:
189: }
190: if ((s>=ADD && s<=SHR) && nextis('='))
191: s += AADD-ADD;
192: return (s);
193: }
194: }
195:
196: /*
197: * Test if the next character in the input is 'n'.
198: * If it is, eat it up and return true;
199: * otherwise put it back and return false.
200: */
201: nextis(n) int n;
202: {
203: register int c;
204:
205: if ((c = get()) == n)
206: return (1);
207: unget(c);
208: return (0);
209: }
210:
211: /*
212: * Get the next non blank character from the input.
213: * This is for cpp, so we do not pass newline.
214: */
215: getnb()
216: {
217: register int c;
218:
219: while ((c = get())==' ' || c=='\t')
220: ;
221: return (c);
222: }
223:
224: /*
225: * Get the next non-skip character.
226: * Different from getnb() which chokes
227: * on newline.
228: */
229: getskip()
230: {
231: register int c;
232:
233: while ((c = get()) > 0 && ct[c] == SKIP)
234: ;
235: return c;
236: }
237:
238: /*
239: * Peek ahead in the input (ignoring whitespace)
240: * to see if the next character is 'n'.
241: * True return it it is.
242: * The character is left in the input stream.
243: * This routine is used to look for the ':' after labels
244: * and the '(' after undefined names in expressions.
245: */
246: spnextis(n) int n;
247: {
248: register int c;
249:
250: while ((c=get()) >= 0) {
251: if (ct[c] != SKIP) {
252: unget(c);
253: if (c == n)
254: return (1);
255: return (0);
256: }
257: }
258: return (0);
259: }
260:
261: /*
262: * This routine is like lex(), except that it correctly skips
263: * over any strings in the input.
264: * Used during error recovery.
265: */
266: skip()
267: {
268: if (s == STRING)
269: while (getmap('\"') >= 0)
270: ;
271: lex();
272: }
273:
274: /*
275: * Read the next character from a string or a character constant.
276: * Return -1 when either end of file or the delimiter 'd' is encountered.
277: */
278: getmap(d) int d;
279: {
280: register int c, n, v;
281:
282: if ((c=get()) == d)
283: return (-1);
284: if (c<0 || c=='\n') {
285: unget(c);
286: cerror("nonterminated string or character constant");
287: return (-1);
288: }
289: if (c == '\\') {
290: c = get();
291: switch (c) {
292:
293: case 'a':
294: c = '\07';
295: break;
296:
297: case 'b':
298: c = '\b';
299: break;
300:
301: case 'f':
302: c = '\f';
303: break;
304:
305: case 'n':
306: c = '\n';
307: break;
308:
309: case 'r':
310: c = '\r';
311: break;
312:
313: case 't':
314: c = '\t';
315: break;
316:
317: case 'v':
318: c = '\013';
319: break;
320:
321: case 'x':
322: notbook();
323: c = get();
324: n = 0;
325: v = 0;
326: while (++n<=3
327: && ( (c>='0' && c<='9')
328: || (c>='A' && c<='F')
329: || (c>='a' && c<='f') )) {
330: v <<= 4;
331: if (c>='0' && c<='9')
332: v += c - '0';
333: else if (c>='A' && c<='F')
334: v += c - 'A' + 10;
335: else
336: v += c - 'a' + 10;
337: c = get();
338: }
339: unget(c);
340: c = v;
341: break;
342:
343: case '0':
344: case '1':
345: case '2':
346: case '3':
347: case '4':
348: case '5':
349: case '6':
350: case '7':
351: n = 0;
352: v = 0;
353: while (++n<=3 && c>='0' && c<='7') {
354: v = (v<<3) + c - '0';
355: c = get();
356: }
357: unget(c);
358: c = v;
359: break;
360: }
361: }
362: return (c);
363: }
364:
365: /*
366: * Read an identifier into id[]
367: * and set idhash.
368: */
369: getid(ch) int ch;
370: {
371: {
372: register char *p;
373: register int c;
374: c = ch;
375: p = id;
376: idhash = 0;
377: idsize = 0;
378: idhide = -1; /* Universal */
379: do {
380: if (p < &id[NCSYMB-1]) {
381: *p++ = c;
382: idhash += c;
383: idsize += 1;
384: }
385: if ((c = get()) >= SET0) {
386: idhide = hideint(c, idhide);
387: c = get();
388: }
389: } while (c>=0 && (ct[c]==ID || ct[c]==CON));
390: unget(c);
391: if (idhide == -1)
392: idhide = SET0; /* Empty */
393: *p++ = 0;
394: *p++ = 0;
395: *p++ = 0;
396: }
397: {
398: register TOK *tp, **tpp;
399:
400: idhash %= NHASH;
401: for (tpp = hash0+idhash; (tp = *tpp) != NULL; tpp = &tp->t_tp)
402: if (ideq(tp))
403: break;
404: if (tp == NULL)
405: *tpp = tp = newtoken();
406: idp = tp;
407: }
408: }
409:
410: setid(cp) char *cp;
411: {
412: {
413: register char *p1, *p2;
414: register int c;
415:
416: p1 = cp;
417: p2 = id;
418: idhash = 0;
419: idsize = 0;
420: while (c = *p1++) {
421: if (p2 < &id[NCSYMB-1]) {
422: *p2++ = c;
423: idhash += c;
424: idsize += 1;
425: }
426: }
427: *p2 = 0;
428: }
429: {
430: register TOK *tp, **tpp;
431:
432: idhash %= NHASH;
433: for (tpp = hash0+idhash; (tp = *tpp) != NULL; tpp = &tp->t_tp)
434: if (ideq(tp))
435: break;
436: if (tp == NULL)
437: *tpp = tp = newtoken();
438: idp = tp;
439: }
440: }
441:
442: /*
443: * Read number into id[].
444: * Set 's' appropriately.
445: */
446: getnum(c, dotf) register int c; int dotf;
447: {
448: register char *np;
449: int expf, sgnf, ntlf, base;
450: int islong, isunsigned, isfloat;
451: long n;
452: static char ulong[] = "unsigned long";
453: # define slong (ulong+9)
454: #if NATIVEFP
455: double d;
456: char *cp, *dp;
457: extern double atof();
458: #endif
459:
460: expf = 0;
461: ntlf = 0;
462: sgnf = 1;
463: base = 10;
464: islong = 0;
465: isunsigned = 0;
466: isfloat = 0;
467: np = id;
468: n = 0;
469: if (dotf)
470: *np++ = '.';
471: if (dotf==0 && c=='0') {
472: base = 8;
473: if ((c = get()) == 'x' || c == 'X') {
474: *np++ = '0';
475: *np++ = c;
476: base = 16;
477: c = get();
478: } else {
479: unget(c);
480: c = '0';
481: }
482: }
483: do {
484: if (base!=16 && c=='.') {
485: if (dotf++)
486: break;
487: } else if (c=='+' || c=='-') {
488: if (sgnf++)
489: break;
490: } else if (base!=16 && (c=='e' || c=='E')) {
491: if (expf++)
492: break;
493: sgnf = 0;
494: } else if (c<'0' || c>'9') {
495: if (base != 16)
496: break;
497: if (!((c>='A' && c<='F') || (c>='a' && c<='f')))
498: break;
499: } else
500: ++sgnf;
501: if (np < &id[NCSYMB-1])
502: *np++ = c;
503: else
504: ntlf = 1;
505: if (base == 8)
506: n <<= 3;
507: else if (base == 10)
508: n = (n<<3) + (n<<1);
509: else
510: n <<= 4;
511: if (c>='A' && c<='F')
512: c -= 'A'-10;
513: else if (c>='a' && c<='f')
514: c -= 'a'-10;
515: else
516: c -= '0';
517: n += c;
518: } while ((c = get()) >= 0);
519: for (;;) {
520: if (c=='l' || c=='L') {
521: ++islong;
522: *np++ = c;
523: c = get();
524: } else if (c == 'u' || c == 'U') {
525: ++isunsigned;
526: *np++ = c;
527: c = get();
528: } else if (c == 'f' || c == 'F') {
529: ++isfloat;
530: *np++ = c;
531: c = get();
532: } else {
533: unget(c);
534: *np = 0;
535: break;
536: }
537: }
538: s = ICON;
539: tval = T_INT;
540: ival = lval = n;
541: if (ntlf) {
542: cerror("number has too many digits");
543: return;
544: }
545: if (dotf || expf || isfloat) {
546: if (isunsigned || (isfloat+islong > 1)) {
547: cerror("illegal floating constant suffix");
548: return;
549: }
550: tval = isfloat ? T_FLOAT : islong ? T_LDOUBLE : T_DOUBLE;
551: #if NATIVEFP
552: d = atof(id);
553: for (dp = (char *)dval, cp = ((char *)&d)+sizeof(double)-1; cp >= &d; )
554: *dp++ = *cp--;
555: #else
556: dvalread((char *)dval, id);
557: #endif
558: s = DCON;
559: return;
560: }
561: if (isunsigned > 1 || islong > 1) {
562: cerror("illegal integer constant suffix");
563: return;
564: }
565: np = NULL;
566: if (islong) {
567: s = LCON;
568: tval = T_LONG;
569: if (isunsigned || (n&SLMASK) != 0)
570: tval = T_ULONG;
571: } else if (isunsigned) {
572: tval = T_UINT;
573: if ((n&UIMASK) != 0) {
574: s = LCON;
575: tval = T_ULONG;
576: np = ulong;
577: }
578: } else if (base == 10 && (n&SIMASK) != 0) {
579: s = LCON;
580: tval = T_LONG;
581: np = slong;
582: if ((n&SLMASK) != 0) {
583: tval = T_ULONG;
584: np = ulong;
585: }
586: } else if ((n&SIMASK) != 0) {
587: tval = T_UINT;
588: if ((n&UIMASK) != 0) {
589: s = LCON;
590: tval = T_LONG;
591: np = slong;
592: if ((n&SLMASK) != 0) {
593: tval = T_ULONG;
594: np = ulong;
595: }
596: }
597: }
598: if (tval == T_ULONG) {
599: /* Test for unsigned long overflow */
600: /* and set np = NULL if a diagnostic is given */
601: ;
602: }
603: if (incpp == 0 && np != NULL && isvariant(VSLCON))
604: cwarn("\"%s\" promoted to %s", id, np);
605: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.