1*21622Sdist /* 2*21622Sdist * Copyright (c) 1983 Regents of the University of California. 3*21622Sdist * All rights reserved. The Berkeley software License Agreement 4*21622Sdist * specifies the terms and conditions for redistribution. 5*21622Sdist */ 69679Slinton 7*21622Sdist #ifndef lint 8*21622Sdist static char sccsid[] = "@(#)scanner.c 5.1 (Berkeley) 05/31/85"; 9*21622Sdist #endif not lint 109679Slinton 1118232Slinton static char rcsid[] = "$Header: scanner.c,v 1.5 84/12/26 10:42:05 linton Exp $"; 1218232Slinton 139679Slinton /* 149679Slinton * Debugger scanner. 159679Slinton */ 169679Slinton 179679Slinton #include "defs.h" 189679Slinton #include "scanner.h" 199679Slinton #include "main.h" 209679Slinton #include "keywords.h" 219679Slinton #include "tree.h" 229679Slinton #include "symbols.h" 239679Slinton #include "names.h" 249679Slinton #include "y.tab.h" 259679Slinton 269679Slinton #ifndef public 279679Slinton typedef int Token; 289679Slinton 2918232Slinton #define MAXLINESIZE 10240 309679Slinton 3118232Slinton #endif 329679Slinton 3316928Ssam public String initfile = ".dbxinit"; 349679Slinton 3518232Slinton typedef enum { WHITE, ALPHA, NUM, OTHER } Charclass; 3618232Slinton 3718232Slinton private Charclass class[256 + 1]; 3818232Slinton private Charclass *lexclass = class + 1; 3918232Slinton 4018232Slinton #define isdigit(c) (lexclass[c] == NUM) 4118232Slinton #define isalnum(c) (lexclass[c] == ALPHA or lexclass[c] == NUM) 4218232Slinton #define ishexdigit(c) ( \ 4318232Slinton isdigit(c) or (c >= 'a' and c <= 'f') or (c >= 'A' and c <= 'F') \ 4418232Slinton ) 4518232Slinton 4618232Slinton public boolean chkalias; 4718232Slinton public char scanner_linebuf[MAXLINESIZE]; 4818232Slinton 4918232Slinton private File in; 5018232Slinton private char *curchar, *prevchar; 5118232Slinton 5218232Slinton #define MAXINCLDEPTH 10 5318232Slinton 5418232Slinton private struct { 5518232Slinton File savefile; 5618232Slinton Filename savefn; 5718232Slinton int savelineno; 5818232Slinton } inclinfo[MAXINCLDEPTH]; 5918232Slinton 6018232Slinton private unsigned int curinclindex; 6118232Slinton 629679Slinton private Token getident(); 639679Slinton private Token getnum(); 649679Slinton private Token getstring(); 6518232Slinton private Boolean eofinput(); 6618232Slinton private char charcon(); 679679Slinton 6818232Slinton private enterlexclass(class, s) 6918232Slinton Charclass class; 7018232Slinton String s; 7118232Slinton { 7218232Slinton register char *p; 739679Slinton 7418232Slinton for (p = s; *p != '\0'; p++) { 7518232Slinton lexclass[*p] = class; 7618232Slinton } 7718232Slinton } 7818232Slinton 799679Slinton public scanner_init() 809679Slinton { 8118232Slinton register Integer i; 829679Slinton 8318232Slinton for (i = 0; i < 257; i++) { 8418232Slinton class[i] = OTHER; 8518232Slinton } 8618232Slinton enterlexclass(WHITE, " \t"); 8718232Slinton enterlexclass(ALPHA, "abcdefghijklmnopqrstuvwxyz"); 8818232Slinton enterlexclass(ALPHA, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_$"); 8918232Slinton enterlexclass(NUM, "0123456789"); 9018232Slinton in = stdin; 9118232Slinton errfilename = nil; 9218232Slinton errlineno = 0; 9318232Slinton curchar = scanner_linebuf; 9418232Slinton scanner_linebuf[0] = '\0'; 9518232Slinton chkalias = true; 969679Slinton } 979679Slinton 989679Slinton /* 999679Slinton * Read a single token. 10018232Slinton * 10118232Slinton * The input is line buffered. Tokens cannot cross line boundaries. 10218232Slinton * 1039679Slinton * There are two "modes" of operation: one as in a compiler, 10418232Slinton * and one for reading shell-like syntax. In the first mode 10518232Slinton * there is the additional choice of doing alias processing. 1069679Slinton */ 10718232Slinton 10818232Slinton private Boolean shellmode; 10918232Slinton 1109679Slinton public Token yylex() 1119679Slinton { 11218232Slinton register int c; 11318232Slinton register char *p; 11418232Slinton register Token t; 11518232Slinton String line; 11618232Slinton integer n; 1179679Slinton 11818232Slinton p = curchar; 11918232Slinton if (*p == '\0') { 12018232Slinton do { 12118232Slinton if (isterm(in)) { 12218232Slinton printf("(%s) ", cmdname); 12318232Slinton } 12418232Slinton fflush(stdout); 12518232Slinton line = fgets(scanner_linebuf, MAXLINESIZE, in); 12618232Slinton } while (line == nil and not eofinput()); 12718232Slinton if (line == nil) { 12818232Slinton c = EOF; 12918232Slinton } else { 13018232Slinton p = scanner_linebuf; 13118232Slinton while (lexclass[*p] == WHITE) { 13218232Slinton p++; 13318232Slinton } 13418232Slinton shellmode = false; 1359679Slinton } 13618232Slinton chkalias = true; 13718232Slinton } else { 13818232Slinton while (lexclass[*p] == WHITE) { 13918232Slinton p++; 1409679Slinton } 14118232Slinton } 14218232Slinton curchar = p; 14318232Slinton prevchar = curchar; 14418232Slinton c = *p; 14518232Slinton if (lexclass[c] == ALPHA) { 14618232Slinton t = getident(chkalias); 14718232Slinton } else if (lexclass[c] == NUM) { 14818232Slinton if (shellmode) { 14918232Slinton t = getident(chkalias); 15018232Slinton } else { 15118232Slinton t = getnum(); 15212120Slinton } 15318232Slinton } else { 15418232Slinton ++curchar; 1559679Slinton switch (c) { 15618232Slinton case '\n': 1579679Slinton t = '\n'; 15818232Slinton if (errlineno != 0) { 15918232Slinton errlineno++; 1609679Slinton } 1619679Slinton break; 1629679Slinton 16318232Slinton case '"': 16418232Slinton case '\'': 16516928Ssam t = getstring(c); 1669679Slinton break; 1679679Slinton 16818232Slinton case '.': 1699679Slinton if (shellmode) { 17018232Slinton --curchar; 17118232Slinton t = getident(chkalias); 17218232Slinton } else if (isdigit(*curchar)) { 17318232Slinton --curchar; 17418232Slinton t = getnum(); 17518232Slinton } else { 17618232Slinton t = '.'; 1779679Slinton } 1789679Slinton break; 1799679Slinton 18018232Slinton case '-': 18118232Slinton if (shellmode) { 18218232Slinton --curchar; 18318232Slinton t = getident(chkalias); 18418232Slinton } else if (*curchar == '>') { 18518232Slinton ++curchar; 18618232Slinton t = ARROW; 18718232Slinton } else { 18818232Slinton t = '-'; 18918232Slinton } 1909679Slinton break; 1919679Slinton 19218232Slinton case '#': 19318232Slinton if (not isterm(in)) { 19418232Slinton *p = '\0'; 19518232Slinton curchar = p; 19618232Slinton t = '\n'; 19718232Slinton ++errlineno; 19818232Slinton } else { 19918232Slinton t = '#'; 20018232Slinton } 2019679Slinton break; 2029679Slinton 20318232Slinton case '\\': 20418232Slinton if (*(p+1) == '\n') { 20518232Slinton n = MAXLINESIZE - (p - &scanner_linebuf[0]); 20618232Slinton if (n > 1) { 20718232Slinton if (fgets(p, n, in) == nil) { 20818232Slinton t = 0; 20918232Slinton } else { 21018232Slinton curchar = p; 21118232Slinton t = yylex(); 21218232Slinton } 21318232Slinton } else { 21418232Slinton t = '\\'; 21518232Slinton } 21618232Slinton } else { 21718232Slinton t = '\\'; 2189679Slinton } 2199679Slinton break; 2209679Slinton 22118232Slinton case EOF: 2229679Slinton t = 0; 2239679Slinton break; 2249679Slinton 22518232Slinton default: 22618232Slinton if (shellmode and index("!&*<>()[]", c) == nil) { 22718232Slinton --curchar; 22818232Slinton t = getident(chkalias); 22918232Slinton } else { 23018232Slinton t = c; 23118232Slinton } 2329679Slinton break; 2339679Slinton } 23418232Slinton } 23518232Slinton chkalias = false; 23618232Slinton # ifdef LEXDEBUG 2379679Slinton if (lexdebug) { 23818232Slinton fprintf(stderr, "yylex returns "); 23918232Slinton print_token(stderr, t); 24018232Slinton fprintf(stderr, "\n"); 2419679Slinton } 24218232Slinton # endif 24318232Slinton return t; 2449679Slinton } 2459679Slinton 2469679Slinton /* 24718232Slinton * Put the given string before the current character 24818232Slinton * in the current line, thus inserting it into the input stream. 2499679Slinton */ 2509679Slinton 25118232Slinton public insertinput (s) 25218232Slinton String s; 2539679Slinton { 25418232Slinton register char *p, *q; 25518232Slinton int need, avail, shift; 2569679Slinton 25718232Slinton q = s; 25818232Slinton need = strlen(q); 25918232Slinton avail = curchar - &scanner_linebuf[0]; 26018232Slinton if (need <= avail) { 26118232Slinton curchar = &scanner_linebuf[avail - need]; 26218232Slinton p = curchar; 26318232Slinton while (*q != '\0') { 26418232Slinton *p++ = *q++; 26516928Ssam } 26618232Slinton } else { 26718232Slinton p = curchar; 26818232Slinton while (*p != '\0') { 26918232Slinton ++p; 2709679Slinton } 27118232Slinton shift = need - avail; 27218232Slinton if (p + shift >= &scanner_linebuf[MAXLINESIZE]) { 27318232Slinton error("alias expansion too large"); 2749679Slinton } 27518232Slinton for (;;) { 27618232Slinton *(p + shift) = *p; 27718232Slinton if (p == curchar) { 2789679Slinton break; 27918232Slinton } 28018232Slinton --p; 2819679Slinton } 28218232Slinton p = &scanner_linebuf[0]; 28318232Slinton while (*q != '\0') { 28418232Slinton *p++ = *q++; 28518232Slinton } 28618232Slinton curchar = &scanner_linebuf[0]; 28718232Slinton } 2889679Slinton } 2899679Slinton 2909679Slinton /* 29118232Slinton * Get the actuals for a macro call. 2929679Slinton */ 2939679Slinton 29418232Slinton private String movetochar (str, c) 29518232Slinton String str; 29618232Slinton char c; 2979679Slinton { 29818232Slinton register char *p; 2999679Slinton 30018232Slinton while (*p != c) { 30118232Slinton if (*p == '\0') { 30218232Slinton error("missing ')' in macro call"); 30318232Slinton } else if (*p == ')') { 30418232Slinton error("not enough parameters in macro call"); 30518232Slinton } else if (*p == ',') { 30618232Slinton error("too many parameters in macro call"); 3079679Slinton } 30818232Slinton ++p; 30918232Slinton } 31018232Slinton return p; 3119679Slinton } 3129679Slinton 31318232Slinton private String *getactuals (n) 31418232Slinton integer n; 3159679Slinton { 31618232Slinton String *a; 31718232Slinton register char *p; 31818232Slinton int i; 3199679Slinton 32018232Slinton a = newarr(String, n); 32118232Slinton p = curchar; 32218232Slinton while (*p != '(') { 32318232Slinton if (lexclass[*p] != WHITE) { 32418232Slinton error("missing actuals for macro"); 3259679Slinton } 32618232Slinton ++p; 32718232Slinton } 32818232Slinton ++p; 32918232Slinton for (i = 0; i < n - 1; i++) { 33018232Slinton a[i] = p; 33118232Slinton p = movetochar(p, ','); 33218232Slinton *p = '\0'; 33318232Slinton ++p; 33418232Slinton } 33518232Slinton a[n-1] = p; 33618232Slinton p = movetochar(p, ')'); 33718232Slinton *p = '\0'; 33818232Slinton curchar = p + 1; 33918232Slinton return a; 3409679Slinton } 3419679Slinton 3429679Slinton /* 34318232Slinton * Do command macro expansion, assuming curchar points to the beginning 34418232Slinton * of the actuals, and we are not in shell mode. 3459679Slinton */ 34618232Slinton 34718232Slinton private expand (pl, str) 34818232Slinton List pl; 34918232Slinton String str; 3509679Slinton { 35118232Slinton char buf[4096], namebuf[100]; 35218232Slinton register char *p, *q, *r; 35318232Slinton String *actual; 35418232Slinton Name n; 35518232Slinton integer i; 35618232Slinton boolean match; 3579679Slinton 35818232Slinton if (pl == nil) { 35918232Slinton insertinput(str); 36018232Slinton } else { 36118232Slinton actual = getactuals(list_size(pl)); 36218232Slinton p = buf; 36318232Slinton q = str; 36418232Slinton while (*q != '\0') { 36518232Slinton if (p >= &buf[4096]) { 36618232Slinton error("alias expansion too large"); 36718232Slinton } 36818232Slinton if (lexclass[*q] == ALPHA) { 36918232Slinton r = namebuf; 37018232Slinton do { 37118232Slinton *r++ = *q++; 37218232Slinton } while (isalnum(*q)); 37318232Slinton *r = '\0'; 37418232Slinton i = 0; 37518232Slinton match = false; 37618232Slinton foreach(Name, n, pl) 37718232Slinton if (streq(ident(n), namebuf)) { 37818232Slinton match = true; 37918232Slinton break; 38018232Slinton } 38118232Slinton ++i; 38218232Slinton endfor 38318232Slinton if (match) { 38418232Slinton r = actual[i]; 38518232Slinton } else { 38618232Slinton r = namebuf; 38716928Ssam } 38818232Slinton while (*r != '\0') { 38918232Slinton *p++ = *r++; 39018232Slinton } 39118232Slinton } else { 39218232Slinton *p++ = *q++; 39318232Slinton } 3949679Slinton } 39518232Slinton *p = '\0'; 39618232Slinton insertinput(buf); 39718232Slinton } 3989679Slinton } 3999679Slinton 4009679Slinton /* 40116928Ssam * Parser error handling. 4029679Slinton */ 40318232Slinton 40416928Ssam public yyerror(s) 4059679Slinton String s; 4069679Slinton { 40718232Slinton register char *p; 40818232Slinton register integer start; 4099679Slinton 41018232Slinton if (streq(s, "syntax error")) { 41118232Slinton beginerrmsg(); 41218232Slinton p = prevchar; 41318232Slinton start = p - &scanner_linebuf[0]; 41418232Slinton if (p > &scanner_linebuf[0]) { 41518232Slinton while (lexclass[*p] == WHITE and p > &scanner_linebuf[0]) { 41618232Slinton --p; 41718232Slinton } 4189679Slinton } 41918232Slinton fprintf(stderr, "%s", scanner_linebuf); 42018232Slinton if (start != 0) { 42118232Slinton fprintf(stderr, "%*c", start, ' '); 42218232Slinton } 42318232Slinton if (p == &scanner_linebuf[0]) { 42418232Slinton fprintf(stderr, "^ unrecognized command"); 42518232Slinton } else { 42618232Slinton fprintf(stderr, "^ syntax error"); 42718232Slinton } 42818232Slinton enderrmsg(); 42918232Slinton } else { 43016928Ssam error(s); 43118232Slinton } 4329679Slinton } 4339679Slinton 4349679Slinton /* 43516928Ssam * Eat the current line. 43616928Ssam */ 43716928Ssam 43818232Slinton public gobble () 43916928Ssam { 44018232Slinton curchar = scanner_linebuf; 44118232Slinton scanner_linebuf[0] = '\0'; 44216928Ssam } 44316928Ssam 44416928Ssam /* 44518232Slinton * Scan an identifier. 44618232Slinton * 44718232Slinton * If chkalias is true, check first to see if it's an alias. 44818232Slinton * Otherwise, check to see if it's a keyword. 4499679Slinton */ 45018232Slinton 45118232Slinton private Token getident (chkalias) 45218232Slinton boolean chkalias; 4539679Slinton { 45418232Slinton char buf[1024]; 45518232Slinton register char *p, *q; 45618232Slinton register Token t; 45718232Slinton List pl; 45818232Slinton String str; 4599679Slinton 46018232Slinton p = curchar; 46118232Slinton q = buf; 46218232Slinton if (shellmode) { 46318232Slinton do { 46418232Slinton *q++ = *p++; 46518232Slinton } while (index(" \t\n!&<>*[]()'\"", *p) == nil); 46618232Slinton } else { 46718232Slinton do { 46818232Slinton *q++ = *p++; 46918232Slinton } while (isalnum(*p)); 47018232Slinton } 47118232Slinton curchar = p; 47218232Slinton *q = '\0'; 47318232Slinton yylval.y_name = identname(buf, false); 47418232Slinton if (chkalias) { 47518232Slinton if (findalias(yylval.y_name, &pl, &str)) { 47618232Slinton expand(pl, str); 47718232Slinton while (lexclass[*curchar] == WHITE) { 47818232Slinton ++curchar; 47918232Slinton } 48018232Slinton if (pl == nil) { 48118232Slinton t = getident(false); 48218232Slinton } else { 48318232Slinton t = getident(true); 48418232Slinton } 48518232Slinton } else if (shellmode) { 48618232Slinton t = NAME; 48718232Slinton } else { 48818232Slinton t = findkeyword(yylval.y_name, NAME); 4899679Slinton } 49018232Slinton } else if (shellmode) { 49118232Slinton t = NAME; 49218232Slinton } else { 49318232Slinton t = findkeyword(yylval.y_name, NAME); 49418232Slinton } 49518232Slinton return t; 4969679Slinton } 4979679Slinton 49816928Ssam /* 49918232Slinton * Scan a number. 50016928Ssam */ 50118232Slinton 50218232Slinton private Token getnum() 5039679Slinton { 50418232Slinton char buf[1024]; 50518232Slinton register Char *p, *q; 50618232Slinton register Token t; 50718232Slinton Integer base; 5089679Slinton 50918232Slinton p = curchar; 51018232Slinton q = buf; 51118232Slinton if (*p == '0') { 51218232Slinton if (*(p+1) == 'x') { 51318232Slinton p += 2; 51418232Slinton base = 16; 51518232Slinton } else if (*(p+1) == 't') { 51618232Slinton base = 10; 51718232Slinton } else if (varIsSet("$hexin")) { 51818232Slinton base = 16; 51918232Slinton } else { 52018232Slinton base = 8; 52118232Slinton } 52218232Slinton } else if (varIsSet("$hexin")) { 52318232Slinton base = 16; 52418232Slinton } else if (varIsSet("$octin")) { 52518232Slinton base = 8; 52618232Slinton } else { 52718232Slinton base = 10; 52818232Slinton } 52918232Slinton if (base == 16) { 53018232Slinton do { 53118232Slinton *q++ = *p++; 53218232Slinton } while (ishexdigit(*p)); 53318232Slinton } else { 53418232Slinton do { 53518232Slinton *q++ = *p++; 53618232Slinton } while (isdigit(*p)); 53718232Slinton } 53818232Slinton if (*p == '.') { 53918232Slinton do { 54018232Slinton *q++ = *p++; 54118232Slinton } while (isdigit(*p)); 54218232Slinton if (*p == 'e' or *p == 'E') { 54318232Slinton p++; 54418232Slinton if (*p == '+' or *p == '-' or isdigit(*p)) { 54518232Slinton *q++ = 'e'; 54618232Slinton do { 54718232Slinton *q++ = *p++; 54818232Slinton } while (isdigit(*p)); 54918232Slinton } 55018232Slinton } 55118232Slinton *q = '\0'; 55218232Slinton yylval.y_real = atof(buf); 55318232Slinton t = REAL; 55418232Slinton } else { 55518232Slinton *q = '\0'; 55618232Slinton switch (base) { 55718232Slinton case 10: 55818232Slinton yylval.y_int = atol(buf); 55918232Slinton break; 56018232Slinton 56118232Slinton case 8: 56218232Slinton yylval.y_int = octal(buf); 56318232Slinton break; 56418232Slinton 56518232Slinton case 16: 56618232Slinton yylval.y_int = hex(buf); 56718232Slinton break; 56818232Slinton 56918232Slinton default: 57018232Slinton badcaseval(base); 57118232Slinton } 57218232Slinton t = INT; 57318232Slinton } 57418232Slinton curchar = p; 57518232Slinton return t; 5769679Slinton } 5779679Slinton 5789679Slinton /* 57918232Slinton * Convert a string of octal digits to an integer. 5809679Slinton */ 5819679Slinton 58218232Slinton private int octal(s) 58318232Slinton String s; 5849679Slinton { 58518232Slinton register Char *p; 58618232Slinton register Integer n; 5879679Slinton 58818232Slinton n = 0; 58918232Slinton for (p = s; *p != '\0'; p++) { 59018232Slinton n = 8*n + (*p - '0'); 59118232Slinton } 59218232Slinton return n; 5939679Slinton } 5949679Slinton 59518232Slinton /* 59618232Slinton * Convert a string of hexadecimal digits to an integer. 59718232Slinton */ 59816928Ssam 59918232Slinton private int hex(s) 60018232Slinton String s; 60116928Ssam { 60218232Slinton register Char *p; 60318232Slinton register Integer n; 60416928Ssam 60518232Slinton n = 0; 60618232Slinton for (p = s; *p != '\0'; p++) { 60718232Slinton n *= 16; 60818232Slinton if (*p >= 'a' and *p <= 'f') { 60918232Slinton n += (*p - 'a' + 10); 61018232Slinton } else if (*p >= 'A' and *p <= 'F') { 61118232Slinton n += (*p - 'A' + 10); 61218232Slinton } else { 61318232Slinton n += (*p - '0'); 61418232Slinton } 61518232Slinton } 61618232Slinton return n; 61716928Ssam } 61816928Ssam 6199679Slinton /* 62018232Slinton * Scan a string. 6219679Slinton */ 62218232Slinton 62318232Slinton private Token getstring (quote) 62418232Slinton char quote; 62516928Ssam { 62618232Slinton register char *p, *q; 62718232Slinton char buf[MAXLINESIZE]; 62818232Slinton boolean endofstring; 62918232Slinton Token t; 6309679Slinton 63118232Slinton p = curchar; 63218232Slinton q = buf; 63318232Slinton endofstring = false; 63418232Slinton while (not endofstring) { 63518232Slinton if (*p == '\\' and *(p+1) == '\n') { 63618232Slinton if (fgets(scanner_linebuf, MAXLINESIZE, in) == nil) { 63718232Slinton error("non-terminated string"); 63818232Slinton } 63918232Slinton p = &scanner_linebuf[0] - 1; 64018232Slinton } else if (*p == '\n' or *p == '\0') { 64118232Slinton error("non-terminated string"); 64218232Slinton endofstring = true; 64318232Slinton } else if (*p == quote) { 64418232Slinton endofstring = true; 64518232Slinton } else { 64618232Slinton curchar = p; 64718232Slinton *q++ = charcon(p); 64818232Slinton p = curchar; 64916928Ssam } 65018232Slinton p++; 65118232Slinton } 65218232Slinton curchar = p; 65318232Slinton *q = '\0'; 65418232Slinton if (quote == '\'' and buf[1] == '\0') { 65518232Slinton yylval.y_char = buf[0]; 65618232Slinton t = CHAR; 65718232Slinton } else { 65818232Slinton yylval.y_string = strdup(buf); 65918232Slinton t = STRING; 66018232Slinton } 66118232Slinton return t; 66216928Ssam } 66316928Ssam 66418232Slinton /* 66518232Slinton * Process a character constant. 66618232Slinton * Watch out for backslashes. 66718232Slinton */ 66818232Slinton 66918232Slinton private char charcon (s) 67018232Slinton String s; 6719679Slinton { 67218232Slinton register char *p, *q; 67318232Slinton char c, buf[10]; 67416928Ssam 67518232Slinton p = s; 67618232Slinton if (*p == '\\') { 67718232Slinton ++p; 67818232Slinton switch (*p) { 67918232Slinton case '\\': 68018232Slinton c = '\\'; 68118232Slinton break; 68216928Ssam 68318232Slinton case 'n': 68418232Slinton c = '\n'; 68516928Ssam break; 68616928Ssam 68718232Slinton case 'r': 68818232Slinton c = '\r'; 68916928Ssam break; 69016928Ssam 69118232Slinton case 't': 69218232Slinton c = '\t'; 69318232Slinton break; 6949679Slinton 69518232Slinton case '\'': 69618232Slinton case '"': 69718232Slinton c = *p; 69816928Ssam break; 69916928Ssam 70018232Slinton default: 70118232Slinton if (isdigit(*p)) { 70218232Slinton q = buf; 70318232Slinton do { 70418232Slinton *q++ = *p++; 70518232Slinton } while (isdigit(*p)); 70618232Slinton *q = '\0'; 70718232Slinton c = (char) octal(buf); 70818232Slinton } 70918232Slinton --p; 71016928Ssam break; 71116928Ssam } 71218232Slinton curchar = p; 71318232Slinton } else { 71418232Slinton c = *p; 71518232Slinton } 71618232Slinton return c; 71716928Ssam } 71816928Ssam 7199679Slinton /* 72018232Slinton * Input file management routines. 7219679Slinton */ 72218232Slinton 72318232Slinton public setinput(filename) 72418232Slinton Filename filename; 72516928Ssam { 72618232Slinton File f; 7279679Slinton 72818232Slinton f = fopen(filename, "r"); 72918232Slinton if (f == nil) { 73018232Slinton error("can't open %s", filename); 73118232Slinton } else { 73218232Slinton if (curinclindex >= MAXINCLDEPTH) { 73318232Slinton error("unreasonable input nesting on \"%s\"", filename); 73416928Ssam } 73518232Slinton inclinfo[curinclindex].savefile = in; 73618232Slinton inclinfo[curinclindex].savefn = errfilename; 73718232Slinton inclinfo[curinclindex].savelineno = errlineno; 73818232Slinton curinclindex++; 73918232Slinton in = f; 74018232Slinton errfilename = filename; 74118232Slinton errlineno = 1; 74218232Slinton } 74316928Ssam } 74416928Ssam 74518232Slinton private Boolean eofinput() 7469679Slinton { 74718232Slinton register Boolean b; 7489679Slinton 74918232Slinton if (curinclindex == 0) { 75018232Slinton if (isterm(in)) { 75118232Slinton putchar('\n'); 75218232Slinton clearerr(in); 75318232Slinton b = false; 75418232Slinton } else { 75518232Slinton b = true; 75618232Slinton } 75718232Slinton } else { 75818232Slinton fclose(in); 75918232Slinton --curinclindex; 76018232Slinton in = inclinfo[curinclindex].savefile; 76118232Slinton errfilename = inclinfo[curinclindex].savefn; 76218232Slinton errlineno = inclinfo[curinclindex].savelineno; 76318232Slinton b = false; 76418232Slinton } 76518232Slinton return b; 7669679Slinton } 7679679Slinton 7689679Slinton /* 76918232Slinton * Pop the current input. Return whether successful. 7709679Slinton */ 77118232Slinton 77218232Slinton public Boolean popinput() 77316928Ssam { 77418232Slinton Boolean b; 7759679Slinton 77618232Slinton if (curinclindex == 0) { 77718232Slinton b = false; 77818232Slinton } else { 77918232Slinton b = (Boolean) (not eofinput()); 78018232Slinton } 78118232Slinton return b; 7829679Slinton } 7839679Slinton 7849679Slinton /* 78516928Ssam * Return whether we are currently reading from standard input. 7869679Slinton */ 78718232Slinton 78816928Ssam public Boolean isstdin() 78916928Ssam { 79018232Slinton return (Boolean) (in == stdin); 79118232Slinton } 7929679Slinton 79318232Slinton /* 79418232Slinton * Send the current line to the shell. 79518232Slinton */ 79618232Slinton 79718232Slinton public shellline() 79818232Slinton { 79918232Slinton register char *p; 80018232Slinton 80118232Slinton p = curchar; 80218232Slinton while (*p != '\0' and (*p == '\n' or lexclass[*p] == WHITE)) { 80318232Slinton ++p; 80418232Slinton } 80518232Slinton shell(p); 80618232Slinton if (*p == '\0' and isterm(in)) { 80718232Slinton putchar('\n'); 80818232Slinton } 80918232Slinton erecover(); 81016928Ssam } 81116928Ssam 81218232Slinton /* 81318232Slinton * Read the rest of the current line in "shell mode". 81418232Slinton */ 81518232Slinton 81618232Slinton public beginshellmode() 8179679Slinton { 81818232Slinton shellmode = true; 81918232Slinton } 82016928Ssam 82118232Slinton /* 82218232Slinton * Print out a token for debugging. 82318232Slinton */ 82418232Slinton 82518232Slinton public print_token(f, t) 82618232Slinton File f; 82718232Slinton Token t; 82818232Slinton { 82918232Slinton if (t == '\n') { 83018232Slinton fprintf(f, "char '\\n'"); 83118232Slinton } else if (t == EOF) { 83218232Slinton fprintf(f, "EOF"); 83318232Slinton } else if (t < 256) { 83418232Slinton fprintf(f, "char '%c'", t); 83518232Slinton } else { 83618232Slinton fprintf(f, "\"%s\"", keywdstring(t)); 83718232Slinton } 8389679Slinton } 839