19679Slinton /* Copyright (c) 1982 Regents of the University of California */ 29679Slinton 3*18232Slinton static char sccsid[] = "@(#)scanner.c 1.12 (Berkeley) 03/01/85"; 49679Slinton 5*18232Slinton static char rcsid[] = "$Header: scanner.c,v 1.5 84/12/26 10:42:05 linton Exp $"; 6*18232Slinton 79679Slinton /* 89679Slinton * Debugger scanner. 99679Slinton */ 109679Slinton 119679Slinton #include "defs.h" 129679Slinton #include "scanner.h" 139679Slinton #include "main.h" 149679Slinton #include "keywords.h" 159679Slinton #include "tree.h" 169679Slinton #include "symbols.h" 179679Slinton #include "names.h" 189679Slinton #include "y.tab.h" 199679Slinton 209679Slinton #ifndef public 219679Slinton typedef int Token; 229679Slinton 23*18232Slinton #define MAXLINESIZE 10240 249679Slinton 25*18232Slinton #endif 269679Slinton 2716928Ssam public String initfile = ".dbxinit"; 289679Slinton 29*18232Slinton typedef enum { WHITE, ALPHA, NUM, OTHER } Charclass; 30*18232Slinton 31*18232Slinton private Charclass class[256 + 1]; 32*18232Slinton private Charclass *lexclass = class + 1; 33*18232Slinton 34*18232Slinton #define isdigit(c) (lexclass[c] == NUM) 35*18232Slinton #define isalnum(c) (lexclass[c] == ALPHA or lexclass[c] == NUM) 36*18232Slinton #define ishexdigit(c) ( \ 37*18232Slinton isdigit(c) or (c >= 'a' and c <= 'f') or (c >= 'A' and c <= 'F') \ 38*18232Slinton ) 39*18232Slinton 40*18232Slinton public boolean chkalias; 41*18232Slinton public char scanner_linebuf[MAXLINESIZE]; 42*18232Slinton 43*18232Slinton private File in; 44*18232Slinton private char *curchar, *prevchar; 45*18232Slinton 46*18232Slinton #define MAXINCLDEPTH 10 47*18232Slinton 48*18232Slinton private struct { 49*18232Slinton File savefile; 50*18232Slinton Filename savefn; 51*18232Slinton int savelineno; 52*18232Slinton } inclinfo[MAXINCLDEPTH]; 53*18232Slinton 54*18232Slinton private unsigned int curinclindex; 55*18232Slinton 569679Slinton private Token getident(); 579679Slinton private Token getnum(); 589679Slinton private Token getstring(); 59*18232Slinton private Boolean eofinput(); 60*18232Slinton private char charcon(); 619679Slinton 62*18232Slinton private enterlexclass(class, s) 63*18232Slinton Charclass class; 64*18232Slinton String s; 65*18232Slinton { 66*18232Slinton register char *p; 679679Slinton 68*18232Slinton for (p = s; *p != '\0'; p++) { 69*18232Slinton lexclass[*p] = class; 70*18232Slinton } 71*18232Slinton } 72*18232Slinton 739679Slinton public scanner_init() 749679Slinton { 75*18232Slinton register Integer i; 769679Slinton 77*18232Slinton for (i = 0; i < 257; i++) { 78*18232Slinton class[i] = OTHER; 79*18232Slinton } 80*18232Slinton enterlexclass(WHITE, " \t"); 81*18232Slinton enterlexclass(ALPHA, "abcdefghijklmnopqrstuvwxyz"); 82*18232Slinton enterlexclass(ALPHA, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_$"); 83*18232Slinton enterlexclass(NUM, "0123456789"); 84*18232Slinton in = stdin; 85*18232Slinton errfilename = nil; 86*18232Slinton errlineno = 0; 87*18232Slinton curchar = scanner_linebuf; 88*18232Slinton scanner_linebuf[0] = '\0'; 89*18232Slinton chkalias = true; 909679Slinton } 919679Slinton 929679Slinton /* 939679Slinton * Read a single token. 94*18232Slinton * 95*18232Slinton * The input is line buffered. Tokens cannot cross line boundaries. 96*18232Slinton * 979679Slinton * There are two "modes" of operation: one as in a compiler, 98*18232Slinton * and one for reading shell-like syntax. In the first mode 99*18232Slinton * there is the additional choice of doing alias processing. 1009679Slinton */ 101*18232Slinton 102*18232Slinton private Boolean shellmode; 103*18232Slinton 1049679Slinton public Token yylex() 1059679Slinton { 106*18232Slinton register int c; 107*18232Slinton register char *p; 108*18232Slinton register Token t; 109*18232Slinton String line; 110*18232Slinton integer n; 1119679Slinton 112*18232Slinton p = curchar; 113*18232Slinton if (*p == '\0') { 114*18232Slinton do { 115*18232Slinton if (isterm(in)) { 116*18232Slinton printf("(%s) ", cmdname); 117*18232Slinton } 118*18232Slinton fflush(stdout); 119*18232Slinton line = fgets(scanner_linebuf, MAXLINESIZE, in); 120*18232Slinton } while (line == nil and not eofinput()); 121*18232Slinton if (line == nil) { 122*18232Slinton c = EOF; 123*18232Slinton } else { 124*18232Slinton p = scanner_linebuf; 125*18232Slinton while (lexclass[*p] == WHITE) { 126*18232Slinton p++; 127*18232Slinton } 128*18232Slinton shellmode = false; 1299679Slinton } 130*18232Slinton chkalias = true; 131*18232Slinton } else { 132*18232Slinton while (lexclass[*p] == WHITE) { 133*18232Slinton p++; 1349679Slinton } 135*18232Slinton } 136*18232Slinton curchar = p; 137*18232Slinton prevchar = curchar; 138*18232Slinton c = *p; 139*18232Slinton if (lexclass[c] == ALPHA) { 140*18232Slinton t = getident(chkalias); 141*18232Slinton } else if (lexclass[c] == NUM) { 142*18232Slinton if (shellmode) { 143*18232Slinton t = getident(chkalias); 144*18232Slinton } else { 145*18232Slinton t = getnum(); 14612120Slinton } 147*18232Slinton } else { 148*18232Slinton ++curchar; 1499679Slinton switch (c) { 150*18232Slinton case '\n': 1519679Slinton t = '\n'; 152*18232Slinton if (errlineno != 0) { 153*18232Slinton errlineno++; 1549679Slinton } 1559679Slinton break; 1569679Slinton 157*18232Slinton case '"': 158*18232Slinton case '\'': 15916928Ssam t = getstring(c); 1609679Slinton break; 1619679Slinton 162*18232Slinton case '.': 1639679Slinton if (shellmode) { 164*18232Slinton --curchar; 165*18232Slinton t = getident(chkalias); 166*18232Slinton } else if (isdigit(*curchar)) { 167*18232Slinton --curchar; 168*18232Slinton t = getnum(); 169*18232Slinton } else { 170*18232Slinton t = '.'; 1719679Slinton } 1729679Slinton break; 1739679Slinton 174*18232Slinton case '-': 175*18232Slinton if (shellmode) { 176*18232Slinton --curchar; 177*18232Slinton t = getident(chkalias); 178*18232Slinton } else if (*curchar == '>') { 179*18232Slinton ++curchar; 180*18232Slinton t = ARROW; 181*18232Slinton } else { 182*18232Slinton t = '-'; 183*18232Slinton } 1849679Slinton break; 1859679Slinton 186*18232Slinton case '#': 187*18232Slinton if (not isterm(in)) { 188*18232Slinton *p = '\0'; 189*18232Slinton curchar = p; 190*18232Slinton t = '\n'; 191*18232Slinton ++errlineno; 192*18232Slinton } else { 193*18232Slinton t = '#'; 194*18232Slinton } 1959679Slinton break; 1969679Slinton 197*18232Slinton case '\\': 198*18232Slinton if (*(p+1) == '\n') { 199*18232Slinton n = MAXLINESIZE - (p - &scanner_linebuf[0]); 200*18232Slinton if (n > 1) { 201*18232Slinton if (fgets(p, n, in) == nil) { 202*18232Slinton t = 0; 203*18232Slinton } else { 204*18232Slinton curchar = p; 205*18232Slinton t = yylex(); 206*18232Slinton } 207*18232Slinton } else { 208*18232Slinton t = '\\'; 209*18232Slinton } 210*18232Slinton } else { 211*18232Slinton t = '\\'; 2129679Slinton } 2139679Slinton break; 2149679Slinton 215*18232Slinton case EOF: 2169679Slinton t = 0; 2179679Slinton break; 2189679Slinton 219*18232Slinton default: 220*18232Slinton if (shellmode and index("!&*<>()[]", c) == nil) { 221*18232Slinton --curchar; 222*18232Slinton t = getident(chkalias); 223*18232Slinton } else { 224*18232Slinton t = c; 225*18232Slinton } 2269679Slinton break; 2279679Slinton } 228*18232Slinton } 229*18232Slinton chkalias = false; 230*18232Slinton # ifdef LEXDEBUG 2319679Slinton if (lexdebug) { 232*18232Slinton fprintf(stderr, "yylex returns "); 233*18232Slinton print_token(stderr, t); 234*18232Slinton fprintf(stderr, "\n"); 2359679Slinton } 236*18232Slinton # endif 237*18232Slinton return t; 2389679Slinton } 2399679Slinton 2409679Slinton /* 241*18232Slinton * Put the given string before the current character 242*18232Slinton * in the current line, thus inserting it into the input stream. 2439679Slinton */ 2449679Slinton 245*18232Slinton public insertinput (s) 246*18232Slinton String s; 2479679Slinton { 248*18232Slinton register char *p, *q; 249*18232Slinton int need, avail, shift; 2509679Slinton 251*18232Slinton q = s; 252*18232Slinton need = strlen(q); 253*18232Slinton avail = curchar - &scanner_linebuf[0]; 254*18232Slinton if (need <= avail) { 255*18232Slinton curchar = &scanner_linebuf[avail - need]; 256*18232Slinton p = curchar; 257*18232Slinton while (*q != '\0') { 258*18232Slinton *p++ = *q++; 25916928Ssam } 260*18232Slinton } else { 261*18232Slinton p = curchar; 262*18232Slinton while (*p != '\0') { 263*18232Slinton ++p; 2649679Slinton } 265*18232Slinton shift = need - avail; 266*18232Slinton if (p + shift >= &scanner_linebuf[MAXLINESIZE]) { 267*18232Slinton error("alias expansion too large"); 2689679Slinton } 269*18232Slinton for (;;) { 270*18232Slinton *(p + shift) = *p; 271*18232Slinton if (p == curchar) { 2729679Slinton break; 273*18232Slinton } 274*18232Slinton --p; 2759679Slinton } 276*18232Slinton p = &scanner_linebuf[0]; 277*18232Slinton while (*q != '\0') { 278*18232Slinton *p++ = *q++; 279*18232Slinton } 280*18232Slinton curchar = &scanner_linebuf[0]; 281*18232Slinton } 2829679Slinton } 2839679Slinton 2849679Slinton /* 285*18232Slinton * Get the actuals for a macro call. 2869679Slinton */ 2879679Slinton 288*18232Slinton private String movetochar (str, c) 289*18232Slinton String str; 290*18232Slinton char c; 2919679Slinton { 292*18232Slinton register char *p; 2939679Slinton 294*18232Slinton while (*p != c) { 295*18232Slinton if (*p == '\0') { 296*18232Slinton error("missing ')' in macro call"); 297*18232Slinton } else if (*p == ')') { 298*18232Slinton error("not enough parameters in macro call"); 299*18232Slinton } else if (*p == ',') { 300*18232Slinton error("too many parameters in macro call"); 3019679Slinton } 302*18232Slinton ++p; 303*18232Slinton } 304*18232Slinton return p; 3059679Slinton } 3069679Slinton 307*18232Slinton private String *getactuals (n) 308*18232Slinton integer n; 3099679Slinton { 310*18232Slinton String *a; 311*18232Slinton register char *p; 312*18232Slinton int i; 3139679Slinton 314*18232Slinton a = newarr(String, n); 315*18232Slinton p = curchar; 316*18232Slinton while (*p != '(') { 317*18232Slinton if (lexclass[*p] != WHITE) { 318*18232Slinton error("missing actuals for macro"); 3199679Slinton } 320*18232Slinton ++p; 321*18232Slinton } 322*18232Slinton ++p; 323*18232Slinton for (i = 0; i < n - 1; i++) { 324*18232Slinton a[i] = p; 325*18232Slinton p = movetochar(p, ','); 326*18232Slinton *p = '\0'; 327*18232Slinton ++p; 328*18232Slinton } 329*18232Slinton a[n-1] = p; 330*18232Slinton p = movetochar(p, ')'); 331*18232Slinton *p = '\0'; 332*18232Slinton curchar = p + 1; 333*18232Slinton return a; 3349679Slinton } 3359679Slinton 3369679Slinton /* 337*18232Slinton * Do command macro expansion, assuming curchar points to the beginning 338*18232Slinton * of the actuals, and we are not in shell mode. 3399679Slinton */ 340*18232Slinton 341*18232Slinton private expand (pl, str) 342*18232Slinton List pl; 343*18232Slinton String str; 3449679Slinton { 345*18232Slinton char buf[4096], namebuf[100]; 346*18232Slinton register char *p, *q, *r; 347*18232Slinton String *actual; 348*18232Slinton Name n; 349*18232Slinton integer i; 350*18232Slinton boolean match; 3519679Slinton 352*18232Slinton if (pl == nil) { 353*18232Slinton insertinput(str); 354*18232Slinton } else { 355*18232Slinton actual = getactuals(list_size(pl)); 356*18232Slinton p = buf; 357*18232Slinton q = str; 358*18232Slinton while (*q != '\0') { 359*18232Slinton if (p >= &buf[4096]) { 360*18232Slinton error("alias expansion too large"); 361*18232Slinton } 362*18232Slinton if (lexclass[*q] == ALPHA) { 363*18232Slinton r = namebuf; 364*18232Slinton do { 365*18232Slinton *r++ = *q++; 366*18232Slinton } while (isalnum(*q)); 367*18232Slinton *r = '\0'; 368*18232Slinton i = 0; 369*18232Slinton match = false; 370*18232Slinton foreach(Name, n, pl) 371*18232Slinton if (streq(ident(n), namebuf)) { 372*18232Slinton match = true; 373*18232Slinton break; 374*18232Slinton } 375*18232Slinton ++i; 376*18232Slinton endfor 377*18232Slinton if (match) { 378*18232Slinton r = actual[i]; 379*18232Slinton } else { 380*18232Slinton r = namebuf; 38116928Ssam } 382*18232Slinton while (*r != '\0') { 383*18232Slinton *p++ = *r++; 384*18232Slinton } 385*18232Slinton } else { 386*18232Slinton *p++ = *q++; 387*18232Slinton } 3889679Slinton } 389*18232Slinton *p = '\0'; 390*18232Slinton insertinput(buf); 391*18232Slinton } 3929679Slinton } 3939679Slinton 3949679Slinton /* 39516928Ssam * Parser error handling. 3969679Slinton */ 397*18232Slinton 39816928Ssam public yyerror(s) 3999679Slinton String s; 4009679Slinton { 401*18232Slinton register char *p; 402*18232Slinton register integer start; 4039679Slinton 404*18232Slinton if (streq(s, "syntax error")) { 405*18232Slinton beginerrmsg(); 406*18232Slinton p = prevchar; 407*18232Slinton start = p - &scanner_linebuf[0]; 408*18232Slinton if (p > &scanner_linebuf[0]) { 409*18232Slinton while (lexclass[*p] == WHITE and p > &scanner_linebuf[0]) { 410*18232Slinton --p; 411*18232Slinton } 4129679Slinton } 413*18232Slinton fprintf(stderr, "%s", scanner_linebuf); 414*18232Slinton if (start != 0) { 415*18232Slinton fprintf(stderr, "%*c", start, ' '); 416*18232Slinton } 417*18232Slinton if (p == &scanner_linebuf[0]) { 418*18232Slinton fprintf(stderr, "^ unrecognized command"); 419*18232Slinton } else { 420*18232Slinton fprintf(stderr, "^ syntax error"); 421*18232Slinton } 422*18232Slinton enderrmsg(); 423*18232Slinton } else { 42416928Ssam error(s); 425*18232Slinton } 4269679Slinton } 4279679Slinton 4289679Slinton /* 42916928Ssam * Eat the current line. 43016928Ssam */ 43116928Ssam 432*18232Slinton public gobble () 43316928Ssam { 434*18232Slinton curchar = scanner_linebuf; 435*18232Slinton scanner_linebuf[0] = '\0'; 43616928Ssam } 43716928Ssam 43816928Ssam /* 439*18232Slinton * Scan an identifier. 440*18232Slinton * 441*18232Slinton * If chkalias is true, check first to see if it's an alias. 442*18232Slinton * Otherwise, check to see if it's a keyword. 4439679Slinton */ 444*18232Slinton 445*18232Slinton private Token getident (chkalias) 446*18232Slinton boolean chkalias; 4479679Slinton { 448*18232Slinton char buf[1024]; 449*18232Slinton register char *p, *q; 450*18232Slinton register Token t; 451*18232Slinton List pl; 452*18232Slinton String str; 4539679Slinton 454*18232Slinton p = curchar; 455*18232Slinton q = buf; 456*18232Slinton if (shellmode) { 457*18232Slinton do { 458*18232Slinton *q++ = *p++; 459*18232Slinton } while (index(" \t\n!&<>*[]()'\"", *p) == nil); 460*18232Slinton } else { 461*18232Slinton do { 462*18232Slinton *q++ = *p++; 463*18232Slinton } while (isalnum(*p)); 464*18232Slinton } 465*18232Slinton curchar = p; 466*18232Slinton *q = '\0'; 467*18232Slinton yylval.y_name = identname(buf, false); 468*18232Slinton if (chkalias) { 469*18232Slinton if (findalias(yylval.y_name, &pl, &str)) { 470*18232Slinton expand(pl, str); 471*18232Slinton while (lexclass[*curchar] == WHITE) { 472*18232Slinton ++curchar; 473*18232Slinton } 474*18232Slinton if (pl == nil) { 475*18232Slinton t = getident(false); 476*18232Slinton } else { 477*18232Slinton t = getident(true); 478*18232Slinton } 479*18232Slinton } else if (shellmode) { 480*18232Slinton t = NAME; 481*18232Slinton } else { 482*18232Slinton t = findkeyword(yylval.y_name, NAME); 4839679Slinton } 484*18232Slinton } else if (shellmode) { 485*18232Slinton t = NAME; 486*18232Slinton } else { 487*18232Slinton t = findkeyword(yylval.y_name, NAME); 488*18232Slinton } 489*18232Slinton return t; 4909679Slinton } 4919679Slinton 49216928Ssam /* 493*18232Slinton * Scan a number. 49416928Ssam */ 495*18232Slinton 496*18232Slinton private Token getnum() 4979679Slinton { 498*18232Slinton char buf[1024]; 499*18232Slinton register Char *p, *q; 500*18232Slinton register Token t; 501*18232Slinton Integer base; 5029679Slinton 503*18232Slinton p = curchar; 504*18232Slinton q = buf; 505*18232Slinton if (*p == '0') { 506*18232Slinton if (*(p+1) == 'x') { 507*18232Slinton p += 2; 508*18232Slinton base = 16; 509*18232Slinton } else if (*(p+1) == 't') { 510*18232Slinton base = 10; 511*18232Slinton } else if (varIsSet("$hexin")) { 512*18232Slinton base = 16; 513*18232Slinton } else { 514*18232Slinton base = 8; 515*18232Slinton } 516*18232Slinton } else if (varIsSet("$hexin")) { 517*18232Slinton base = 16; 518*18232Slinton } else if (varIsSet("$octin")) { 519*18232Slinton base = 8; 520*18232Slinton } else { 521*18232Slinton base = 10; 522*18232Slinton } 523*18232Slinton if (base == 16) { 524*18232Slinton do { 525*18232Slinton *q++ = *p++; 526*18232Slinton } while (ishexdigit(*p)); 527*18232Slinton } else { 528*18232Slinton do { 529*18232Slinton *q++ = *p++; 530*18232Slinton } while (isdigit(*p)); 531*18232Slinton } 532*18232Slinton if (*p == '.') { 533*18232Slinton do { 534*18232Slinton *q++ = *p++; 535*18232Slinton } while (isdigit(*p)); 536*18232Slinton if (*p == 'e' or *p == 'E') { 537*18232Slinton p++; 538*18232Slinton if (*p == '+' or *p == '-' or isdigit(*p)) { 539*18232Slinton *q++ = 'e'; 540*18232Slinton do { 541*18232Slinton *q++ = *p++; 542*18232Slinton } while (isdigit(*p)); 543*18232Slinton } 544*18232Slinton } 545*18232Slinton *q = '\0'; 546*18232Slinton yylval.y_real = atof(buf); 547*18232Slinton t = REAL; 548*18232Slinton } else { 549*18232Slinton *q = '\0'; 550*18232Slinton switch (base) { 551*18232Slinton case 10: 552*18232Slinton yylval.y_int = atol(buf); 553*18232Slinton break; 554*18232Slinton 555*18232Slinton case 8: 556*18232Slinton yylval.y_int = octal(buf); 557*18232Slinton break; 558*18232Slinton 559*18232Slinton case 16: 560*18232Slinton yylval.y_int = hex(buf); 561*18232Slinton break; 562*18232Slinton 563*18232Slinton default: 564*18232Slinton badcaseval(base); 565*18232Slinton } 566*18232Slinton t = INT; 567*18232Slinton } 568*18232Slinton curchar = p; 569*18232Slinton return t; 5709679Slinton } 5719679Slinton 5729679Slinton /* 573*18232Slinton * Convert a string of octal digits to an integer. 5749679Slinton */ 5759679Slinton 576*18232Slinton private int octal(s) 577*18232Slinton String s; 5789679Slinton { 579*18232Slinton register Char *p; 580*18232Slinton register Integer n; 5819679Slinton 582*18232Slinton n = 0; 583*18232Slinton for (p = s; *p != '\0'; p++) { 584*18232Slinton n = 8*n + (*p - '0'); 585*18232Slinton } 586*18232Slinton return n; 5879679Slinton } 5889679Slinton 589*18232Slinton /* 590*18232Slinton * Convert a string of hexadecimal digits to an integer. 591*18232Slinton */ 59216928Ssam 593*18232Slinton private int hex(s) 594*18232Slinton String s; 59516928Ssam { 596*18232Slinton register Char *p; 597*18232Slinton register Integer n; 59816928Ssam 599*18232Slinton n = 0; 600*18232Slinton for (p = s; *p != '\0'; p++) { 601*18232Slinton n *= 16; 602*18232Slinton if (*p >= 'a' and *p <= 'f') { 603*18232Slinton n += (*p - 'a' + 10); 604*18232Slinton } else if (*p >= 'A' and *p <= 'F') { 605*18232Slinton n += (*p - 'A' + 10); 606*18232Slinton } else { 607*18232Slinton n += (*p - '0'); 608*18232Slinton } 609*18232Slinton } 610*18232Slinton return n; 61116928Ssam } 61216928Ssam 6139679Slinton /* 614*18232Slinton * Scan a string. 6159679Slinton */ 616*18232Slinton 617*18232Slinton private Token getstring (quote) 618*18232Slinton char quote; 61916928Ssam { 620*18232Slinton register char *p, *q; 621*18232Slinton char buf[MAXLINESIZE]; 622*18232Slinton boolean endofstring; 623*18232Slinton Token t; 6249679Slinton 625*18232Slinton p = curchar; 626*18232Slinton q = buf; 627*18232Slinton endofstring = false; 628*18232Slinton while (not endofstring) { 629*18232Slinton if (*p == '\\' and *(p+1) == '\n') { 630*18232Slinton if (fgets(scanner_linebuf, MAXLINESIZE, in) == nil) { 631*18232Slinton error("non-terminated string"); 632*18232Slinton } 633*18232Slinton p = &scanner_linebuf[0] - 1; 634*18232Slinton } else if (*p == '\n' or *p == '\0') { 635*18232Slinton error("non-terminated string"); 636*18232Slinton endofstring = true; 637*18232Slinton } else if (*p == quote) { 638*18232Slinton endofstring = true; 639*18232Slinton } else { 640*18232Slinton curchar = p; 641*18232Slinton *q++ = charcon(p); 642*18232Slinton p = curchar; 64316928Ssam } 644*18232Slinton p++; 645*18232Slinton } 646*18232Slinton curchar = p; 647*18232Slinton *q = '\0'; 648*18232Slinton if (quote == '\'' and buf[1] == '\0') { 649*18232Slinton yylval.y_char = buf[0]; 650*18232Slinton t = CHAR; 651*18232Slinton } else { 652*18232Slinton yylval.y_string = strdup(buf); 653*18232Slinton t = STRING; 654*18232Slinton } 655*18232Slinton return t; 65616928Ssam } 65716928Ssam 658*18232Slinton /* 659*18232Slinton * Process a character constant. 660*18232Slinton * Watch out for backslashes. 661*18232Slinton */ 662*18232Slinton 663*18232Slinton private char charcon (s) 664*18232Slinton String s; 6659679Slinton { 666*18232Slinton register char *p, *q; 667*18232Slinton char c, buf[10]; 66816928Ssam 669*18232Slinton p = s; 670*18232Slinton if (*p == '\\') { 671*18232Slinton ++p; 672*18232Slinton switch (*p) { 673*18232Slinton case '\\': 674*18232Slinton c = '\\'; 675*18232Slinton break; 67616928Ssam 677*18232Slinton case 'n': 678*18232Slinton c = '\n'; 67916928Ssam break; 68016928Ssam 681*18232Slinton case 'r': 682*18232Slinton c = '\r'; 68316928Ssam break; 68416928Ssam 685*18232Slinton case 't': 686*18232Slinton c = '\t'; 687*18232Slinton break; 6889679Slinton 689*18232Slinton case '\'': 690*18232Slinton case '"': 691*18232Slinton c = *p; 69216928Ssam break; 69316928Ssam 694*18232Slinton default: 695*18232Slinton if (isdigit(*p)) { 696*18232Slinton q = buf; 697*18232Slinton do { 698*18232Slinton *q++ = *p++; 699*18232Slinton } while (isdigit(*p)); 700*18232Slinton *q = '\0'; 701*18232Slinton c = (char) octal(buf); 702*18232Slinton } 703*18232Slinton --p; 70416928Ssam break; 70516928Ssam } 706*18232Slinton curchar = p; 707*18232Slinton } else { 708*18232Slinton c = *p; 709*18232Slinton } 710*18232Slinton return c; 71116928Ssam } 71216928Ssam 7139679Slinton /* 714*18232Slinton * Input file management routines. 7159679Slinton */ 716*18232Slinton 717*18232Slinton public setinput(filename) 718*18232Slinton Filename filename; 71916928Ssam { 720*18232Slinton File f; 7219679Slinton 722*18232Slinton f = fopen(filename, "r"); 723*18232Slinton if (f == nil) { 724*18232Slinton error("can't open %s", filename); 725*18232Slinton } else { 726*18232Slinton if (curinclindex >= MAXINCLDEPTH) { 727*18232Slinton error("unreasonable input nesting on \"%s\"", filename); 72816928Ssam } 729*18232Slinton inclinfo[curinclindex].savefile = in; 730*18232Slinton inclinfo[curinclindex].savefn = errfilename; 731*18232Slinton inclinfo[curinclindex].savelineno = errlineno; 732*18232Slinton curinclindex++; 733*18232Slinton in = f; 734*18232Slinton errfilename = filename; 735*18232Slinton errlineno = 1; 736*18232Slinton } 73716928Ssam } 73816928Ssam 739*18232Slinton private Boolean eofinput() 7409679Slinton { 741*18232Slinton register Boolean b; 7429679Slinton 743*18232Slinton if (curinclindex == 0) { 744*18232Slinton if (isterm(in)) { 745*18232Slinton putchar('\n'); 746*18232Slinton clearerr(in); 747*18232Slinton b = false; 748*18232Slinton } else { 749*18232Slinton b = true; 750*18232Slinton } 751*18232Slinton } else { 752*18232Slinton fclose(in); 753*18232Slinton --curinclindex; 754*18232Slinton in = inclinfo[curinclindex].savefile; 755*18232Slinton errfilename = inclinfo[curinclindex].savefn; 756*18232Slinton errlineno = inclinfo[curinclindex].savelineno; 757*18232Slinton b = false; 758*18232Slinton } 759*18232Slinton return b; 7609679Slinton } 7619679Slinton 7629679Slinton /* 763*18232Slinton * Pop the current input. Return whether successful. 7649679Slinton */ 765*18232Slinton 766*18232Slinton public Boolean popinput() 76716928Ssam { 768*18232Slinton Boolean b; 7699679Slinton 770*18232Slinton if (curinclindex == 0) { 771*18232Slinton b = false; 772*18232Slinton } else { 773*18232Slinton b = (Boolean) (not eofinput()); 774*18232Slinton } 775*18232Slinton return b; 7769679Slinton } 7779679Slinton 7789679Slinton /* 77916928Ssam * Return whether we are currently reading from standard input. 7809679Slinton */ 781*18232Slinton 78216928Ssam public Boolean isstdin() 78316928Ssam { 784*18232Slinton return (Boolean) (in == stdin); 785*18232Slinton } 7869679Slinton 787*18232Slinton /* 788*18232Slinton * Send the current line to the shell. 789*18232Slinton */ 790*18232Slinton 791*18232Slinton public shellline() 792*18232Slinton { 793*18232Slinton register char *p; 794*18232Slinton 795*18232Slinton p = curchar; 796*18232Slinton while (*p != '\0' and (*p == '\n' or lexclass[*p] == WHITE)) { 797*18232Slinton ++p; 798*18232Slinton } 799*18232Slinton shell(p); 800*18232Slinton if (*p == '\0' and isterm(in)) { 801*18232Slinton putchar('\n'); 802*18232Slinton } 803*18232Slinton erecover(); 80416928Ssam } 80516928Ssam 806*18232Slinton /* 807*18232Slinton * Read the rest of the current line in "shell mode". 808*18232Slinton */ 809*18232Slinton 810*18232Slinton public beginshellmode() 8119679Slinton { 812*18232Slinton shellmode = true; 813*18232Slinton } 81416928Ssam 815*18232Slinton /* 816*18232Slinton * Print out a token for debugging. 817*18232Slinton */ 818*18232Slinton 819*18232Slinton public print_token(f, t) 820*18232Slinton File f; 821*18232Slinton Token t; 822*18232Slinton { 823*18232Slinton if (t == '\n') { 824*18232Slinton fprintf(f, "char '\\n'"); 825*18232Slinton } else if (t == EOF) { 826*18232Slinton fprintf(f, "EOF"); 827*18232Slinton } else if (t < 256) { 828*18232Slinton fprintf(f, "char '%c'", t); 829*18232Slinton } else { 830*18232Slinton fprintf(f, "\"%s\"", keywdstring(t)); 831*18232Slinton } 8329679Slinton } 833