xref: /csrg-svn/old/dbx/scanner.c (revision 18232)
19679Slinton /* Copyright (c) 1982 Regents of the University of California */
29679Slinton 
3*18232Slinton static char sccsid[] = "@(#)scanner.c	1.12 (Berkeley) 03/01/85";
49679Slinton 
5*18232Slinton static char rcsid[] = "$Header: scanner.c,v 1.5 84/12/26 10:42:05 linton Exp $";
6*18232Slinton 
79679Slinton /*
89679Slinton  * Debugger scanner.
99679Slinton  */
109679Slinton 
119679Slinton #include "defs.h"
129679Slinton #include "scanner.h"
139679Slinton #include "main.h"
149679Slinton #include "keywords.h"
159679Slinton #include "tree.h"
169679Slinton #include "symbols.h"
179679Slinton #include "names.h"
189679Slinton #include "y.tab.h"
199679Slinton 
209679Slinton #ifndef public
219679Slinton typedef int Token;
229679Slinton 
23*18232Slinton #define MAXLINESIZE 10240
249679Slinton 
25*18232Slinton #endif
269679Slinton 
2716928Ssam public String initfile = ".dbxinit";
289679Slinton 
29*18232Slinton typedef enum { WHITE, ALPHA, NUM, OTHER } Charclass;
30*18232Slinton 
31*18232Slinton private Charclass class[256 + 1];
32*18232Slinton private Charclass *lexclass = class + 1;
33*18232Slinton 
34*18232Slinton #define isdigit(c) (lexclass[c] == NUM)
35*18232Slinton #define isalnum(c) (lexclass[c] == ALPHA or lexclass[c] == NUM)
36*18232Slinton #define ishexdigit(c) ( \
37*18232Slinton     isdigit(c) or (c >= 'a' and c <= 'f') or (c >= 'A' and c <= 'F') \
38*18232Slinton )
39*18232Slinton 
40*18232Slinton public boolean chkalias;
41*18232Slinton public char scanner_linebuf[MAXLINESIZE];
42*18232Slinton 
43*18232Slinton private File in;
44*18232Slinton private char *curchar, *prevchar;
45*18232Slinton 
46*18232Slinton #define MAXINCLDEPTH 10
47*18232Slinton 
48*18232Slinton private struct {
49*18232Slinton     File savefile;
50*18232Slinton     Filename savefn;
51*18232Slinton     int savelineno;
52*18232Slinton } inclinfo[MAXINCLDEPTH];
53*18232Slinton 
54*18232Slinton private unsigned int curinclindex;
55*18232Slinton 
569679Slinton private Token getident();
579679Slinton private Token getnum();
589679Slinton private Token getstring();
59*18232Slinton private Boolean eofinput();
60*18232Slinton private char charcon();
619679Slinton 
62*18232Slinton private enterlexclass(class, s)
63*18232Slinton Charclass class;
64*18232Slinton String s;
65*18232Slinton {
66*18232Slinton     register char *p;
679679Slinton 
68*18232Slinton     for (p = s; *p != '\0'; p++) {
69*18232Slinton 	lexclass[*p] = class;
70*18232Slinton     }
71*18232Slinton }
72*18232Slinton 
739679Slinton public scanner_init()
749679Slinton {
75*18232Slinton     register Integer i;
769679Slinton 
77*18232Slinton     for (i = 0; i < 257; i++) {
78*18232Slinton 	class[i] = OTHER;
79*18232Slinton     }
80*18232Slinton     enterlexclass(WHITE, " \t");
81*18232Slinton     enterlexclass(ALPHA, "abcdefghijklmnopqrstuvwxyz");
82*18232Slinton     enterlexclass(ALPHA, "ABCDEFGHIJKLMNOPQRSTUVWXYZ_$");
83*18232Slinton     enterlexclass(NUM, "0123456789");
84*18232Slinton     in = stdin;
85*18232Slinton     errfilename = nil;
86*18232Slinton     errlineno = 0;
87*18232Slinton     curchar = scanner_linebuf;
88*18232Slinton     scanner_linebuf[0] = '\0';
89*18232Slinton     chkalias = true;
909679Slinton }
919679Slinton 
929679Slinton /*
939679Slinton  * Read a single token.
94*18232Slinton  *
95*18232Slinton  * The input is line buffered.  Tokens cannot cross line boundaries.
96*18232Slinton  *
979679Slinton  * There are two "modes" of operation:  one as in a compiler,
98*18232Slinton  * and one for reading shell-like syntax.  In the first mode
99*18232Slinton  * there is the additional choice of doing alias processing.
1009679Slinton  */
101*18232Slinton 
102*18232Slinton private Boolean shellmode;
103*18232Slinton 
1049679Slinton public Token yylex()
1059679Slinton {
106*18232Slinton     register int c;
107*18232Slinton     register char *p;
108*18232Slinton     register Token t;
109*18232Slinton     String line;
110*18232Slinton     integer n;
1119679Slinton 
112*18232Slinton     p = curchar;
113*18232Slinton     if (*p == '\0') {
114*18232Slinton 	do {
115*18232Slinton 	    if (isterm(in)) {
116*18232Slinton 		printf("(%s) ", cmdname);
117*18232Slinton 	    }
118*18232Slinton 	    fflush(stdout);
119*18232Slinton 	    line = fgets(scanner_linebuf, MAXLINESIZE, in);
120*18232Slinton 	} while (line == nil and not eofinput());
121*18232Slinton 	if (line == nil) {
122*18232Slinton 	    c = EOF;
123*18232Slinton 	} else {
124*18232Slinton 	    p = scanner_linebuf;
125*18232Slinton 	    while (lexclass[*p] == WHITE) {
126*18232Slinton 		p++;
127*18232Slinton 	    }
128*18232Slinton 	    shellmode = false;
1299679Slinton 	}
130*18232Slinton 	chkalias = true;
131*18232Slinton     } else {
132*18232Slinton 	while (lexclass[*p] == WHITE) {
133*18232Slinton 	    p++;
1349679Slinton 	}
135*18232Slinton     }
136*18232Slinton     curchar = p;
137*18232Slinton     prevchar = curchar;
138*18232Slinton     c = *p;
139*18232Slinton     if (lexclass[c] == ALPHA) {
140*18232Slinton 	t = getident(chkalias);
141*18232Slinton     } else if (lexclass[c] == NUM) {
142*18232Slinton 	if (shellmode) {
143*18232Slinton 	    t = getident(chkalias);
144*18232Slinton 	} else {
145*18232Slinton 	    t = getnum();
14612120Slinton 	}
147*18232Slinton     } else {
148*18232Slinton 	++curchar;
1499679Slinton 	switch (c) {
150*18232Slinton 	    case '\n':
1519679Slinton 		t = '\n';
152*18232Slinton 		if (errlineno != 0) {
153*18232Slinton 		    errlineno++;
1549679Slinton 		}
1559679Slinton 		break;
1569679Slinton 
157*18232Slinton 	    case '"':
158*18232Slinton 	    case '\'':
15916928Ssam 		t = getstring(c);
1609679Slinton 		break;
1619679Slinton 
162*18232Slinton 	    case '.':
1639679Slinton 		if (shellmode) {
164*18232Slinton 		    --curchar;
165*18232Slinton 		    t = getident(chkalias);
166*18232Slinton 		} else if (isdigit(*curchar)) {
167*18232Slinton 		    --curchar;
168*18232Slinton 		    t = getnum();
169*18232Slinton 		} else {
170*18232Slinton 		    t = '.';
1719679Slinton 		}
1729679Slinton 		break;
1739679Slinton 
174*18232Slinton 	    case '-':
175*18232Slinton 		if (shellmode) {
176*18232Slinton 		    --curchar;
177*18232Slinton 		    t = getident(chkalias);
178*18232Slinton 		} else if (*curchar == '>') {
179*18232Slinton 		    ++curchar;
180*18232Slinton 		    t = ARROW;
181*18232Slinton 		} else {
182*18232Slinton 		    t = '-';
183*18232Slinton 		}
1849679Slinton 		break;
1859679Slinton 
186*18232Slinton 	    case '#':
187*18232Slinton 		if (not isterm(in)) {
188*18232Slinton 		    *p = '\0';
189*18232Slinton 		    curchar = p;
190*18232Slinton 		    t = '\n';
191*18232Slinton 		    ++errlineno;
192*18232Slinton 		} else {
193*18232Slinton 		    t = '#';
194*18232Slinton 		}
1959679Slinton 		break;
1969679Slinton 
197*18232Slinton 	    case '\\':
198*18232Slinton 		if (*(p+1) == '\n') {
199*18232Slinton 		    n = MAXLINESIZE - (p - &scanner_linebuf[0]);
200*18232Slinton 		    if (n > 1) {
201*18232Slinton 			if (fgets(p, n, in) == nil) {
202*18232Slinton 			    t = 0;
203*18232Slinton 			} else {
204*18232Slinton 			    curchar = p;
205*18232Slinton 			    t = yylex();
206*18232Slinton 			}
207*18232Slinton 		    } else {
208*18232Slinton 			t = '\\';
209*18232Slinton 		    }
210*18232Slinton 		} else {
211*18232Slinton 		    t = '\\';
2129679Slinton 		}
2139679Slinton 		break;
2149679Slinton 
215*18232Slinton 	    case EOF:
2169679Slinton 		t = 0;
2179679Slinton 		break;
2189679Slinton 
219*18232Slinton 	    default:
220*18232Slinton 		if (shellmode and index("!&*<>()[]", c) == nil) {
221*18232Slinton 		    --curchar;
222*18232Slinton 		    t = getident(chkalias);
223*18232Slinton 		} else {
224*18232Slinton 		    t = c;
225*18232Slinton 		}
2269679Slinton 		break;
2279679Slinton 	}
228*18232Slinton     }
229*18232Slinton     chkalias = false;
230*18232Slinton #   ifdef LEXDEBUG
2319679Slinton 	if (lexdebug) {
232*18232Slinton 	    fprintf(stderr, "yylex returns ");
233*18232Slinton 	    print_token(stderr, t);
234*18232Slinton 	    fprintf(stderr, "\n");
2359679Slinton 	}
236*18232Slinton #   endif
237*18232Slinton     return t;
2389679Slinton }
2399679Slinton 
2409679Slinton /*
241*18232Slinton  * Put the given string before the current character
242*18232Slinton  * in the current line, thus inserting it into the input stream.
2439679Slinton  */
2449679Slinton 
245*18232Slinton public insertinput (s)
246*18232Slinton String s;
2479679Slinton {
248*18232Slinton     register char *p, *q;
249*18232Slinton     int need, avail, shift;
2509679Slinton 
251*18232Slinton     q = s;
252*18232Slinton     need = strlen(q);
253*18232Slinton     avail = curchar - &scanner_linebuf[0];
254*18232Slinton     if (need <= avail) {
255*18232Slinton 	curchar = &scanner_linebuf[avail - need];
256*18232Slinton 	p = curchar;
257*18232Slinton 	while (*q != '\0') {
258*18232Slinton 	    *p++ = *q++;
25916928Ssam 	}
260*18232Slinton     } else {
261*18232Slinton 	p = curchar;
262*18232Slinton 	while (*p != '\0') {
263*18232Slinton 	    ++p;
2649679Slinton 	}
265*18232Slinton 	shift = need - avail;
266*18232Slinton 	if (p + shift >= &scanner_linebuf[MAXLINESIZE]) {
267*18232Slinton 	    error("alias expansion too large");
2689679Slinton 	}
269*18232Slinton 	for (;;) {
270*18232Slinton 	    *(p + shift) = *p;
271*18232Slinton 	    if (p == curchar) {
2729679Slinton 		break;
273*18232Slinton 	    }
274*18232Slinton 	    --p;
2759679Slinton 	}
276*18232Slinton 	p = &scanner_linebuf[0];
277*18232Slinton 	while (*q != '\0') {
278*18232Slinton 	    *p++ = *q++;
279*18232Slinton 	}
280*18232Slinton 	curchar = &scanner_linebuf[0];
281*18232Slinton     }
2829679Slinton }
2839679Slinton 
2849679Slinton /*
285*18232Slinton  * Get the actuals for a macro call.
2869679Slinton  */
2879679Slinton 
288*18232Slinton private String movetochar (str, c)
289*18232Slinton String str;
290*18232Slinton char c;
2919679Slinton {
292*18232Slinton     register char *p;
2939679Slinton 
294*18232Slinton     while (*p != c) {
295*18232Slinton 	if (*p == '\0') {
296*18232Slinton 	    error("missing ')' in macro call");
297*18232Slinton 	} else if (*p == ')') {
298*18232Slinton 	    error("not enough parameters in macro call");
299*18232Slinton 	} else if (*p == ',') {
300*18232Slinton 	    error("too many parameters in macro call");
3019679Slinton 	}
302*18232Slinton 	++p;
303*18232Slinton     }
304*18232Slinton     return p;
3059679Slinton }
3069679Slinton 
307*18232Slinton private String *getactuals (n)
308*18232Slinton integer n;
3099679Slinton {
310*18232Slinton     String *a;
311*18232Slinton     register char *p;
312*18232Slinton     int i;
3139679Slinton 
314*18232Slinton     a = newarr(String, n);
315*18232Slinton     p = curchar;
316*18232Slinton     while (*p != '(') {
317*18232Slinton 	if (lexclass[*p] != WHITE) {
318*18232Slinton 	    error("missing actuals for macro");
3199679Slinton 	}
320*18232Slinton 	++p;
321*18232Slinton     }
322*18232Slinton     ++p;
323*18232Slinton     for (i = 0; i < n - 1; i++) {
324*18232Slinton 	a[i] = p;
325*18232Slinton 	p = movetochar(p, ',');
326*18232Slinton 	*p = '\0';
327*18232Slinton 	++p;
328*18232Slinton     }
329*18232Slinton     a[n-1] = p;
330*18232Slinton     p = movetochar(p, ')');
331*18232Slinton     *p = '\0';
332*18232Slinton     curchar = p + 1;
333*18232Slinton     return a;
3349679Slinton }
3359679Slinton 
3369679Slinton /*
337*18232Slinton  * Do command macro expansion, assuming curchar points to the beginning
338*18232Slinton  * of the actuals, and we are not in shell mode.
3399679Slinton  */
340*18232Slinton 
341*18232Slinton private expand (pl, str)
342*18232Slinton List pl;
343*18232Slinton String str;
3449679Slinton {
345*18232Slinton     char buf[4096], namebuf[100];
346*18232Slinton     register char *p, *q, *r;
347*18232Slinton     String *actual;
348*18232Slinton     Name n;
349*18232Slinton     integer i;
350*18232Slinton     boolean match;
3519679Slinton 
352*18232Slinton     if (pl == nil) {
353*18232Slinton 	insertinput(str);
354*18232Slinton     } else {
355*18232Slinton 	actual = getactuals(list_size(pl));
356*18232Slinton 	p = buf;
357*18232Slinton 	q = str;
358*18232Slinton 	while (*q != '\0') {
359*18232Slinton 	    if (p >= &buf[4096]) {
360*18232Slinton 		error("alias expansion too large");
361*18232Slinton 	    }
362*18232Slinton 	    if (lexclass[*q] == ALPHA) {
363*18232Slinton 		r = namebuf;
364*18232Slinton 		do {
365*18232Slinton 		    *r++ = *q++;
366*18232Slinton 		} while (isalnum(*q));
367*18232Slinton 		*r = '\0';
368*18232Slinton 		i = 0;
369*18232Slinton 		match = false;
370*18232Slinton 		foreach(Name, n, pl)
371*18232Slinton 		    if (streq(ident(n), namebuf)) {
372*18232Slinton 			match = true;
373*18232Slinton 			break;
374*18232Slinton 		    }
375*18232Slinton 		    ++i;
376*18232Slinton 		endfor
377*18232Slinton 		if (match) {
378*18232Slinton 		    r = actual[i];
379*18232Slinton 		} else {
380*18232Slinton 		    r = namebuf;
38116928Ssam 		}
382*18232Slinton 		while (*r != '\0') {
383*18232Slinton 		    *p++ = *r++;
384*18232Slinton 		}
385*18232Slinton 	    } else {
386*18232Slinton 		*p++ = *q++;
387*18232Slinton 	    }
3889679Slinton 	}
389*18232Slinton 	*p = '\0';
390*18232Slinton 	insertinput(buf);
391*18232Slinton     }
3929679Slinton }
3939679Slinton 
3949679Slinton /*
39516928Ssam  * Parser error handling.
3969679Slinton  */
397*18232Slinton 
39816928Ssam public yyerror(s)
3999679Slinton String s;
4009679Slinton {
401*18232Slinton     register char *p;
402*18232Slinton     register integer start;
4039679Slinton 
404*18232Slinton     if (streq(s, "syntax error")) {
405*18232Slinton 	beginerrmsg();
406*18232Slinton 	p = prevchar;
407*18232Slinton 	start = p - &scanner_linebuf[0];
408*18232Slinton 	if (p > &scanner_linebuf[0]) {
409*18232Slinton 	    while (lexclass[*p] == WHITE and p > &scanner_linebuf[0]) {
410*18232Slinton 		--p;
411*18232Slinton 	    }
4129679Slinton 	}
413*18232Slinton 	fprintf(stderr, "%s", scanner_linebuf);
414*18232Slinton 	if (start != 0) {
415*18232Slinton 	    fprintf(stderr, "%*c", start, ' ');
416*18232Slinton 	}
417*18232Slinton 	if (p == &scanner_linebuf[0]) {
418*18232Slinton 	    fprintf(stderr, "^ unrecognized command");
419*18232Slinton 	} else {
420*18232Slinton 	    fprintf(stderr, "^ syntax error");
421*18232Slinton 	}
422*18232Slinton 	enderrmsg();
423*18232Slinton     } else {
42416928Ssam 	error(s);
425*18232Slinton     }
4269679Slinton }
4279679Slinton 
4289679Slinton /*
42916928Ssam  * Eat the current line.
43016928Ssam  */
43116928Ssam 
432*18232Slinton public gobble ()
43316928Ssam {
434*18232Slinton     curchar = scanner_linebuf;
435*18232Slinton     scanner_linebuf[0] = '\0';
43616928Ssam }
43716928Ssam 
43816928Ssam /*
439*18232Slinton  * Scan an identifier.
440*18232Slinton  *
441*18232Slinton  * If chkalias is true, check first to see if it's an alias.
442*18232Slinton  * Otherwise, check to see if it's a keyword.
4439679Slinton  */
444*18232Slinton 
445*18232Slinton private Token getident (chkalias)
446*18232Slinton boolean chkalias;
4479679Slinton {
448*18232Slinton     char buf[1024];
449*18232Slinton     register char *p, *q;
450*18232Slinton     register Token t;
451*18232Slinton     List pl;
452*18232Slinton     String str;
4539679Slinton 
454*18232Slinton     p = curchar;
455*18232Slinton     q = buf;
456*18232Slinton     if (shellmode) {
457*18232Slinton 	do {
458*18232Slinton 	    *q++ = *p++;
459*18232Slinton 	} while (index(" \t\n!&<>*[]()'\"", *p) == nil);
460*18232Slinton     } else {
461*18232Slinton 	do {
462*18232Slinton 	    *q++ = *p++;
463*18232Slinton 	} while (isalnum(*p));
464*18232Slinton     }
465*18232Slinton     curchar = p;
466*18232Slinton     *q = '\0';
467*18232Slinton     yylval.y_name = identname(buf, false);
468*18232Slinton     if (chkalias) {
469*18232Slinton 	if (findalias(yylval.y_name, &pl, &str)) {
470*18232Slinton 	    expand(pl, str);
471*18232Slinton 	    while (lexclass[*curchar] == WHITE) {
472*18232Slinton 		++curchar;
473*18232Slinton 	    }
474*18232Slinton 	    if (pl == nil) {
475*18232Slinton 		t = getident(false);
476*18232Slinton 	    } else {
477*18232Slinton 		t = getident(true);
478*18232Slinton 	    }
479*18232Slinton 	} else if (shellmode) {
480*18232Slinton 	    t = NAME;
481*18232Slinton 	} else {
482*18232Slinton 	    t = findkeyword(yylval.y_name, NAME);
4839679Slinton 	}
484*18232Slinton     } else if (shellmode) {
485*18232Slinton 	t = NAME;
486*18232Slinton     } else {
487*18232Slinton 	t = findkeyword(yylval.y_name, NAME);
488*18232Slinton     }
489*18232Slinton     return t;
4909679Slinton }
4919679Slinton 
49216928Ssam /*
493*18232Slinton  * Scan a number.
49416928Ssam  */
495*18232Slinton 
496*18232Slinton private Token getnum()
4979679Slinton {
498*18232Slinton     char buf[1024];
499*18232Slinton     register Char *p, *q;
500*18232Slinton     register Token t;
501*18232Slinton     Integer base;
5029679Slinton 
503*18232Slinton     p = curchar;
504*18232Slinton     q = buf;
505*18232Slinton     if (*p == '0') {
506*18232Slinton 	if (*(p+1) == 'x') {
507*18232Slinton 	    p += 2;
508*18232Slinton 	    base = 16;
509*18232Slinton 	} else if (*(p+1) == 't') {
510*18232Slinton 	    base = 10;
511*18232Slinton 	} else if (varIsSet("$hexin")) {
512*18232Slinton 	    base = 16;
513*18232Slinton 	} else {
514*18232Slinton 	    base = 8;
515*18232Slinton 	}
516*18232Slinton     } else if (varIsSet("$hexin")) {
517*18232Slinton 	base = 16;
518*18232Slinton     } else if (varIsSet("$octin")) {
519*18232Slinton 	base = 8;
520*18232Slinton     } else {
521*18232Slinton 	base = 10;
522*18232Slinton     }
523*18232Slinton     if (base == 16) {
524*18232Slinton 	do {
525*18232Slinton 	    *q++ = *p++;
526*18232Slinton 	} while (ishexdigit(*p));
527*18232Slinton     } else {
528*18232Slinton 	do {
529*18232Slinton 	    *q++ = *p++;
530*18232Slinton 	} while (isdigit(*p));
531*18232Slinton     }
532*18232Slinton     if (*p == '.') {
533*18232Slinton 	do {
534*18232Slinton 	    *q++ = *p++;
535*18232Slinton 	} while (isdigit(*p));
536*18232Slinton 	if (*p == 'e' or *p == 'E') {
537*18232Slinton 	    p++;
538*18232Slinton 	    if (*p == '+' or *p == '-' or isdigit(*p)) {
539*18232Slinton 		*q++ = 'e';
540*18232Slinton 		do {
541*18232Slinton 		    *q++ = *p++;
542*18232Slinton 		} while (isdigit(*p));
543*18232Slinton 	    }
544*18232Slinton 	}
545*18232Slinton 	*q = '\0';
546*18232Slinton 	yylval.y_real = atof(buf);
547*18232Slinton 	t = REAL;
548*18232Slinton     } else {
549*18232Slinton 	*q = '\0';
550*18232Slinton 	switch (base) {
551*18232Slinton 	    case 10:
552*18232Slinton 		yylval.y_int = atol(buf);
553*18232Slinton 		break;
554*18232Slinton 
555*18232Slinton 	    case 8:
556*18232Slinton 		yylval.y_int = octal(buf);
557*18232Slinton 		break;
558*18232Slinton 
559*18232Slinton 	    case 16:
560*18232Slinton 		yylval.y_int = hex(buf);
561*18232Slinton 		break;
562*18232Slinton 
563*18232Slinton 	    default:
564*18232Slinton 		badcaseval(base);
565*18232Slinton 	}
566*18232Slinton 	t = INT;
567*18232Slinton     }
568*18232Slinton     curchar = p;
569*18232Slinton     return t;
5709679Slinton }
5719679Slinton 
5729679Slinton /*
573*18232Slinton  * Convert a string of octal digits to an integer.
5749679Slinton  */
5759679Slinton 
576*18232Slinton private int octal(s)
577*18232Slinton String s;
5789679Slinton {
579*18232Slinton     register Char *p;
580*18232Slinton     register Integer n;
5819679Slinton 
582*18232Slinton     n = 0;
583*18232Slinton     for (p = s; *p != '\0'; p++) {
584*18232Slinton 	n = 8*n + (*p - '0');
585*18232Slinton     }
586*18232Slinton     return n;
5879679Slinton }
5889679Slinton 
589*18232Slinton /*
590*18232Slinton  * Convert a string of hexadecimal digits to an integer.
591*18232Slinton  */
59216928Ssam 
593*18232Slinton private int hex(s)
594*18232Slinton String s;
59516928Ssam {
596*18232Slinton     register Char *p;
597*18232Slinton     register Integer n;
59816928Ssam 
599*18232Slinton     n = 0;
600*18232Slinton     for (p = s; *p != '\0'; p++) {
601*18232Slinton 	n *= 16;
602*18232Slinton 	if (*p >= 'a' and *p <= 'f') {
603*18232Slinton 	    n += (*p - 'a' + 10);
604*18232Slinton 	} else if (*p >= 'A' and *p <= 'F') {
605*18232Slinton 	    n += (*p - 'A' + 10);
606*18232Slinton 	} else {
607*18232Slinton 	    n += (*p - '0');
608*18232Slinton 	}
609*18232Slinton     }
610*18232Slinton     return n;
61116928Ssam }
61216928Ssam 
6139679Slinton /*
614*18232Slinton  * Scan a string.
6159679Slinton  */
616*18232Slinton 
617*18232Slinton private Token getstring (quote)
618*18232Slinton char quote;
61916928Ssam {
620*18232Slinton     register char *p, *q;
621*18232Slinton     char buf[MAXLINESIZE];
622*18232Slinton     boolean endofstring;
623*18232Slinton     Token t;
6249679Slinton 
625*18232Slinton     p = curchar;
626*18232Slinton     q = buf;
627*18232Slinton     endofstring = false;
628*18232Slinton     while (not endofstring) {
629*18232Slinton 	if (*p == '\\' and *(p+1) == '\n') {
630*18232Slinton 	    if (fgets(scanner_linebuf, MAXLINESIZE, in) == nil) {
631*18232Slinton 		error("non-terminated string");
632*18232Slinton 	    }
633*18232Slinton 	    p = &scanner_linebuf[0] - 1;
634*18232Slinton 	} else if (*p == '\n' or *p == '\0') {
635*18232Slinton 	    error("non-terminated string");
636*18232Slinton 	    endofstring = true;
637*18232Slinton 	} else if (*p == quote) {
638*18232Slinton 	    endofstring = true;
639*18232Slinton 	} else {
640*18232Slinton 	    curchar = p;
641*18232Slinton 	    *q++ = charcon(p);
642*18232Slinton 	    p = curchar;
64316928Ssam 	}
644*18232Slinton 	p++;
645*18232Slinton     }
646*18232Slinton     curchar = p;
647*18232Slinton     *q = '\0';
648*18232Slinton     if (quote == '\'' and buf[1] == '\0') {
649*18232Slinton 	yylval.y_char = buf[0];
650*18232Slinton 	t = CHAR;
651*18232Slinton     } else {
652*18232Slinton 	yylval.y_string = strdup(buf);
653*18232Slinton 	t = STRING;
654*18232Slinton     }
655*18232Slinton     return t;
65616928Ssam }
65716928Ssam 
658*18232Slinton /*
659*18232Slinton  * Process a character constant.
660*18232Slinton  * Watch out for backslashes.
661*18232Slinton  */
662*18232Slinton 
663*18232Slinton private char charcon (s)
664*18232Slinton String s;
6659679Slinton {
666*18232Slinton     register char *p, *q;
667*18232Slinton     char c, buf[10];
66816928Ssam 
669*18232Slinton     p = s;
670*18232Slinton     if (*p == '\\') {
671*18232Slinton 	++p;
672*18232Slinton 	switch (*p) {
673*18232Slinton 	    case '\\':
674*18232Slinton 		c = '\\';
675*18232Slinton 		break;
67616928Ssam 
677*18232Slinton 	    case 'n':
678*18232Slinton 		c = '\n';
67916928Ssam 		break;
68016928Ssam 
681*18232Slinton 	    case 'r':
682*18232Slinton 		c = '\r';
68316928Ssam 		break;
68416928Ssam 
685*18232Slinton 	    case 't':
686*18232Slinton 		c = '\t';
687*18232Slinton 		break;
6889679Slinton 
689*18232Slinton 	    case '\'':
690*18232Slinton 	    case '"':
691*18232Slinton 		c = *p;
69216928Ssam 		break;
69316928Ssam 
694*18232Slinton 	    default:
695*18232Slinton 		if (isdigit(*p)) {
696*18232Slinton 		    q = buf;
697*18232Slinton 		    do {
698*18232Slinton 			*q++ = *p++;
699*18232Slinton 		    } while (isdigit(*p));
700*18232Slinton 		    *q = '\0';
701*18232Slinton 		    c = (char) octal(buf);
702*18232Slinton 		}
703*18232Slinton 		--p;
70416928Ssam 		break;
70516928Ssam 	}
706*18232Slinton 	curchar = p;
707*18232Slinton     } else {
708*18232Slinton 	c = *p;
709*18232Slinton     }
710*18232Slinton     return c;
71116928Ssam }
71216928Ssam 
7139679Slinton /*
714*18232Slinton  * Input file management routines.
7159679Slinton  */
716*18232Slinton 
717*18232Slinton public setinput(filename)
718*18232Slinton Filename filename;
71916928Ssam {
720*18232Slinton     File f;
7219679Slinton 
722*18232Slinton     f = fopen(filename, "r");
723*18232Slinton     if (f == nil) {
724*18232Slinton 	error("can't open %s", filename);
725*18232Slinton     } else {
726*18232Slinton 	if (curinclindex >= MAXINCLDEPTH) {
727*18232Slinton 	    error("unreasonable input nesting on \"%s\"", filename);
72816928Ssam 	}
729*18232Slinton 	inclinfo[curinclindex].savefile = in;
730*18232Slinton 	inclinfo[curinclindex].savefn = errfilename;
731*18232Slinton 	inclinfo[curinclindex].savelineno = errlineno;
732*18232Slinton 	curinclindex++;
733*18232Slinton 	in = f;
734*18232Slinton 	errfilename = filename;
735*18232Slinton 	errlineno = 1;
736*18232Slinton     }
73716928Ssam }
73816928Ssam 
739*18232Slinton private Boolean eofinput()
7409679Slinton {
741*18232Slinton     register Boolean b;
7429679Slinton 
743*18232Slinton     if (curinclindex == 0) {
744*18232Slinton 	if (isterm(in)) {
745*18232Slinton 	    putchar('\n');
746*18232Slinton 	    clearerr(in);
747*18232Slinton 	    b = false;
748*18232Slinton 	} else {
749*18232Slinton 	    b = true;
750*18232Slinton 	}
751*18232Slinton     } else {
752*18232Slinton 	fclose(in);
753*18232Slinton 	--curinclindex;
754*18232Slinton 	in = inclinfo[curinclindex].savefile;
755*18232Slinton 	errfilename = inclinfo[curinclindex].savefn;
756*18232Slinton 	errlineno = inclinfo[curinclindex].savelineno;
757*18232Slinton 	b = false;
758*18232Slinton     }
759*18232Slinton     return b;
7609679Slinton }
7619679Slinton 
7629679Slinton /*
763*18232Slinton  * Pop the current input.  Return whether successful.
7649679Slinton  */
765*18232Slinton 
766*18232Slinton public Boolean popinput()
76716928Ssam {
768*18232Slinton     Boolean b;
7699679Slinton 
770*18232Slinton     if (curinclindex == 0) {
771*18232Slinton 	b = false;
772*18232Slinton     } else {
773*18232Slinton 	b = (Boolean) (not eofinput());
774*18232Slinton     }
775*18232Slinton     return b;
7769679Slinton }
7779679Slinton 
7789679Slinton /*
77916928Ssam  * Return whether we are currently reading from standard input.
7809679Slinton  */
781*18232Slinton 
78216928Ssam public Boolean isstdin()
78316928Ssam {
784*18232Slinton     return (Boolean) (in == stdin);
785*18232Slinton }
7869679Slinton 
787*18232Slinton /*
788*18232Slinton  * Send the current line to the shell.
789*18232Slinton  */
790*18232Slinton 
791*18232Slinton public shellline()
792*18232Slinton {
793*18232Slinton     register char *p;
794*18232Slinton 
795*18232Slinton     p = curchar;
796*18232Slinton     while (*p != '\0' and (*p == '\n' or lexclass[*p] == WHITE)) {
797*18232Slinton 	++p;
798*18232Slinton     }
799*18232Slinton     shell(p);
800*18232Slinton     if (*p == '\0' and isterm(in)) {
801*18232Slinton 	putchar('\n');
802*18232Slinton     }
803*18232Slinton     erecover();
80416928Ssam }
80516928Ssam 
806*18232Slinton /*
807*18232Slinton  * Read the rest of the current line in "shell mode".
808*18232Slinton  */
809*18232Slinton 
810*18232Slinton public beginshellmode()
8119679Slinton {
812*18232Slinton     shellmode = true;
813*18232Slinton }
81416928Ssam 
815*18232Slinton /*
816*18232Slinton  * Print out a token for debugging.
817*18232Slinton  */
818*18232Slinton 
819*18232Slinton public print_token(f, t)
820*18232Slinton File f;
821*18232Slinton Token t;
822*18232Slinton {
823*18232Slinton     if (t == '\n') {
824*18232Slinton 	fprintf(f, "char '\\n'");
825*18232Slinton     } else if (t == EOF) {
826*18232Slinton 	fprintf(f, "EOF");
827*18232Slinton     } else if (t < 256) {
828*18232Slinton 	fprintf(f, "char '%c'", t);
829*18232Slinton     } else {
830*18232Slinton 	fprintf(f, "\"%s\"", keywdstring(t));
831*18232Slinton     }
8329679Slinton }
833