121622Sdist /* 2*38105Sbostic * Copyright (c) 1983 The Regents of the University of California. 3*38105Sbostic * All rights reserved. 4*38105Sbostic * 5*38105Sbostic * Redistribution and use in source and binary forms are permitted 6*38105Sbostic * provided that the above copyright notice and this paragraph are 7*38105Sbostic * duplicated in all such forms and that any documentation, 8*38105Sbostic * advertising materials, and other materials related to such 9*38105Sbostic * distribution and use acknowledge that the software was developed 10*38105Sbostic * by the University of California, Berkeley. The name of the 11*38105Sbostic * University may not be used to endorse or promote products derived 12*38105Sbostic * from this software without specific prior written permission. 13*38105Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*38105Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*38105Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621622Sdist */ 179679Slinton 1821622Sdist #ifndef lint 19*38105Sbostic static char sccsid[] = "@(#)scanner.c 5.2 (Berkeley) 05/23/89"; 20*38105Sbostic #endif /* not lint */ 219679Slinton 229679Slinton /* 239679Slinton * Debugger scanner. 249679Slinton */ 259679Slinton 269679Slinton #include "defs.h" 279679Slinton #include "scanner.h" 289679Slinton #include "main.h" 299679Slinton #include "keywords.h" 309679Slinton #include "tree.h" 319679Slinton #include "symbols.h" 329679Slinton #include "names.h" 339679Slinton #include "y.tab.h" 349679Slinton 359679Slinton #ifndef public 369679Slinton typedef int Token; 379679Slinton 3818232Slinton #define MAXLINESIZE 10240 399679Slinton 4018232Slinton #endif 419679Slinton 4216928Ssam public String initfile = ".dbxinit"; 439679Slinton 4418232Slinton typedef enum { WHITE, ALPHA, NUM, OTHER } Charclass; 4518232Slinton 4618232Slinton private Charclass class[256 + 1]; 4718232Slinton private Charclass *lexclass = class + 1; 4818232Slinton 4918232Slinton #define isdigit(c) (lexclass[c] == NUM) 5018232Slinton #define isalnum(c) (lexclass[c] == ALPHA or lexclass[c] == NUM) 5118232Slinton #define ishexdigit(c) ( \ 5218232Slinton isdigit(c) or (c >= 'a' and c <= 'f') or (c >= 'A' and c <= 'F') \ 5318232Slinton ) 5418232Slinton 5518232Slinton public boolean chkalias; 5618232Slinton public char scanner_linebuf[MAXLINESIZE]; 5718232Slinton 5818232Slinton private File in; 5918232Slinton private char *curchar, *prevchar; 6018232Slinton 6118232Slinton #define MAXINCLDEPTH 10 6218232Slinton 6318232Slinton private struct { 6418232Slinton File savefile; 6518232Slinton Filename savefn; 6618232Slinton int savelineno; 6718232Slinton } inclinfo[MAXINCLDEPTH]; 6818232Slinton 6918232Slinton private unsigned int curinclindex; 7018232Slinton 719679Slinton private Token getident(); 729679Slinton private Token getnum(); 739679Slinton private Token getstring(); 7418232Slinton private Boolean eofinput(); 7518232Slinton private char charcon(); 769679Slinton 7718232Slinton private enterlexclass(class, s) 7818232Slinton Charclass class; 7918232Slinton String s; 8018232Slinton { 8118232Slinton register char *p; 829679Slinton 8318232Slinton for (p = s; *p != '\0'; p++) { 8418232Slinton lexclass[*p] = class; 8518232Slinton } 8618232Slinton } 8718232Slinton 889679Slinton public scanner_init() 899679Slinton { 9018232Slinton register Integer i; 919679Slinton 9218232Slinton for (i = 0; i < 257; i++) { 9318232Slinton class[i] = OTHER; 9418232Slinton } 9518232Slinton enterlexclass(WHITE, " \t"); 9618232Slinton enterlexclass(ALPHA, "abcdefghijklmnopqrstuvwxyz"); 9718232Slinton enterlexclass(ALPHA, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_$"); 9818232Slinton enterlexclass(NUM, "0123456789"); 9918232Slinton in = stdin; 10018232Slinton errfilename = nil; 10118232Slinton errlineno = 0; 10218232Slinton curchar = scanner_linebuf; 10318232Slinton scanner_linebuf[0] = '\0'; 10418232Slinton chkalias = true; 1059679Slinton } 1069679Slinton 1079679Slinton /* 1089679Slinton * Read a single token. 10918232Slinton * 11018232Slinton * The input is line buffered. Tokens cannot cross line boundaries. 11118232Slinton * 1129679Slinton * There are two "modes" of operation: one as in a compiler, 11318232Slinton * and one for reading shell-like syntax. In the first mode 11418232Slinton * there is the additional choice of doing alias processing. 1159679Slinton */ 11618232Slinton 11718232Slinton private Boolean shellmode; 11818232Slinton 1199679Slinton public Token yylex() 1209679Slinton { 12118232Slinton register int c; 12218232Slinton register char *p; 12318232Slinton register Token t; 12418232Slinton String line; 12518232Slinton integer n; 1269679Slinton 12718232Slinton p = curchar; 12818232Slinton if (*p == '\0') { 12918232Slinton do { 13018232Slinton if (isterm(in)) { 13118232Slinton printf("(%s) ", cmdname); 13218232Slinton } 13318232Slinton fflush(stdout); 13418232Slinton line = fgets(scanner_linebuf, MAXLINESIZE, in); 13518232Slinton } while (line == nil and not eofinput()); 13618232Slinton if (line == nil) { 13718232Slinton c = EOF; 13818232Slinton } else { 13918232Slinton p = scanner_linebuf; 14018232Slinton while (lexclass[*p] == WHITE) { 14118232Slinton p++; 14218232Slinton } 14318232Slinton shellmode = false; 1449679Slinton } 14518232Slinton chkalias = true; 14618232Slinton } else { 14718232Slinton while (lexclass[*p] == WHITE) { 14818232Slinton p++; 1499679Slinton } 15018232Slinton } 15118232Slinton curchar = p; 15218232Slinton prevchar = curchar; 15318232Slinton c = *p; 15418232Slinton if (lexclass[c] == ALPHA) { 15518232Slinton t = getident(chkalias); 15618232Slinton } else if (lexclass[c] == NUM) { 15718232Slinton if (shellmode) { 15818232Slinton t = getident(chkalias); 15918232Slinton } else { 16018232Slinton t = getnum(); 16112120Slinton } 16218232Slinton } else { 16318232Slinton ++curchar; 1649679Slinton switch (c) { 16518232Slinton case '\n': 1669679Slinton t = '\n'; 16718232Slinton if (errlineno != 0) { 16818232Slinton errlineno++; 1699679Slinton } 1709679Slinton break; 1719679Slinton 17218232Slinton case '"': 17318232Slinton case '\'': 17416928Ssam t = getstring(c); 1759679Slinton break; 1769679Slinton 17718232Slinton case '.': 1789679Slinton if (shellmode) { 17918232Slinton --curchar; 18018232Slinton t = getident(chkalias); 18118232Slinton } else if (isdigit(*curchar)) { 18218232Slinton --curchar; 18318232Slinton t = getnum(); 18418232Slinton } else { 18518232Slinton t = '.'; 1869679Slinton } 1879679Slinton break; 1889679Slinton 18918232Slinton case '-': 19018232Slinton if (shellmode) { 19118232Slinton --curchar; 19218232Slinton t = getident(chkalias); 19318232Slinton } else if (*curchar == '>') { 19418232Slinton ++curchar; 19518232Slinton t = ARROW; 19618232Slinton } else { 19718232Slinton t = '-'; 19818232Slinton } 1999679Slinton break; 2009679Slinton 20118232Slinton case '#': 20218232Slinton if (not isterm(in)) { 20318232Slinton *p = '\0'; 20418232Slinton curchar = p; 20518232Slinton t = '\n'; 20618232Slinton ++errlineno; 20718232Slinton } else { 20818232Slinton t = '#'; 20918232Slinton } 2109679Slinton break; 2119679Slinton 21218232Slinton case '\\': 21318232Slinton if (*(p+1) == '\n') { 21418232Slinton n = MAXLINESIZE - (p - &scanner_linebuf[0]); 21518232Slinton if (n > 1) { 21618232Slinton if (fgets(p, n, in) == nil) { 21718232Slinton t = 0; 21818232Slinton } else { 21918232Slinton curchar = p; 22018232Slinton t = yylex(); 22118232Slinton } 22218232Slinton } else { 22318232Slinton t = '\\'; 22418232Slinton } 22518232Slinton } else { 22618232Slinton t = '\\'; 2279679Slinton } 2289679Slinton break; 2299679Slinton 23018232Slinton case EOF: 2319679Slinton t = 0; 2329679Slinton break; 2339679Slinton 23418232Slinton default: 23518232Slinton if (shellmode and index("!&*<>()[]", c) == nil) { 23618232Slinton --curchar; 23718232Slinton t = getident(chkalias); 23818232Slinton } else { 23918232Slinton t = c; 24018232Slinton } 2419679Slinton break; 2429679Slinton } 24318232Slinton } 24418232Slinton chkalias = false; 24518232Slinton # ifdef LEXDEBUG 2469679Slinton if (lexdebug) { 24718232Slinton fprintf(stderr, "yylex returns "); 24818232Slinton print_token(stderr, t); 24918232Slinton fprintf(stderr, "\n"); 2509679Slinton } 25118232Slinton # endif 25218232Slinton return t; 2539679Slinton } 2549679Slinton 2559679Slinton /* 25618232Slinton * Put the given string before the current character 25718232Slinton * in the current line, thus inserting it into the input stream. 2589679Slinton */ 2599679Slinton 26018232Slinton public insertinput (s) 26118232Slinton String s; 2629679Slinton { 26318232Slinton register char *p, *q; 26418232Slinton int need, avail, shift; 2659679Slinton 26618232Slinton q = s; 26718232Slinton need = strlen(q); 26818232Slinton avail = curchar - &scanner_linebuf[0]; 26918232Slinton if (need <= avail) { 27018232Slinton curchar = &scanner_linebuf[avail - need]; 27118232Slinton p = curchar; 27218232Slinton while (*q != '\0') { 27318232Slinton *p++ = *q++; 27416928Ssam } 27518232Slinton } else { 27618232Slinton p = curchar; 27718232Slinton while (*p != '\0') { 27818232Slinton ++p; 2799679Slinton } 28018232Slinton shift = need - avail; 28118232Slinton if (p + shift >= &scanner_linebuf[MAXLINESIZE]) { 28218232Slinton error("alias expansion too large"); 2839679Slinton } 28418232Slinton for (;;) { 28518232Slinton *(p + shift) = *p; 28618232Slinton if (p == curchar) { 2879679Slinton break; 28818232Slinton } 28918232Slinton --p; 2909679Slinton } 29118232Slinton p = &scanner_linebuf[0]; 29218232Slinton while (*q != '\0') { 29318232Slinton *p++ = *q++; 29418232Slinton } 29518232Slinton curchar = &scanner_linebuf[0]; 29618232Slinton } 2979679Slinton } 2989679Slinton 2999679Slinton /* 30018232Slinton * Get the actuals for a macro call. 3019679Slinton */ 3029679Slinton 30318232Slinton private String movetochar (str, c) 30418232Slinton String str; 30518232Slinton char c; 3069679Slinton { 30718232Slinton register char *p; 3089679Slinton 30918232Slinton while (*p != c) { 31018232Slinton if (*p == '\0') { 31118232Slinton error("missing ')' in macro call"); 31218232Slinton } else if (*p == ')') { 31318232Slinton error("not enough parameters in macro call"); 31418232Slinton } else if (*p == ',') { 31518232Slinton error("too many parameters in macro call"); 3169679Slinton } 31718232Slinton ++p; 31818232Slinton } 31918232Slinton return p; 3209679Slinton } 3219679Slinton 32218232Slinton private String *getactuals (n) 32318232Slinton integer n; 3249679Slinton { 32518232Slinton String *a; 32618232Slinton register char *p; 32718232Slinton int i; 3289679Slinton 32918232Slinton a = newarr(String, n); 33018232Slinton p = curchar; 33118232Slinton while (*p != '(') { 33218232Slinton if (lexclass[*p] != WHITE) { 33318232Slinton error("missing actuals for macro"); 3349679Slinton } 33518232Slinton ++p; 33618232Slinton } 33718232Slinton ++p; 33818232Slinton for (i = 0; i < n - 1; i++) { 33918232Slinton a[i] = p; 34018232Slinton p = movetochar(p, ','); 34118232Slinton *p = '\0'; 34218232Slinton ++p; 34318232Slinton } 34418232Slinton a[n-1] = p; 34518232Slinton p = movetochar(p, ')'); 34618232Slinton *p = '\0'; 34718232Slinton curchar = p + 1; 34818232Slinton return a; 3499679Slinton } 3509679Slinton 3519679Slinton /* 35218232Slinton * Do command macro expansion, assuming curchar points to the beginning 35318232Slinton * of the actuals, and we are not in shell mode. 3549679Slinton */ 35518232Slinton 35618232Slinton private expand (pl, str) 35718232Slinton List pl; 35818232Slinton String str; 3599679Slinton { 36018232Slinton char buf[4096], namebuf[100]; 36118232Slinton register char *p, *q, *r; 36218232Slinton String *actual; 36318232Slinton Name n; 36418232Slinton integer i; 36518232Slinton boolean match; 3669679Slinton 36718232Slinton if (pl == nil) { 36818232Slinton insertinput(str); 36918232Slinton } else { 37018232Slinton actual = getactuals(list_size(pl)); 37118232Slinton p = buf; 37218232Slinton q = str; 37318232Slinton while (*q != '\0') { 37418232Slinton if (p >= &buf[4096]) { 37518232Slinton error("alias expansion too large"); 37618232Slinton } 37718232Slinton if (lexclass[*q] == ALPHA) { 37818232Slinton r = namebuf; 37918232Slinton do { 38018232Slinton *r++ = *q++; 38118232Slinton } while (isalnum(*q)); 38218232Slinton *r = '\0'; 38318232Slinton i = 0; 38418232Slinton match = false; 38518232Slinton foreach(Name, n, pl) 38618232Slinton if (streq(ident(n), namebuf)) { 38718232Slinton match = true; 38818232Slinton break; 38918232Slinton } 39018232Slinton ++i; 39118232Slinton endfor 39218232Slinton if (match) { 39318232Slinton r = actual[i]; 39418232Slinton } else { 39518232Slinton r = namebuf; 39616928Ssam } 39718232Slinton while (*r != '\0') { 39818232Slinton *p++ = *r++; 39918232Slinton } 40018232Slinton } else { 40118232Slinton *p++ = *q++; 40218232Slinton } 4039679Slinton } 40418232Slinton *p = '\0'; 40518232Slinton insertinput(buf); 40618232Slinton } 4079679Slinton } 4089679Slinton 4099679Slinton /* 41016928Ssam * Parser error handling. 4119679Slinton */ 41218232Slinton 41316928Ssam public yyerror(s) 4149679Slinton String s; 4159679Slinton { 41618232Slinton register char *p; 41718232Slinton register integer start; 4189679Slinton 41918232Slinton if (streq(s, "syntax error")) { 42018232Slinton beginerrmsg(); 42118232Slinton p = prevchar; 42218232Slinton start = p - &scanner_linebuf[0]; 42318232Slinton if (p > &scanner_linebuf[0]) { 42418232Slinton while (lexclass[*p] == WHITE and p > &scanner_linebuf[0]) { 42518232Slinton --p; 42618232Slinton } 4279679Slinton } 42818232Slinton fprintf(stderr, "%s", scanner_linebuf); 42918232Slinton if (start != 0) { 43018232Slinton fprintf(stderr, "%*c", start, ' '); 43118232Slinton } 43218232Slinton if (p == &scanner_linebuf[0]) { 43318232Slinton fprintf(stderr, "^ unrecognized command"); 43418232Slinton } else { 43518232Slinton fprintf(stderr, "^ syntax error"); 43618232Slinton } 43718232Slinton enderrmsg(); 43818232Slinton } else { 43916928Ssam error(s); 44018232Slinton } 4419679Slinton } 4429679Slinton 4439679Slinton /* 44416928Ssam * Eat the current line. 44516928Ssam */ 44616928Ssam 44718232Slinton public gobble () 44816928Ssam { 44918232Slinton curchar = scanner_linebuf; 45018232Slinton scanner_linebuf[0] = '\0'; 45116928Ssam } 45216928Ssam 45316928Ssam /* 45418232Slinton * Scan an identifier. 45518232Slinton * 45618232Slinton * If chkalias is true, check first to see if it's an alias. 45718232Slinton * Otherwise, check to see if it's a keyword. 4589679Slinton */ 45918232Slinton 46018232Slinton private Token getident (chkalias) 46118232Slinton boolean chkalias; 4629679Slinton { 46318232Slinton char buf[1024]; 46418232Slinton register char *p, *q; 46518232Slinton register Token t; 46618232Slinton List pl; 46718232Slinton String str; 4689679Slinton 46918232Slinton p = curchar; 47018232Slinton q = buf; 47118232Slinton if (shellmode) { 47218232Slinton do { 47318232Slinton *q++ = *p++; 47418232Slinton } while (index(" \t\n!&<>*[]()'\"", *p) == nil); 47518232Slinton } else { 47618232Slinton do { 47718232Slinton *q++ = *p++; 47818232Slinton } while (isalnum(*p)); 47918232Slinton } 48018232Slinton curchar = p; 48118232Slinton *q = '\0'; 48218232Slinton yylval.y_name = identname(buf, false); 48318232Slinton if (chkalias) { 48418232Slinton if (findalias(yylval.y_name, &pl, &str)) { 48518232Slinton expand(pl, str); 48618232Slinton while (lexclass[*curchar] == WHITE) { 48718232Slinton ++curchar; 48818232Slinton } 48918232Slinton if (pl == nil) { 49018232Slinton t = getident(false); 49118232Slinton } else { 49218232Slinton t = getident(true); 49318232Slinton } 49418232Slinton } else if (shellmode) { 49518232Slinton t = NAME; 49618232Slinton } else { 49718232Slinton t = findkeyword(yylval.y_name, NAME); 4989679Slinton } 49918232Slinton } else if (shellmode) { 50018232Slinton t = NAME; 50118232Slinton } else { 50218232Slinton t = findkeyword(yylval.y_name, NAME); 50318232Slinton } 50418232Slinton return t; 5059679Slinton } 5069679Slinton 50716928Ssam /* 50818232Slinton * Scan a number. 50916928Ssam */ 51018232Slinton 51118232Slinton private Token getnum() 5129679Slinton { 51318232Slinton char buf[1024]; 51418232Slinton register Char *p, *q; 51518232Slinton register Token t; 51618232Slinton Integer base; 5179679Slinton 51818232Slinton p = curchar; 51918232Slinton q = buf; 52018232Slinton if (*p == '0') { 52118232Slinton if (*(p+1) == 'x') { 52218232Slinton p += 2; 52318232Slinton base = 16; 52418232Slinton } else if (*(p+1) == 't') { 52518232Slinton base = 10; 52618232Slinton } else if (varIsSet("$hexin")) { 52718232Slinton base = 16; 52818232Slinton } else { 52918232Slinton base = 8; 53018232Slinton } 53118232Slinton } else if (varIsSet("$hexin")) { 53218232Slinton base = 16; 53318232Slinton } else if (varIsSet("$octin")) { 53418232Slinton base = 8; 53518232Slinton } else { 53618232Slinton base = 10; 53718232Slinton } 53818232Slinton if (base == 16) { 53918232Slinton do { 54018232Slinton *q++ = *p++; 54118232Slinton } while (ishexdigit(*p)); 54218232Slinton } else { 54318232Slinton do { 54418232Slinton *q++ = *p++; 54518232Slinton } while (isdigit(*p)); 54618232Slinton } 54718232Slinton if (*p == '.') { 54818232Slinton do { 54918232Slinton *q++ = *p++; 55018232Slinton } while (isdigit(*p)); 55118232Slinton if (*p == 'e' or *p == 'E') { 55218232Slinton p++; 55318232Slinton if (*p == '+' or *p == '-' or isdigit(*p)) { 55418232Slinton *q++ = 'e'; 55518232Slinton do { 55618232Slinton *q++ = *p++; 55718232Slinton } while (isdigit(*p)); 55818232Slinton } 55918232Slinton } 56018232Slinton *q = '\0'; 56118232Slinton yylval.y_real = atof(buf); 56218232Slinton t = REAL; 56318232Slinton } else { 56418232Slinton *q = '\0'; 56518232Slinton switch (base) { 56618232Slinton case 10: 56718232Slinton yylval.y_int = atol(buf); 56818232Slinton break; 56918232Slinton 57018232Slinton case 8: 57118232Slinton yylval.y_int = octal(buf); 57218232Slinton break; 57318232Slinton 57418232Slinton case 16: 57518232Slinton yylval.y_int = hex(buf); 57618232Slinton break; 57718232Slinton 57818232Slinton default: 57918232Slinton badcaseval(base); 58018232Slinton } 58118232Slinton t = INT; 58218232Slinton } 58318232Slinton curchar = p; 58418232Slinton return t; 5859679Slinton } 5869679Slinton 5879679Slinton /* 58818232Slinton * Convert a string of octal digits to an integer. 5899679Slinton */ 5909679Slinton 59118232Slinton private int octal(s) 59218232Slinton String s; 5939679Slinton { 59418232Slinton register Char *p; 59518232Slinton register Integer n; 5969679Slinton 59718232Slinton n = 0; 59818232Slinton for (p = s; *p != '\0'; p++) { 59918232Slinton n = 8*n + (*p - '0'); 60018232Slinton } 60118232Slinton return n; 6029679Slinton } 6039679Slinton 60418232Slinton /* 60518232Slinton * Convert a string of hexadecimal digits to an integer. 60618232Slinton */ 60716928Ssam 60818232Slinton private int hex(s) 60918232Slinton String s; 61016928Ssam { 61118232Slinton register Char *p; 61218232Slinton register Integer n; 61316928Ssam 61418232Slinton n = 0; 61518232Slinton for (p = s; *p != '\0'; p++) { 61618232Slinton n *= 16; 61718232Slinton if (*p >= 'a' and *p <= 'f') { 61818232Slinton n += (*p - 'a' + 10); 61918232Slinton } else if (*p >= 'A' and *p <= 'F') { 62018232Slinton n += (*p - 'A' + 10); 62118232Slinton } else { 62218232Slinton n += (*p - '0'); 62318232Slinton } 62418232Slinton } 62518232Slinton return n; 62616928Ssam } 62716928Ssam 6289679Slinton /* 62918232Slinton * Scan a string. 6309679Slinton */ 63118232Slinton 63218232Slinton private Token getstring (quote) 63318232Slinton char quote; 63416928Ssam { 63518232Slinton register char *p, *q; 63618232Slinton char buf[MAXLINESIZE]; 63718232Slinton boolean endofstring; 63818232Slinton Token t; 6399679Slinton 64018232Slinton p = curchar; 64118232Slinton q = buf; 64218232Slinton endofstring = false; 64318232Slinton while (not endofstring) { 64418232Slinton if (*p == '\\' and *(p+1) == '\n') { 64518232Slinton if (fgets(scanner_linebuf, MAXLINESIZE, in) == nil) { 64618232Slinton error("non-terminated string"); 64718232Slinton } 64818232Slinton p = &scanner_linebuf[0] - 1; 64918232Slinton } else if (*p == '\n' or *p == '\0') { 65018232Slinton error("non-terminated string"); 65118232Slinton endofstring = true; 65218232Slinton } else if (*p == quote) { 65318232Slinton endofstring = true; 65418232Slinton } else { 65518232Slinton curchar = p; 65618232Slinton *q++ = charcon(p); 65718232Slinton p = curchar; 65816928Ssam } 65918232Slinton p++; 66018232Slinton } 66118232Slinton curchar = p; 66218232Slinton *q = '\0'; 66318232Slinton if (quote == '\'' and buf[1] == '\0') { 66418232Slinton yylval.y_char = buf[0]; 66518232Slinton t = CHAR; 66618232Slinton } else { 66718232Slinton yylval.y_string = strdup(buf); 66818232Slinton t = STRING; 66918232Slinton } 67018232Slinton return t; 67116928Ssam } 67216928Ssam 67318232Slinton /* 67418232Slinton * Process a character constant. 67518232Slinton * Watch out for backslashes. 67618232Slinton */ 67718232Slinton 67818232Slinton private char charcon (s) 67918232Slinton String s; 6809679Slinton { 68118232Slinton register char *p, *q; 68218232Slinton char c, buf[10]; 68316928Ssam 68418232Slinton p = s; 68518232Slinton if (*p == '\\') { 68618232Slinton ++p; 68718232Slinton switch (*p) { 68818232Slinton case '\\': 68918232Slinton c = '\\'; 69018232Slinton break; 69116928Ssam 69218232Slinton case 'n': 69318232Slinton c = '\n'; 69416928Ssam break; 69516928Ssam 69618232Slinton case 'r': 69718232Slinton c = '\r'; 69816928Ssam break; 69916928Ssam 70018232Slinton case 't': 70118232Slinton c = '\t'; 70218232Slinton break; 7039679Slinton 70418232Slinton case '\'': 70518232Slinton case '"': 70618232Slinton c = *p; 70716928Ssam break; 70816928Ssam 70918232Slinton default: 71018232Slinton if (isdigit(*p)) { 71118232Slinton q = buf; 71218232Slinton do { 71318232Slinton *q++ = *p++; 71418232Slinton } while (isdigit(*p)); 71518232Slinton *q = '\0'; 71618232Slinton c = (char) octal(buf); 71718232Slinton } 71818232Slinton --p; 71916928Ssam break; 72016928Ssam } 72118232Slinton curchar = p; 72218232Slinton } else { 72318232Slinton c = *p; 72418232Slinton } 72518232Slinton return c; 72616928Ssam } 72716928Ssam 7289679Slinton /* 72918232Slinton * Input file management routines. 7309679Slinton */ 73118232Slinton 73218232Slinton public setinput(filename) 73318232Slinton Filename filename; 73416928Ssam { 73518232Slinton File f; 7369679Slinton 73718232Slinton f = fopen(filename, "r"); 73818232Slinton if (f == nil) { 73918232Slinton error("can't open %s", filename); 74018232Slinton } else { 74118232Slinton if (curinclindex >= MAXINCLDEPTH) { 74218232Slinton error("unreasonable input nesting on \"%s\"", filename); 74316928Ssam } 74418232Slinton inclinfo[curinclindex].savefile = in; 74518232Slinton inclinfo[curinclindex].savefn = errfilename; 74618232Slinton inclinfo[curinclindex].savelineno = errlineno; 74718232Slinton curinclindex++; 74818232Slinton in = f; 74918232Slinton errfilename = filename; 75018232Slinton errlineno = 1; 75118232Slinton } 75216928Ssam } 75316928Ssam 75418232Slinton private Boolean eofinput() 7559679Slinton { 75618232Slinton register Boolean b; 7579679Slinton 75818232Slinton if (curinclindex == 0) { 75918232Slinton if (isterm(in)) { 76018232Slinton putchar('\n'); 76118232Slinton clearerr(in); 76218232Slinton b = false; 76318232Slinton } else { 76418232Slinton b = true; 76518232Slinton } 76618232Slinton } else { 76718232Slinton fclose(in); 76818232Slinton --curinclindex; 76918232Slinton in = inclinfo[curinclindex].savefile; 77018232Slinton errfilename = inclinfo[curinclindex].savefn; 77118232Slinton errlineno = inclinfo[curinclindex].savelineno; 77218232Slinton b = false; 77318232Slinton } 77418232Slinton return b; 7759679Slinton } 7769679Slinton 7779679Slinton /* 77818232Slinton * Pop the current input. Return whether successful. 7799679Slinton */ 78018232Slinton 78118232Slinton public Boolean popinput() 78216928Ssam { 78318232Slinton Boolean b; 7849679Slinton 78518232Slinton if (curinclindex == 0) { 78618232Slinton b = false; 78718232Slinton } else { 78818232Slinton b = (Boolean) (not eofinput()); 78918232Slinton } 79018232Slinton return b; 7919679Slinton } 7929679Slinton 7939679Slinton /* 79416928Ssam * Return whether we are currently reading from standard input. 7959679Slinton */ 79618232Slinton 79716928Ssam public Boolean isstdin() 79816928Ssam { 79918232Slinton return (Boolean) (in == stdin); 80018232Slinton } 8019679Slinton 80218232Slinton /* 80318232Slinton * Send the current line to the shell. 80418232Slinton */ 80518232Slinton 80618232Slinton public shellline() 80718232Slinton { 80818232Slinton register char *p; 80918232Slinton 81018232Slinton p = curchar; 81118232Slinton while (*p != '\0' and (*p == '\n' or lexclass[*p] == WHITE)) { 81218232Slinton ++p; 81318232Slinton } 81418232Slinton shell(p); 81518232Slinton if (*p == '\0' and isterm(in)) { 81618232Slinton putchar('\n'); 81718232Slinton } 81818232Slinton erecover(); 81916928Ssam } 82016928Ssam 82118232Slinton /* 82218232Slinton * Read the rest of the current line in "shell mode". 82318232Slinton */ 82418232Slinton 82518232Slinton public beginshellmode() 8269679Slinton { 82718232Slinton shellmode = true; 82818232Slinton } 82916928Ssam 83018232Slinton /* 83118232Slinton * Print out a token for debugging. 83218232Slinton */ 83318232Slinton 83418232Slinton public print_token(f, t) 83518232Slinton File f; 83618232Slinton Token t; 83718232Slinton { 83818232Slinton if (t == '\n') { 83918232Slinton fprintf(f, "char '\\n'"); 84018232Slinton } else if (t == EOF) { 84118232Slinton fprintf(f, "EOF"); 84218232Slinton } else if (t < 256) { 84318232Slinton fprintf(f, "char '%c'", t); 84418232Slinton } else { 84518232Slinton fprintf(f, "\"%s\"", keywdstring(t)); 84618232Slinton } 8479679Slinton } 848