xref: /csrg-svn/old/dbx/scanner.c (revision 42685)
121622Sdist /*
238105Sbostic  * Copyright (c) 1983 The Regents of the University of California.
338105Sbostic  * All rights reserved.
438105Sbostic  *
5*42685Sbostic  * %sccs.include.redist.c%
621622Sdist  */
79679Slinton 
821622Sdist #ifndef lint
9*42685Sbostic static char sccsid[] = "@(#)scanner.c	5.3 (Berkeley) 06/01/90";
1038105Sbostic #endif /* not lint */
119679Slinton 
129679Slinton /*
139679Slinton  * Debugger scanner.
149679Slinton  */
159679Slinton 
169679Slinton #include "defs.h"
179679Slinton #include "scanner.h"
189679Slinton #include "main.h"
199679Slinton #include "keywords.h"
209679Slinton #include "tree.h"
219679Slinton #include "symbols.h"
229679Slinton #include "names.h"
239679Slinton #include "y.tab.h"
249679Slinton 
259679Slinton #ifndef public
269679Slinton typedef int Token;
279679Slinton 
2818232Slinton #define MAXLINESIZE 10240
299679Slinton 
3018232Slinton #endif
319679Slinton 
3216928Ssam public String initfile = ".dbxinit";
339679Slinton 
3418232Slinton typedef enum { WHITE, ALPHA, NUM, OTHER } Charclass;
3518232Slinton 
3618232Slinton private Charclass class[256 + 1];
3718232Slinton private Charclass *lexclass = class + 1;
3818232Slinton 
3918232Slinton #define isdigit(c) (lexclass[c] == NUM)
4018232Slinton #define isalnum(c) (lexclass[c] == ALPHA or lexclass[c] == NUM)
4118232Slinton #define ishexdigit(c) ( \
4218232Slinton     isdigit(c) or (c >= 'a' and c <= 'f') or (c >= 'A' and c <= 'F') \
4318232Slinton )
4418232Slinton 
4518232Slinton public boolean chkalias;
4618232Slinton public char scanner_linebuf[MAXLINESIZE];
4718232Slinton 
4818232Slinton private File in;
4918232Slinton private char *curchar, *prevchar;
5018232Slinton 
5118232Slinton #define MAXINCLDEPTH 10
5218232Slinton 
5318232Slinton private struct {
5418232Slinton     File savefile;
5518232Slinton     Filename savefn;
5618232Slinton     int savelineno;
5718232Slinton } inclinfo[MAXINCLDEPTH];
5818232Slinton 
5918232Slinton private unsigned int curinclindex;
6018232Slinton 
619679Slinton private Token getident();
629679Slinton private Token getnum();
639679Slinton private Token getstring();
6418232Slinton private Boolean eofinput();
6518232Slinton private char charcon();
669679Slinton 
enterlexclass(class,s)6718232Slinton private enterlexclass(class, s)
6818232Slinton Charclass class;
6918232Slinton String s;
7018232Slinton {
7118232Slinton     register char *p;
729679Slinton 
7318232Slinton     for (p = s; *p != '\0'; p++) {
7418232Slinton 	lexclass[*p] = class;
7518232Slinton     }
7618232Slinton }
7718232Slinton 
scanner_init()789679Slinton public scanner_init()
799679Slinton {
8018232Slinton     register Integer i;
819679Slinton 
8218232Slinton     for (i = 0; i < 257; i++) {
8318232Slinton 	class[i] = OTHER;
8418232Slinton     }
8518232Slinton     enterlexclass(WHITE, " \t");
8618232Slinton     enterlexclass(ALPHA, "abcdefghijklmnopqrstuvwxyz");
8718232Slinton     enterlexclass(ALPHA, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_$");
8818232Slinton     enterlexclass(NUM, "0123456789");
8918232Slinton     in = stdin;
9018232Slinton     errfilename = nil;
9118232Slinton     errlineno = 0;
9218232Slinton     curchar = scanner_linebuf;
9318232Slinton     scanner_linebuf[0] = '\0';
9418232Slinton     chkalias = true;
959679Slinton }
969679Slinton 
979679Slinton /*
989679Slinton  * Read a single token.
9918232Slinton  *
10018232Slinton  * The input is line buffered.  Tokens cannot cross line boundaries.
10118232Slinton  *
1029679Slinton  * There are two "modes" of operation:  one as in a compiler,
10318232Slinton  * and one for reading shell-like syntax.  In the first mode
10418232Slinton  * there is the additional choice of doing alias processing.
1059679Slinton  */
10618232Slinton 
10718232Slinton private Boolean shellmode;
10818232Slinton 
yylex()1099679Slinton public Token yylex()
1109679Slinton {
11118232Slinton     register int c;
11218232Slinton     register char *p;
11318232Slinton     register Token t;
11418232Slinton     String line;
11518232Slinton     integer n;
1169679Slinton 
11718232Slinton     p = curchar;
11818232Slinton     if (*p == '\0') {
11918232Slinton 	do {
12018232Slinton 	    if (isterm(in)) {
12118232Slinton 		printf("(%s) ", cmdname);
12218232Slinton 	    }
12318232Slinton 	    fflush(stdout);
12418232Slinton 	    line = fgets(scanner_linebuf, MAXLINESIZE, in);
12518232Slinton 	} while (line == nil and not eofinput());
12618232Slinton 	if (line == nil) {
12718232Slinton 	    c = EOF;
12818232Slinton 	} else {
12918232Slinton 	    p = scanner_linebuf;
13018232Slinton 	    while (lexclass[*p] == WHITE) {
13118232Slinton 		p++;
13218232Slinton 	    }
13318232Slinton 	    shellmode = false;
1349679Slinton 	}
13518232Slinton 	chkalias = true;
13618232Slinton     } else {
13718232Slinton 	while (lexclass[*p] == WHITE) {
13818232Slinton 	    p++;
1399679Slinton 	}
14018232Slinton     }
14118232Slinton     curchar = p;
14218232Slinton     prevchar = curchar;
14318232Slinton     c = *p;
14418232Slinton     if (lexclass[c] == ALPHA) {
14518232Slinton 	t = getident(chkalias);
14618232Slinton     } else if (lexclass[c] == NUM) {
14718232Slinton 	if (shellmode) {
14818232Slinton 	    t = getident(chkalias);
14918232Slinton 	} else {
15018232Slinton 	    t = getnum();
15112120Slinton 	}
15218232Slinton     } else {
15318232Slinton 	++curchar;
1549679Slinton 	switch (c) {
15518232Slinton 	    case '\n':
1569679Slinton 		t = '\n';
15718232Slinton 		if (errlineno != 0) {
15818232Slinton 		    errlineno++;
1599679Slinton 		}
1609679Slinton 		break;
1619679Slinton 
16218232Slinton 	    case '"':
16318232Slinton 	    case '\'':
16416928Ssam 		t = getstring(c);
1659679Slinton 		break;
1669679Slinton 
16718232Slinton 	    case '.':
1689679Slinton 		if (shellmode) {
16918232Slinton 		    --curchar;
17018232Slinton 		    t = getident(chkalias);
17118232Slinton 		} else if (isdigit(*curchar)) {
17218232Slinton 		    --curchar;
17318232Slinton 		    t = getnum();
17418232Slinton 		} else {
17518232Slinton 		    t = '.';
1769679Slinton 		}
1779679Slinton 		break;
1789679Slinton 
17918232Slinton 	    case '-':
18018232Slinton 		if (shellmode) {
18118232Slinton 		    --curchar;
18218232Slinton 		    t = getident(chkalias);
18318232Slinton 		} else if (*curchar == '>') {
18418232Slinton 		    ++curchar;
18518232Slinton 		    t = ARROW;
18618232Slinton 		} else {
18718232Slinton 		    t = '-';
18818232Slinton 		}
1899679Slinton 		break;
1909679Slinton 
19118232Slinton 	    case '#':
19218232Slinton 		if (not isterm(in)) {
19318232Slinton 		    *p = '\0';
19418232Slinton 		    curchar = p;
19518232Slinton 		    t = '\n';
19618232Slinton 		    ++errlineno;
19718232Slinton 		} else {
19818232Slinton 		    t = '#';
19918232Slinton 		}
2009679Slinton 		break;
2019679Slinton 
20218232Slinton 	    case '\\':
20318232Slinton 		if (*(p+1) == '\n') {
20418232Slinton 		    n = MAXLINESIZE - (p - &scanner_linebuf[0]);
20518232Slinton 		    if (n > 1) {
20618232Slinton 			if (fgets(p, n, in) == nil) {
20718232Slinton 			    t = 0;
20818232Slinton 			} else {
20918232Slinton 			    curchar = p;
21018232Slinton 			    t = yylex();
21118232Slinton 			}
21218232Slinton 		    } else {
21318232Slinton 			t = '\\';
21418232Slinton 		    }
21518232Slinton 		} else {
21618232Slinton 		    t = '\\';
2179679Slinton 		}
2189679Slinton 		break;
2199679Slinton 
22018232Slinton 	    case EOF:
2219679Slinton 		t = 0;
2229679Slinton 		break;
2239679Slinton 
22418232Slinton 	    default:
22518232Slinton 		if (shellmode and index("!&*<>()[]", c) == nil) {
22618232Slinton 		    --curchar;
22718232Slinton 		    t = getident(chkalias);
22818232Slinton 		} else {
22918232Slinton 		    t = c;
23018232Slinton 		}
2319679Slinton 		break;
2329679Slinton 	}
23318232Slinton     }
23418232Slinton     chkalias = false;
23518232Slinton #   ifdef LEXDEBUG
2369679Slinton 	if (lexdebug) {
23718232Slinton 	    fprintf(stderr, "yylex returns ");
23818232Slinton 	    print_token(stderr, t);
23918232Slinton 	    fprintf(stderr, "\n");
2409679Slinton 	}
24118232Slinton #   endif
24218232Slinton     return t;
2439679Slinton }
2449679Slinton 
2459679Slinton /*
24618232Slinton  * Put the given string before the current character
24718232Slinton  * in the current line, thus inserting it into the input stream.
2489679Slinton  */
2499679Slinton 
insertinput(s)25018232Slinton public insertinput (s)
25118232Slinton String s;
2529679Slinton {
25318232Slinton     register char *p, *q;
25418232Slinton     int need, avail, shift;
2559679Slinton 
25618232Slinton     q = s;
25718232Slinton     need = strlen(q);
25818232Slinton     avail = curchar - &scanner_linebuf[0];
25918232Slinton     if (need <= avail) {
26018232Slinton 	curchar = &scanner_linebuf[avail - need];
26118232Slinton 	p = curchar;
26218232Slinton 	while (*q != '\0') {
26318232Slinton 	    *p++ = *q++;
26416928Ssam 	}
26518232Slinton     } else {
26618232Slinton 	p = curchar;
26718232Slinton 	while (*p != '\0') {
26818232Slinton 	    ++p;
2699679Slinton 	}
27018232Slinton 	shift = need - avail;
27118232Slinton 	if (p + shift >= &scanner_linebuf[MAXLINESIZE]) {
27218232Slinton 	    error("alias expansion too large");
2739679Slinton 	}
27418232Slinton 	for (;;) {
27518232Slinton 	    *(p + shift) = *p;
27618232Slinton 	    if (p == curchar) {
2779679Slinton 		break;
27818232Slinton 	    }
27918232Slinton 	    --p;
2809679Slinton 	}
28118232Slinton 	p = &scanner_linebuf[0];
28218232Slinton 	while (*q != '\0') {
28318232Slinton 	    *p++ = *q++;
28418232Slinton 	}
28518232Slinton 	curchar = &scanner_linebuf[0];
28618232Slinton     }
2879679Slinton }
2889679Slinton 
2899679Slinton /*
29018232Slinton  * Get the actuals for a macro call.
2919679Slinton  */
2929679Slinton 
movetochar(str,c)29318232Slinton private String movetochar (str, c)
29418232Slinton String str;
29518232Slinton char c;
2969679Slinton {
29718232Slinton     register char *p;
2989679Slinton 
29918232Slinton     while (*p != c) {
30018232Slinton 	if (*p == '\0') {
30118232Slinton 	    error("missing ')' in macro call");
30218232Slinton 	} else if (*p == ')') {
30318232Slinton 	    error("not enough parameters in macro call");
30418232Slinton 	} else if (*p == ',') {
30518232Slinton 	    error("too many parameters in macro call");
3069679Slinton 	}
30718232Slinton 	++p;
30818232Slinton     }
30918232Slinton     return p;
3109679Slinton }
3119679Slinton 
getactuals(n)31218232Slinton private String *getactuals (n)
31318232Slinton integer n;
3149679Slinton {
31518232Slinton     String *a;
31618232Slinton     register char *p;
31718232Slinton     int i;
3189679Slinton 
31918232Slinton     a = newarr(String, n);
32018232Slinton     p = curchar;
32118232Slinton     while (*p != '(') {
32218232Slinton 	if (lexclass[*p] != WHITE) {
32318232Slinton 	    error("missing actuals for macro");
3249679Slinton 	}
32518232Slinton 	++p;
32618232Slinton     }
32718232Slinton     ++p;
32818232Slinton     for (i = 0; i < n - 1; i++) {
32918232Slinton 	a[i] = p;
33018232Slinton 	p = movetochar(p, ',');
33118232Slinton 	*p = '\0';
33218232Slinton 	++p;
33318232Slinton     }
33418232Slinton     a[n-1] = p;
33518232Slinton     p = movetochar(p, ')');
33618232Slinton     *p = '\0';
33718232Slinton     curchar = p + 1;
33818232Slinton     return a;
3399679Slinton }
3409679Slinton 
3419679Slinton /*
34218232Slinton  * Do command macro expansion, assuming curchar points to the beginning
34318232Slinton  * of the actuals, and we are not in shell mode.
3449679Slinton  */
34518232Slinton 
expand(pl,str)34618232Slinton private expand (pl, str)
34718232Slinton List pl;
34818232Slinton String str;
3499679Slinton {
35018232Slinton     char buf[4096], namebuf[100];
35118232Slinton     register char *p, *q, *r;
35218232Slinton     String *actual;
35318232Slinton     Name n;
35418232Slinton     integer i;
35518232Slinton     boolean match;
3569679Slinton 
35718232Slinton     if (pl == nil) {
35818232Slinton 	insertinput(str);
35918232Slinton     } else {
36018232Slinton 	actual = getactuals(list_size(pl));
36118232Slinton 	p = buf;
36218232Slinton 	q = str;
36318232Slinton 	while (*q != '\0') {
36418232Slinton 	    if (p >= &buf[4096]) {
36518232Slinton 		error("alias expansion too large");
36618232Slinton 	    }
36718232Slinton 	    if (lexclass[*q] == ALPHA) {
36818232Slinton 		r = namebuf;
36918232Slinton 		do {
37018232Slinton 		    *r++ = *q++;
37118232Slinton 		} while (isalnum(*q));
37218232Slinton 		*r = '\0';
37318232Slinton 		i = 0;
37418232Slinton 		match = false;
37518232Slinton 		foreach(Name, n, pl)
37618232Slinton 		    if (streq(ident(n), namebuf)) {
37718232Slinton 			match = true;
37818232Slinton 			break;
37918232Slinton 		    }
38018232Slinton 		    ++i;
38118232Slinton 		endfor
38218232Slinton 		if (match) {
38318232Slinton 		    r = actual[i];
38418232Slinton 		} else {
38518232Slinton 		    r = namebuf;
38616928Ssam 		}
38718232Slinton 		while (*r != '\0') {
38818232Slinton 		    *p++ = *r++;
38918232Slinton 		}
39018232Slinton 	    } else {
39118232Slinton 		*p++ = *q++;
39218232Slinton 	    }
3939679Slinton 	}
39418232Slinton 	*p = '\0';
39518232Slinton 	insertinput(buf);
39618232Slinton     }
3979679Slinton }
3989679Slinton 
3999679Slinton /*
40016928Ssam  * Parser error handling.
4019679Slinton  */
40218232Slinton 
yyerror(s)40316928Ssam public yyerror(s)
4049679Slinton String s;
4059679Slinton {
40618232Slinton     register char *p;
40718232Slinton     register integer start;
4089679Slinton 
40918232Slinton     if (streq(s, "syntax error")) {
41018232Slinton 	beginerrmsg();
41118232Slinton 	p = prevchar;
41218232Slinton 	start = p - &scanner_linebuf[0];
41318232Slinton 	if (p > &scanner_linebuf[0]) {
41418232Slinton 	    while (lexclass[*p] == WHITE and p > &scanner_linebuf[0]) {
41518232Slinton 		--p;
41618232Slinton 	    }
4179679Slinton 	}
41818232Slinton 	fprintf(stderr, "%s", scanner_linebuf);
41918232Slinton 	if (start != 0) {
42018232Slinton 	    fprintf(stderr, "%*c", start, ' ');
42118232Slinton 	}
42218232Slinton 	if (p == &scanner_linebuf[0]) {
42318232Slinton 	    fprintf(stderr, "^ unrecognized command");
42418232Slinton 	} else {
42518232Slinton 	    fprintf(stderr, "^ syntax error");
42618232Slinton 	}
42718232Slinton 	enderrmsg();
42818232Slinton     } else {
42916928Ssam 	error(s);
43018232Slinton     }
4319679Slinton }
4329679Slinton 
4339679Slinton /*
43416928Ssam  * Eat the current line.
43516928Ssam  */
43616928Ssam 
gobble()43718232Slinton public gobble ()
43816928Ssam {
43918232Slinton     curchar = scanner_linebuf;
44018232Slinton     scanner_linebuf[0] = '\0';
44116928Ssam }
44216928Ssam 
44316928Ssam /*
44418232Slinton  * Scan an identifier.
44518232Slinton  *
44618232Slinton  * If chkalias is true, check first to see if it's an alias.
44718232Slinton  * Otherwise, check to see if it's a keyword.
4489679Slinton  */
44918232Slinton 
getident(chkalias)45018232Slinton private Token getident (chkalias)
45118232Slinton boolean chkalias;
4529679Slinton {
45318232Slinton     char buf[1024];
45418232Slinton     register char *p, *q;
45518232Slinton     register Token t;
45618232Slinton     List pl;
45718232Slinton     String str;
4589679Slinton 
45918232Slinton     p = curchar;
46018232Slinton     q = buf;
46118232Slinton     if (shellmode) {
46218232Slinton 	do {
46318232Slinton 	    *q++ = *p++;
46418232Slinton 	} while (index(" \t\n!&<>*[]()'\"", *p) == nil);
46518232Slinton     } else {
46618232Slinton 	do {
46718232Slinton 	    *q++ = *p++;
46818232Slinton 	} while (isalnum(*p));
46918232Slinton     }
47018232Slinton     curchar = p;
47118232Slinton     *q = '\0';
47218232Slinton     yylval.y_name = identname(buf, false);
47318232Slinton     if (chkalias) {
47418232Slinton 	if (findalias(yylval.y_name, &pl, &str)) {
47518232Slinton 	    expand(pl, str);
47618232Slinton 	    while (lexclass[*curchar] == WHITE) {
47718232Slinton 		++curchar;
47818232Slinton 	    }
47918232Slinton 	    if (pl == nil) {
48018232Slinton 		t = getident(false);
48118232Slinton 	    } else {
48218232Slinton 		t = getident(true);
48318232Slinton 	    }
48418232Slinton 	} else if (shellmode) {
48518232Slinton 	    t = NAME;
48618232Slinton 	} else {
48718232Slinton 	    t = findkeyword(yylval.y_name, NAME);
4889679Slinton 	}
48918232Slinton     } else if (shellmode) {
49018232Slinton 	t = NAME;
49118232Slinton     } else {
49218232Slinton 	t = findkeyword(yylval.y_name, NAME);
49318232Slinton     }
49418232Slinton     return t;
4959679Slinton }
4969679Slinton 
49716928Ssam /*
49818232Slinton  * Scan a number.
49916928Ssam  */
50018232Slinton 
getnum()50118232Slinton private Token getnum()
5029679Slinton {
50318232Slinton     char buf[1024];
50418232Slinton     register Char *p, *q;
50518232Slinton     register Token t;
50618232Slinton     Integer base;
5079679Slinton 
50818232Slinton     p = curchar;
50918232Slinton     q = buf;
51018232Slinton     if (*p == '0') {
51118232Slinton 	if (*(p+1) == 'x') {
51218232Slinton 	    p += 2;
51318232Slinton 	    base = 16;
51418232Slinton 	} else if (*(p+1) == 't') {
51518232Slinton 	    base = 10;
51618232Slinton 	} else if (varIsSet("$hexin")) {
51718232Slinton 	    base = 16;
51818232Slinton 	} else {
51918232Slinton 	    base = 8;
52018232Slinton 	}
52118232Slinton     } else if (varIsSet("$hexin")) {
52218232Slinton 	base = 16;
52318232Slinton     } else if (varIsSet("$octin")) {
52418232Slinton 	base = 8;
52518232Slinton     } else {
52618232Slinton 	base = 10;
52718232Slinton     }
52818232Slinton     if (base == 16) {
52918232Slinton 	do {
53018232Slinton 	    *q++ = *p++;
53118232Slinton 	} while (ishexdigit(*p));
53218232Slinton     } else {
53318232Slinton 	do {
53418232Slinton 	    *q++ = *p++;
53518232Slinton 	} while (isdigit(*p));
53618232Slinton     }
53718232Slinton     if (*p == '.') {
53818232Slinton 	do {
53918232Slinton 	    *q++ = *p++;
54018232Slinton 	} while (isdigit(*p));
54118232Slinton 	if (*p == 'e' or *p == 'E') {
54218232Slinton 	    p++;
54318232Slinton 	    if (*p == '+' or *p == '-' or isdigit(*p)) {
54418232Slinton 		*q++ = 'e';
54518232Slinton 		do {
54618232Slinton 		    *q++ = *p++;
54718232Slinton 		} while (isdigit(*p));
54818232Slinton 	    }
54918232Slinton 	}
55018232Slinton 	*q = '\0';
55118232Slinton 	yylval.y_real = atof(buf);
55218232Slinton 	t = REAL;
55318232Slinton     } else {
55418232Slinton 	*q = '\0';
55518232Slinton 	switch (base) {
55618232Slinton 	    case 10:
55718232Slinton 		yylval.y_int = atol(buf);
55818232Slinton 		break;
55918232Slinton 
56018232Slinton 	    case 8:
56118232Slinton 		yylval.y_int = octal(buf);
56218232Slinton 		break;
56318232Slinton 
56418232Slinton 	    case 16:
56518232Slinton 		yylval.y_int = hex(buf);
56618232Slinton 		break;
56718232Slinton 
56818232Slinton 	    default:
56918232Slinton 		badcaseval(base);
57018232Slinton 	}
57118232Slinton 	t = INT;
57218232Slinton     }
57318232Slinton     curchar = p;
57418232Slinton     return t;
5759679Slinton }
5769679Slinton 
5779679Slinton /*
57818232Slinton  * Convert a string of octal digits to an integer.
5799679Slinton  */
5809679Slinton 
octal(s)58118232Slinton private int octal(s)
58218232Slinton String s;
5839679Slinton {
58418232Slinton     register Char *p;
58518232Slinton     register Integer n;
5869679Slinton 
58718232Slinton     n = 0;
58818232Slinton     for (p = s; *p != '\0'; p++) {
58918232Slinton 	n = 8*n + (*p - '0');
59018232Slinton     }
59118232Slinton     return n;
5929679Slinton }
5939679Slinton 
59418232Slinton /*
59518232Slinton  * Convert a string of hexadecimal digits to an integer.
59618232Slinton  */
59716928Ssam 
hex(s)59818232Slinton private int hex(s)
59918232Slinton String s;
60016928Ssam {
60118232Slinton     register Char *p;
60218232Slinton     register Integer n;
60316928Ssam 
60418232Slinton     n = 0;
60518232Slinton     for (p = s; *p != '\0'; p++) {
60618232Slinton 	n *= 16;
60718232Slinton 	if (*p >= 'a' and *p <= 'f') {
60818232Slinton 	    n += (*p - 'a' + 10);
60918232Slinton 	} else if (*p >= 'A' and *p <= 'F') {
61018232Slinton 	    n += (*p - 'A' + 10);
61118232Slinton 	} else {
61218232Slinton 	    n += (*p - '0');
61318232Slinton 	}
61418232Slinton     }
61518232Slinton     return n;
61616928Ssam }
61716928Ssam 
6189679Slinton /*
61918232Slinton  * Scan a string.
6209679Slinton  */
62118232Slinton 
getstring(quote)62218232Slinton private Token getstring (quote)
62318232Slinton char quote;
62416928Ssam {
62518232Slinton     register char *p, *q;
62618232Slinton     char buf[MAXLINESIZE];
62718232Slinton     boolean endofstring;
62818232Slinton     Token t;
6299679Slinton 
63018232Slinton     p = curchar;
63118232Slinton     q = buf;
63218232Slinton     endofstring = false;
63318232Slinton     while (not endofstring) {
63418232Slinton 	if (*p == '\\' and *(p+1) == '\n') {
63518232Slinton 	    if (fgets(scanner_linebuf, MAXLINESIZE, in) == nil) {
63618232Slinton 		error("non-terminated string");
63718232Slinton 	    }
63818232Slinton 	    p = &scanner_linebuf[0] - 1;
63918232Slinton 	} else if (*p == '\n' or *p == '\0') {
64018232Slinton 	    error("non-terminated string");
64118232Slinton 	    endofstring = true;
64218232Slinton 	} else if (*p == quote) {
64318232Slinton 	    endofstring = true;
64418232Slinton 	} else {
64518232Slinton 	    curchar = p;
64618232Slinton 	    *q++ = charcon(p);
64718232Slinton 	    p = curchar;
64816928Ssam 	}
64918232Slinton 	p++;
65018232Slinton     }
65118232Slinton     curchar = p;
65218232Slinton     *q = '\0';
65318232Slinton     if (quote == '\'' and buf[1] == '\0') {
65418232Slinton 	yylval.y_char = buf[0];
65518232Slinton 	t = CHAR;
65618232Slinton     } else {
65718232Slinton 	yylval.y_string = strdup(buf);
65818232Slinton 	t = STRING;
65918232Slinton     }
66018232Slinton     return t;
66116928Ssam }
66216928Ssam 
66318232Slinton /*
66418232Slinton  * Process a character constant.
66518232Slinton  * Watch out for backslashes.
66618232Slinton  */
66718232Slinton 
charcon(s)66818232Slinton private char charcon (s)
66918232Slinton String s;
6709679Slinton {
67118232Slinton     register char *p, *q;
67218232Slinton     char c, buf[10];
67316928Ssam 
67418232Slinton     p = s;
67518232Slinton     if (*p == '\\') {
67618232Slinton 	++p;
67718232Slinton 	switch (*p) {
67818232Slinton 	    case '\\':
67918232Slinton 		c = '\\';
68018232Slinton 		break;
68116928Ssam 
68218232Slinton 	    case 'n':
68318232Slinton 		c = '\n';
68416928Ssam 		break;
68516928Ssam 
68618232Slinton 	    case 'r':
68718232Slinton 		c = '\r';
68816928Ssam 		break;
68916928Ssam 
69018232Slinton 	    case 't':
69118232Slinton 		c = '\t';
69218232Slinton 		break;
6939679Slinton 
69418232Slinton 	    case '\'':
69518232Slinton 	    case '"':
69618232Slinton 		c = *p;
69716928Ssam 		break;
69816928Ssam 
69918232Slinton 	    default:
70018232Slinton 		if (isdigit(*p)) {
70118232Slinton 		    q = buf;
70218232Slinton 		    do {
70318232Slinton 			*q++ = *p++;
70418232Slinton 		    } while (isdigit(*p));
70518232Slinton 		    *q = '\0';
70618232Slinton 		    c = (char) octal(buf);
70718232Slinton 		}
70818232Slinton 		--p;
70916928Ssam 		break;
71016928Ssam 	}
71118232Slinton 	curchar = p;
71218232Slinton     } else {
71318232Slinton 	c = *p;
71418232Slinton     }
71518232Slinton     return c;
71616928Ssam }
71716928Ssam 
7189679Slinton /*
71918232Slinton  * Input file management routines.
7209679Slinton  */
72118232Slinton 
setinput(filename)72218232Slinton public setinput(filename)
72318232Slinton Filename filename;
72416928Ssam {
72518232Slinton     File f;
7269679Slinton 
72718232Slinton     f = fopen(filename, "r");
72818232Slinton     if (f == nil) {
72918232Slinton 	error("can't open %s", filename);
73018232Slinton     } else {
73118232Slinton 	if (curinclindex >= MAXINCLDEPTH) {
73218232Slinton 	    error("unreasonable input nesting on \"%s\"", filename);
73316928Ssam 	}
73418232Slinton 	inclinfo[curinclindex].savefile = in;
73518232Slinton 	inclinfo[curinclindex].savefn = errfilename;
73618232Slinton 	inclinfo[curinclindex].savelineno = errlineno;
73718232Slinton 	curinclindex++;
73818232Slinton 	in = f;
73918232Slinton 	errfilename = filename;
74018232Slinton 	errlineno = 1;
74118232Slinton     }
74216928Ssam }
74316928Ssam 
eofinput()74418232Slinton private Boolean eofinput()
7459679Slinton {
74618232Slinton     register Boolean b;
7479679Slinton 
74818232Slinton     if (curinclindex == 0) {
74918232Slinton 	if (isterm(in)) {
75018232Slinton 	    putchar('\n');
75118232Slinton 	    clearerr(in);
75218232Slinton 	    b = false;
75318232Slinton 	} else {
75418232Slinton 	    b = true;
75518232Slinton 	}
75618232Slinton     } else {
75718232Slinton 	fclose(in);
75818232Slinton 	--curinclindex;
75918232Slinton 	in = inclinfo[curinclindex].savefile;
76018232Slinton 	errfilename = inclinfo[curinclindex].savefn;
76118232Slinton 	errlineno = inclinfo[curinclindex].savelineno;
76218232Slinton 	b = false;
76318232Slinton     }
76418232Slinton     return b;
7659679Slinton }
7669679Slinton 
7679679Slinton /*
76818232Slinton  * Pop the current input.  Return whether successful.
7699679Slinton  */
77018232Slinton 
popinput()77118232Slinton public Boolean popinput()
77216928Ssam {
77318232Slinton     Boolean b;
7749679Slinton 
77518232Slinton     if (curinclindex == 0) {
77618232Slinton 	b = false;
77718232Slinton     } else {
77818232Slinton 	b = (Boolean) (not eofinput());
77918232Slinton     }
78018232Slinton     return b;
7819679Slinton }
7829679Slinton 
7839679Slinton /*
78416928Ssam  * Return whether we are currently reading from standard input.
7859679Slinton  */
78618232Slinton 
isstdin()78716928Ssam public Boolean isstdin()
78816928Ssam {
78918232Slinton     return (Boolean) (in == stdin);
79018232Slinton }
7919679Slinton 
79218232Slinton /*
79318232Slinton  * Send the current line to the shell.
79418232Slinton  */
79518232Slinton 
shellline()79618232Slinton public shellline()
79718232Slinton {
79818232Slinton     register char *p;
79918232Slinton 
80018232Slinton     p = curchar;
80118232Slinton     while (*p != '\0' and (*p == '\n' or lexclass[*p] == WHITE)) {
80218232Slinton 	++p;
80318232Slinton     }
80418232Slinton     shell(p);
80518232Slinton     if (*p == '\0' and isterm(in)) {
80618232Slinton 	putchar('\n');
80718232Slinton     }
80818232Slinton     erecover();
80916928Ssam }
81016928Ssam 
81118232Slinton /*
81218232Slinton  * Read the rest of the current line in "shell mode".
81318232Slinton  */
81418232Slinton 
beginshellmode()81518232Slinton public beginshellmode()
8169679Slinton {
81718232Slinton     shellmode = true;
81818232Slinton }
81916928Ssam 
82018232Slinton /*
82118232Slinton  * Print out a token for debugging.
82218232Slinton  */
82318232Slinton 
print_token(f,t)82418232Slinton public print_token(f, t)
82518232Slinton File f;
82618232Slinton Token t;
82718232Slinton {
82818232Slinton     if (t == '\n') {
82918232Slinton 	fprintf(f, "char '\\n'");
83018232Slinton     } else if (t == EOF) {
83118232Slinton 	fprintf(f, "EOF");
83218232Slinton     } else if (t < 256) {
83318232Slinton 	fprintf(f, "char '%c'", t);
83418232Slinton     } else {
83518232Slinton 	fprintf(f, "\"%s\"", keywdstring(t));
83618232Slinton     }
8379679Slinton }
838