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