xref: /csrg-svn/old/dbx/scanner.c (revision 21622)
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