|
|
1.1 ! root 1: /* Copyright (c) 1982 Regents of the University of California */ ! 2: ! 3: static char sccsid[] = "@(#)scanner.c 1.8 8/5/83"; ! 4: ! 5: /* ! 6: * Debugger scanner. ! 7: */ ! 8: ! 9: #include "defs.h" ! 10: #include "scanner.h" ! 11: #include "main.h" ! 12: #include "keywords.h" ! 13: #include "tree.h" ! 14: #include "symbols.h" ! 15: #include "names.h" ! 16: #include "y.tab.h" ! 17: ! 18: #ifndef public ! 19: typedef int Token; ! 20: #endif ! 21: ! 22: public String initfile = ".dbxinit"; ! 23: ! 24: typedef enum { WHITE, ALPHA, NUM, OTHER } Charclass; ! 25: ! 26: private Charclass class[256 + 1]; ! 27: private Charclass *lexclass = class + 1; ! 28: ! 29: #define isdigit(c) (lexclass[c] == NUM) ! 30: #define isalnum(c) (lexclass[c] == ALPHA or lexclass[c] == NUM) ! 31: #define ishexdigit(c) ( \ ! 32: isdigit(c) or (c >= 'a' and c <= 'f') or (c >= 'A' and c <= 'F') \ ! 33: ) ! 34: ! 35: #define MAXLINESIZE 1024 ! 36: ! 37: private File in; ! 38: private Char linebuf[MAXLINESIZE]; ! 39: private Char *curchar; ! 40: ! 41: #define MAXINCLDEPTH 10 ! 42: ! 43: private struct { ! 44: File savefile; ! 45: Filename savefn; ! 46: int savelineno; ! 47: } inclinfo[MAXINCLDEPTH]; ! 48: ! 49: private unsigned int curinclindex; ! 50: ! 51: private Token getident(); ! 52: private Token getnum(); ! 53: private Token getstring(); ! 54: private Boolean eofinput(); ! 55: private Char charcon(); ! 56: private Char charlookup(); ! 57: ! 58: private enterlexclass(class, s) ! 59: Charclass class; ! 60: String s; ! 61: { ! 62: register char *p; ! 63: ! 64: for (p = s; *p != '\0'; p++) { ! 65: lexclass[*p] = class; ! 66: } ! 67: } ! 68: ! 69: public scanner_init() ! 70: { ! 71: register Integer i; ! 72: ! 73: for (i = 0; i < 257; i++) { ! 74: class[i] = OTHER; ! 75: } ! 76: enterlexclass(WHITE, " \t"); ! 77: enterlexclass(ALPHA, "abcdefghijklmnopqrstuvwxyz"); ! 78: enterlexclass(ALPHA, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_$"); ! 79: enterlexclass(NUM, "0123456789"); ! 80: in = stdin; ! 81: errfilename = nil; ! 82: errlineno = 0; ! 83: curchar = linebuf; ! 84: linebuf[0] = '\0'; ! 85: } ! 86: ! 87: /* ! 88: * Read a single token. ! 89: * ! 90: * Input is line buffered. ! 91: * ! 92: * There are two "modes" of operation: one as in a compiler, ! 93: * and one for reading shell-like syntax. ! 94: */ ! 95: ! 96: private Boolean shellmode; ! 97: ! 98: public Token yylex() ! 99: { ! 100: register int c; ! 101: register char *p; ! 102: register Token t; ! 103: String line; ! 104: ! 105: p = curchar; ! 106: if (*p == '\0') { ! 107: do { ! 108: if (isterm(in)) { ! 109: printf("(%s) ", cmdname); ! 110: fflush(stdout); ! 111: } ! 112: line = fgets(linebuf, MAXLINESIZE, in); ! 113: } while (line == nil and not eofinput()); ! 114: if (line == nil) { ! 115: c = EOF; ! 116: } else { ! 117: p = linebuf; ! 118: while (lexclass[*p] == WHITE) { ! 119: p++; ! 120: } ! 121: shellmode = false; ! 122: } ! 123: } else { ! 124: while (lexclass[*p] == WHITE) { ! 125: p++; ! 126: } ! 127: } ! 128: curchar = p; ! 129: c = *p; ! 130: if (lexclass[c] == ALPHA) { ! 131: t = getident(); ! 132: } else if (lexclass[c] == NUM) { ! 133: if (shellmode) { ! 134: t = getident(); ! 135: } else { ! 136: t = getnum(); ! 137: } ! 138: } else { ! 139: ++curchar; ! 140: switch (c) { ! 141: case '\n': ! 142: t = '\n'; ! 143: if (errlineno != 0) { ! 144: errlineno++; ! 145: } ! 146: break; ! 147: ! 148: case '"': ! 149: case '\'': ! 150: t = getstring(); ! 151: break; ! 152: ! 153: case '.': ! 154: if (shellmode) { ! 155: --curchar; ! 156: t = getident(); ! 157: } else if (isdigit(*curchar)) { ! 158: --curchar; ! 159: t = getnum(); ! 160: } else { ! 161: t = '.'; ! 162: } ! 163: break; ! 164: ! 165: case '<': ! 166: if (not shellmode and *curchar == '<') { ! 167: ++curchar; ! 168: t = LFORMER; ! 169: } else { ! 170: t = '<'; ! 171: } ! 172: break; ! 173: ! 174: case '>': ! 175: if (not shellmode and *curchar == '>') { ! 176: ++curchar; ! 177: t = RFORMER; ! 178: } else { ! 179: t = '>'; ! 180: } ! 181: break; ! 182: ! 183: case '#': ! 184: if (*curchar == '^') { ! 185: ++curchar; ! 186: t = ABSTRACTION; ! 187: } else { ! 188: t = '#'; ! 189: } ! 190: break; ! 191: ! 192: case '-': ! 193: if (shellmode) { ! 194: --curchar; ! 195: t = getident(); ! 196: } else if (*curchar == '>') { ! 197: ++curchar; ! 198: t = ARROW; ! 199: } else { ! 200: t = '-'; ! 201: } ! 202: break; ! 203: ! 204: case EOF: ! 205: t = 0; ! 206: break; ! 207: ! 208: default: ! 209: if (shellmode and index("!&*()[]", c) == nil) { ! 210: --curchar; ! 211: t = getident(); ! 212: } else { ! 213: t = c; ! 214: } ! 215: break; ! 216: } ! 217: } ! 218: # ifdef LEXDEBUG ! 219: if (lexdebug) { ! 220: fprintf(stderr, "yylex returns "); ! 221: print_token(stderr, t); ! 222: fprintf(stderr, "\n"); ! 223: } ! 224: # endif ! 225: return t; ! 226: } ! 227: ! 228: /* ! 229: * Parser error handling. ! 230: */ ! 231: ! 232: public yyerror(s) ! 233: String s; ! 234: { ! 235: register Char *p, *tokenbegin, *tokenend; ! 236: register Integer len; ! 237: ! 238: if (streq(s, "syntax error")) { ! 239: beginerrmsg(); ! 240: tokenend = curchar - 1; ! 241: tokenbegin = tokenend; ! 242: while (lexclass[*tokenbegin] != WHITE and tokenbegin > &linebuf[0]) { ! 243: --tokenbegin; ! 244: } ! 245: len = tokenend - tokenbegin + 1; ! 246: p = tokenbegin; ! 247: if (p > &linebuf[0]) { ! 248: while (lexclass[*p] == WHITE and p > &linebuf[0]) { ! 249: --p; ! 250: } ! 251: } ! 252: if (p == &linebuf[0]) { ! 253: fprintf(stderr, "unrecognized command \"%.*s\"", len, tokenbegin); ! 254: } else { ! 255: fprintf(stderr, "syntax error"); ! 256: if (len != 0) { ! 257: fprintf(stderr, " on \"%.*s\"", len, tokenbegin); ! 258: } ! 259: } ! 260: enderrmsg(); ! 261: } else { ! 262: error(s); ! 263: } ! 264: } ! 265: ! 266: /* ! 267: * Eat the current line. ! 268: */ ! 269: ! 270: public gobble() ! 271: { ! 272: curchar = linebuf; ! 273: linebuf[0] = '\0'; ! 274: } ! 275: ! 276: /* ! 277: * Scan an identifier and check to see if it's a keyword. ! 278: */ ! 279: ! 280: private Token getident() ! 281: { ! 282: char buf[256]; ! 283: register Char *p, *q; ! 284: register Token t; ! 285: ! 286: p = curchar; ! 287: q = buf; ! 288: if (shellmode) { ! 289: do { ! 290: *q++ = *p++; ! 291: } while (index(" \t\n!&<>*[]()", *p) == nil); ! 292: } else { ! 293: do { ! 294: *q++ = *p++; ! 295: } while (isalnum(*p)); ! 296: } ! 297: curchar = p; ! 298: *q = '\0'; ! 299: yylval.y_name = identname(buf, false); ! 300: if (not shellmode) { ! 301: t = findkeyword(yylval.y_name); ! 302: if (t == nil) { ! 303: t = NAME; ! 304: } ! 305: } else { ! 306: t = NAME; ! 307: } ! 308: return t; ! 309: } ! 310: ! 311: /* ! 312: * Scan a number. ! 313: */ ! 314: ! 315: private Token getnum() ! 316: { ! 317: char buf[256]; ! 318: register Char *p, *q; ! 319: register Token t; ! 320: Integer base; ! 321: ! 322: p = curchar; ! 323: q = buf; ! 324: if (*p == '0') { ! 325: if (*(p+1) == 'x') { ! 326: p += 2; ! 327: base = 16; ! 328: } else { ! 329: base = 8; ! 330: } ! 331: } else { ! 332: base = 10; ! 333: } ! 334: if (base == 16) { ! 335: do { ! 336: *q++ = *p++; ! 337: } while (ishexdigit(*p)); ! 338: } else { ! 339: do { ! 340: *q++ = *p++; ! 341: } while (isdigit(*p)); ! 342: } ! 343: if (*p == '.') { ! 344: do { ! 345: *q++ = *p++; ! 346: } while (isdigit(*p)); ! 347: if (*p == 'e' or *p == 'E') { ! 348: p++; ! 349: if (*p == '+' or *p == '-' or isdigit(*p)) { ! 350: *q++ = 'e'; ! 351: do { ! 352: *q++ = *p++; ! 353: } while (isdigit(*p)); ! 354: } ! 355: } ! 356: *q = '\0'; ! 357: yylval.y_real = atof(buf); ! 358: t = REAL; ! 359: } else { ! 360: *q = '\0'; ! 361: switch (base) { ! 362: case 10: ! 363: yylval.y_int = atol(buf); ! 364: break; ! 365: ! 366: case 8: ! 367: yylval.y_int = octal(buf); ! 368: break; ! 369: ! 370: case 16: ! 371: yylval.y_int = hex(buf); ! 372: break; ! 373: ! 374: default: ! 375: badcaseval(base); ! 376: } ! 377: t = INT; ! 378: } ! 379: curchar = p; ! 380: return t; ! 381: } ! 382: ! 383: /* ! 384: * Convert a string of octal digits to an integer. ! 385: */ ! 386: ! 387: private int octal(s) ! 388: String s; ! 389: { ! 390: register Char *p; ! 391: register Integer n; ! 392: ! 393: n = 0; ! 394: for (p = s; *p != '\0'; p++) { ! 395: n = 8*n + (*p - '0'); ! 396: } ! 397: return n; ! 398: } ! 399: ! 400: /* ! 401: * Convert a string of hexadecimal digits to an integer. ! 402: */ ! 403: ! 404: private int hex(s) ! 405: String s; ! 406: { ! 407: register Char *p; ! 408: register Integer n; ! 409: ! 410: n = 0; ! 411: for (p = s; *p != '\0'; p++) { ! 412: n *= 16; ! 413: if (*p >= 'a' and *p <= 'f') { ! 414: n += (*p - 'a' + 10); ! 415: } else if (*p >= 'A' and *p <= 'F') { ! 416: n += (*p - 'A' + 10); ! 417: } else { ! 418: n += (*p - '0'); ! 419: } ! 420: } ! 421: return n; ! 422: } ! 423: ! 424: /* ! 425: * Scan a string. ! 426: */ ! 427: ! 428: private Token getstring() ! 429: { ! 430: char buf[256]; ! 431: register Char *p, *q; ! 432: Boolean endofstring; ! 433: ! 434: p = curchar; ! 435: q = buf; ! 436: endofstring = false; ! 437: while (not endofstring) { ! 438: if (*p == '\n' or *p == '\0') { ! 439: error("non-terminated string"); ! 440: endofstring = true; ! 441: } else if (*p == '"' or *p == '\'') { ! 442: if (*(p+1) != *p) { ! 443: endofstring = true; ! 444: } else { ! 445: *q++ = *p; ! 446: } ! 447: } else { ! 448: curchar = p; ! 449: *q++ = charcon(p); ! 450: p = curchar; ! 451: } ! 452: p++; ! 453: } ! 454: curchar = p; ! 455: *q = '\0'; ! 456: yylval.y_string = strdup(buf); ! 457: return STRING; ! 458: } ! 459: ! 460: /* ! 461: * Process a character constant. ! 462: * Watch out for backslashes. ! 463: */ ! 464: ! 465: private Char charcon(p) ! 466: char *p; ! 467: { ! 468: char c, buf[10], *q; ! 469: ! 470: if (*p == '\\') { ! 471: ++p; ! 472: if (*p != '\\') { ! 473: q = buf; ! 474: do { ! 475: *q++ = *p++; ! 476: } while (*p != '\\' and *p != '\'' and *p != '\n' and *p != '\0'); ! 477: *q = '\0'; ! 478: if (isdigit(buf[0])) { ! 479: c = (Char) octal(buf); ! 480: } else { ! 481: c = charlookup(buf); ! 482: } ! 483: curchar = p - 1; ! 484: } else { ! 485: c = '\\'; ! 486: } ! 487: } else { ! 488: c = *p; ! 489: } ! 490: return c; ! 491: } ! 492: ! 493: /* ! 494: * Do a lookup for a ASCII character name. ! 495: */ ! 496: ! 497: private String ascii[] = { ! 498: "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", ! 499: "BS", "HT", "NL", "VT", "NP", "CR", "SO", "SI", ! 500: "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB", ! 501: "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US", ! 502: "SP", nil ! 503: }; ! 504: ! 505: private char charlookup(s) ! 506: String s; ! 507: { ! 508: register int i; ! 509: ! 510: for (i = 0; ascii[i] != NULL; i++) { ! 511: if (streq(s, ascii[i])) { ! 512: return i; ! 513: } ! 514: } ! 515: if (streq(s, "DEL")) { ! 516: return 0177; ! 517: } ! 518: error("unknown ascii name \"%s\"", s); ! 519: return '?'; ! 520: } ! 521: ! 522: /* ! 523: * Input file management routines. ! 524: */ ! 525: ! 526: public setinput(filename) ! 527: Filename filename; ! 528: { ! 529: File f; ! 530: ! 531: f = fopen(filename, "r"); ! 532: if (f == nil) { ! 533: error("can't open %s", filename); ! 534: } else { ! 535: if (curinclindex >= MAXINCLDEPTH) { ! 536: error("unreasonable input nesting on \"%s\"", filename); ! 537: } ! 538: inclinfo[curinclindex].savefile = in; ! 539: inclinfo[curinclindex].savefn = errfilename; ! 540: inclinfo[curinclindex].savelineno = errlineno; ! 541: curinclindex++; ! 542: in = f; ! 543: errfilename = filename; ! 544: errlineno = 1; ! 545: } ! 546: } ! 547: ! 548: private Boolean eofinput() ! 549: { ! 550: register Boolean b; ! 551: ! 552: if (curinclindex == 0) { ! 553: if (isterm(in)) { ! 554: putchar('\n'); ! 555: clearerr(in); ! 556: b = false; ! 557: } else { ! 558: b = true; ! 559: } ! 560: } else { ! 561: fclose(in); ! 562: --curinclindex; ! 563: in = inclinfo[curinclindex].savefile; ! 564: errfilename = inclinfo[curinclindex].savefn; ! 565: errlineno = inclinfo[curinclindex].savelineno; ! 566: b = false; ! 567: } ! 568: return b; ! 569: } ! 570: ! 571: /* ! 572: * Pop the current input. Return whether successful. ! 573: */ ! 574: ! 575: public Boolean popinput() ! 576: { ! 577: Boolean b; ! 578: ! 579: if (curinclindex == 0) { ! 580: b = false; ! 581: } else { ! 582: b = (Boolean) (not eofinput()); ! 583: } ! 584: return b; ! 585: } ! 586: ! 587: /* ! 588: * Return whether we are currently reading from standard input. ! 589: */ ! 590: ! 591: public Boolean isstdin() ! 592: { ! 593: return (Boolean) (in == stdin); ! 594: } ! 595: ! 596: /* ! 597: * Send the current line to the shell. ! 598: */ ! 599: ! 600: public shellline() ! 601: { ! 602: register char *p; ! 603: ! 604: p = curchar; ! 605: while (*p != '\0' and (*p == '\n' or lexclass[*p] == WHITE)) { ! 606: ++p; ! 607: } ! 608: shell(p); ! 609: if (*p == '\0' and isterm(in)) { ! 610: putchar('\n'); ! 611: } ! 612: erecover(); ! 613: } ! 614: ! 615: /* ! 616: * Read the rest of the current line in "shell mode". ! 617: */ ! 618: ! 619: public beginshellmode() ! 620: { ! 621: shellmode = true; ! 622: } ! 623: ! 624: /* ! 625: * Print out a token for debugging. ! 626: */ ! 627: ! 628: public print_token(f, t) ! 629: File f; ! 630: Token t; ! 631: { ! 632: if (t == '\n') { ! 633: fprintf(f, "char '\\n'"); ! 634: } else if (t == EOF) { ! 635: fprintf(f, "EOF"); ! 636: } else if (t < 256) { ! 637: fprintf(f, "char '%c'", t); ! 638: } else { ! 639: fprintf(f, "\"%s\"", keywdstring(t)); ! 640: } ! 641: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.