xref: /csrg-svn/old/dbx/scanner.c (revision 16928)
19679Slinton /* Copyright (c) 1982 Regents of the University of California */
29679Slinton 
3*16928Ssam static char sccsid[] = "@(#)scanner.c	1.10 (Berkeley) 08/12/84";
49679Slinton 
59679Slinton /*
69679Slinton  * Debugger scanner.
79679Slinton  */
89679Slinton 
9*16928Ssam #include <ctype.h>
109679Slinton #include "defs.h"
119679Slinton #include "scanner.h"
129679Slinton #include "main.h"
139679Slinton #include "keywords.h"
149679Slinton #include "tree.h"
159679Slinton #include "symbols.h"
169679Slinton #include "names.h"
179679Slinton #include "y.tab.h"
189679Slinton 
199679Slinton #ifndef public
209679Slinton typedef int Token;
219679Slinton #endif
229679Slinton 
23*16928Ssam typedef struct {
24*16928Ssam 	int	s_type;
25*16928Ssam #define	ST_FILE		0
26*16928Ssam #define	ST_ALIAS	1
27*16928Ssam 	char	*s_name;
28*16928Ssam 	int	s_lineno;
29*16928Ssam 	union {
30*16928Ssam 		File	su_file;
31*16928Ssam 		struct sum {
32*16928Ssam 			char	*sum_data;
33*16928Ssam 			char	*sum_cur;
34*16928Ssam 		} su_macro;
35*16928Ssam 	} su;
36*16928Ssam #define	s_file	su.su_file
37*16928Ssam #define	s_macro	su.su_macro
38*16928Ssam #define	s_data	s_macro.sum_data
39*16928Ssam #define	s_cur	s_macro.sum_cur
40*16928Ssam } STREAM;
419679Slinton 
42*16928Ssam #define	NSTREAMS	10
43*16928Ssam private	STREAM stack[NSTREAMS];
44*16928Ssam private	STREAM *sp = &stack[-1];
459679Slinton 
46*16928Ssam public String initfile = ".dbxinit";
479679Slinton 
489679Slinton private Token getident();
499679Slinton private Token getnum();
509679Slinton private Token getstring();
519679Slinton private Char charcon();
529679Slinton 
53*16928Ssam #define MAXLINESIZE 1024
54*16928Ssam private Char yytext[MAXLINESIZE];
55*16928Ssam private Boolean shellmode;
56*16928Ssam private	Boolean doaliases;
579679Slinton 
589679Slinton public scanner_init()
599679Slinton {
60*16928Ssam 	register Integer i;
619679Slinton 
62*16928Ssam 	if (sp < stack)
63*16928Ssam 		(void) pushinput(ST_FILE, nil, stdin);
64*16928Ssam 	shellmode = false;
65*16928Ssam 	doaliases = true;
66*16928Ssam 	errfilename = nil;
67*16928Ssam 	errlineno = sp->s_lineno = 0;
68*16928Ssam 	yytext[0] = '\0';
699679Slinton }
709679Slinton 
71*16928Ssam #define	MAXDEPTH	25
729679Slinton /*
739679Slinton  * Read a single token.
749679Slinton  * There are two "modes" of operation:  one as in a compiler,
759679Slinton  * and one for reading shell-like syntax.
769679Slinton  */
779679Slinton public Token yylex()
789679Slinton {
79*16928Ssam 	register int c;
80*16928Ssam 	register char *p;
81*16928Ssam 	register Token t;
82*16928Ssam 	static int depth = 0;
839679Slinton 
84*16928Ssam 	depth++;
85*16928Ssam 	if (depth > MAXDEPTH) {
86*16928Ssam 	    depth = 0;
87*16928Ssam 	    error("Alias loop (maximum %d deep).\n", MAXDEPTH);
889679Slinton 	}
89*16928Ssam again:
90*16928Ssam 	do
91*16928Ssam 		c = getch();
92*16928Ssam 	while (c == ' ' || c == '\t');
93*16928Ssam 	if (isalpha(c) || c == '_' || c == '$') {
94*16928Ssam 		t = getident(c);
95*16928Ssam 		if (t == NAME && doaliases) {
96*16928Ssam 			p = findalias(yylval.y_name);
97*16928Ssam 			if (p != nil) {
98*16928Ssam 				if (lexdebug)
99*16928Ssam 					fprintf(stderr, "alias %s to \"%s\"\n",
100*16928Ssam 					    ident(yylval.y_name), p);
101*16928Ssam 				if (!pushinput(ST_ALIAS, "", p)) {
102*16928Ssam 					unwindinput(ST_ALIAS);
103*16928Ssam 					error("Alias stack overflow.");
104*16928Ssam 				}
105*16928Ssam 				t = yylex();
106*16928Ssam 			}
107*16928Ssam 		}
108*16928Ssam 		goto done;
1099679Slinton 	}
110*16928Ssam 	if (isdigit(c)) {
111*16928Ssam 		t = shellmode ? getident(c) : getnum(c);
112*16928Ssam 		goto done;
11312120Slinton 	}
1149679Slinton 	switch (c) {
115*16928Ssam 
116*16928Ssam 	case '\n':
1179679Slinton 		t = '\n';
118*16928Ssam 		if (sp->s_lineno != 0) {
119*16928Ssam 			sp->s_lineno++;
120*16928Ssam 			if (sp->s_type == ST_FILE)
121*16928Ssam 				errlineno = sp->s_lineno;
1229679Slinton 		}
1239679Slinton 		break;
1249679Slinton 
125*16928Ssam 	case '"':
126*16928Ssam 	case '\'':
127*16928Ssam 		t = getstring(c);
1289679Slinton 		break;
1299679Slinton 
130*16928Ssam 	case '.':
1319679Slinton 		if (shellmode) {
132*16928Ssam 			t = getident(c);
133*16928Ssam 			break;
1349679Slinton 		}
135*16928Ssam 		c = getch();
136*16928Ssam 		ungetch(c);
137*16928Ssam 		t = isdigit(c) ? getnum('.') : '.';
1389679Slinton 		break;
1399679Slinton 
140*16928Ssam 	case '<':
141*16928Ssam 		c = getch();
142*16928Ssam 		if (shellmode || c != '<') {
143*16928Ssam 			ungetch(c);
144*16928Ssam 			t = '<';
145*16928Ssam 		} else
146*16928Ssam 			t = LFORMER;
1479679Slinton 		break;
1489679Slinton 
149*16928Ssam 	case '>':
150*16928Ssam 		c = getch();
151*16928Ssam 		if (shellmode || c != '>') {
152*16928Ssam 			ungetch(c);
153*16928Ssam 			t = '>';
154*16928Ssam 		} else
155*16928Ssam 			t = RFORMER;
1569679Slinton 		break;
1579679Slinton 
158*16928Ssam 	case '#':
159*16928Ssam 		c = getch();
160*16928Ssam 		if (c != '^') {
161*16928Ssam 			ungetch(c);
162*16928Ssam 			t = '#';
163*16928Ssam 		} else
164*16928Ssam 			t = ABSTRACTION;
1659679Slinton 		break;
1669679Slinton 
167*16928Ssam 	case '-':
1689679Slinton 		if (shellmode) {
169*16928Ssam 			t = getident(c);
170*16928Ssam 			break;
1719679Slinton 		}
172*16928Ssam 		c = getch();
173*16928Ssam 		if (c != '>') {
174*16928Ssam 			ungetch(c);
175*16928Ssam 			t = '-';
176*16928Ssam 		} else
177*16928Ssam 			t = ARROW;
1789679Slinton 		break;
1799679Slinton 
180*16928Ssam 	case EOF:
1819679Slinton 		t = 0;
1829679Slinton 		break;
1839679Slinton 
184*16928Ssam 	default:
185*16928Ssam 		t = shellmode && index("!&*()[];", c) == nil ?
186*16928Ssam 		    getident(c) : c;
1879679Slinton 		break;
1889679Slinton 	}
189*16928Ssam done:
1909679Slinton 	if (lexdebug) {
191*16928Ssam 		fprintf(stderr, "token ");
192*16928Ssam 		print_token(stderr, t);
193*16928Ssam 		fprintf(stderr, "\n");
1949679Slinton 	}
195*16928Ssam 	depth--;
196*16928Ssam 	return (t);
1979679Slinton }
1989679Slinton 
1999679Slinton /*
200*16928Ssam  * Scan an identifier and check to see if it's a keyword.
2019679Slinton  */
202*16928Ssam private Token getident(c)
203*16928Ssam Char c;
2049679Slinton {
205*16928Ssam 	register Char *p, *q;
206*16928Ssam 	Token t;
2079679Slinton 
208*16928Ssam 	q = yytext;
209*16928Ssam 	if (shellmode) {
210*16928Ssam 		do {
211*16928Ssam 			*q++ = c;
212*16928Ssam 			c = getch();
213*16928Ssam 		} while (index(" \t\n!&<>*[]();", c) == nil);
2149679Slinton 	} else {
215*16928Ssam 		do {
216*16928Ssam 			*q++ = c;
217*16928Ssam 			c = getch();
218*16928Ssam 		} while (isalnum(c) || c == '_' || c == '$');
2199679Slinton 	}
220*16928Ssam 	ungetch(c);
221*16928Ssam 	*q = '\0';
222*16928Ssam 	yylval.y_name = identname(yytext, false);
223*16928Ssam 	if (shellmode)
224*16928Ssam 		return (NAME);
2259679Slinton 	t = findkeyword(yylval.y_name);
226*16928Ssam 	return (t == nil ? NAME : t);
2279679Slinton }
2289679Slinton 
2299679Slinton /*
2309679Slinton  * Scan a number.
2319679Slinton  */
232*16928Ssam private Token getnum(c)
233*16928Ssam Char c;
2349679Slinton {
235*16928Ssam 	register Char *q;
236*16928Ssam 	register Token t;
237*16928Ssam 	Integer base = 10;
2389679Slinton 
239*16928Ssam 	q = yytext;
240*16928Ssam 	if (c == '0') {
241*16928Ssam 		c = getch();
242*16928Ssam 		if (c == 'x') {
243*16928Ssam 			base = 16;
244*16928Ssam 		} else {
245*16928Ssam 			base = 8;
246*16928Ssam 			ungetch(c);
247*16928Ssam 			c = '0';
248*16928Ssam 		}
249*16928Ssam 	}
250*16928Ssam 	if (base == 16) {
251*16928Ssam 		while (isdigit(c = getch()) ||
252*16928Ssam 		    (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
253*16928Ssam 			*q++ = c;
2549679Slinton 	} else {
255*16928Ssam 		do {
256*16928Ssam 			*q++ = c;
257*16928Ssam 			c = getch();
258*16928Ssam 		} while (isdigit(c));
2599679Slinton 	}
260*16928Ssam 	if (c == '.') {
2619679Slinton 		do {
262*16928Ssam 			*q++ = c;
263*16928Ssam 			c = getch();
264*16928Ssam 		} while (isdigit(c));
265*16928Ssam 		if (c == 'e' || c == 'E') {
266*16928Ssam 			c = getch();
267*16928Ssam 			if (c == '+' || c == '-' || isdigit(c)) {
268*16928Ssam 				*q++ = 'e';
269*16928Ssam 				do {
270*16928Ssam 					*q++ = c;
271*16928Ssam 					c = getch();
272*16928Ssam 				} while (isdigit(c));
273*16928Ssam 			}
274*16928Ssam 		}
275*16928Ssam 		ungetch(c);
276*16928Ssam 		*q = '\0';
277*16928Ssam 		yylval.y_real = atof(yytext);
278*16928Ssam 		return (REAL);
2799679Slinton 	}
280*16928Ssam 	ungetch(c);
2819679Slinton 	*q = '\0';
2829679Slinton 	switch (base) {
283*16928Ssam 
284*16928Ssam 	case 10:
285*16928Ssam 		yylval.y_int = atol(yytext);
2869679Slinton 		break;
2879679Slinton 
288*16928Ssam 	case 8:
289*16928Ssam 		yylval.y_int = octal(yytext);
2909679Slinton 		break;
2919679Slinton 
292*16928Ssam 	case 16:
293*16928Ssam 		yylval.y_int = hex(yytext);
2949679Slinton 		break;
2959679Slinton 
296*16928Ssam 	default:
2979679Slinton 		badcaseval(base);
2989679Slinton 	}
299*16928Ssam 	return (INT);
3009679Slinton }
3019679Slinton 
3029679Slinton /*
3039679Slinton  * Convert a string of octal digits to an integer.
3049679Slinton  */
3059679Slinton private int octal(s)
3069679Slinton String s;
3079679Slinton {
308*16928Ssam 	register Char *p;
309*16928Ssam 	register Integer n;
3109679Slinton 
311*16928Ssam 	n = 0;
312*16928Ssam 	for (p = s; *p != '\0'; p++)
313*16928Ssam 		n = (n << 3) + (*p - '0');
314*16928Ssam 	return (n);
3159679Slinton }
3169679Slinton 
3179679Slinton /*
3189679Slinton  * Convert a string of hexadecimal digits to an integer.
3199679Slinton  */
3209679Slinton private int hex(s)
3219679Slinton String s;
3229679Slinton {
323*16928Ssam 	register Char *p;
324*16928Ssam 	register Integer n;
3259679Slinton 
326*16928Ssam 	n = 0;
327*16928Ssam 	for (p = s; *p != '\0'; p++) {
328*16928Ssam 		n <<= 4;
329*16928Ssam 		if (*p >= 'a' && *p <= 'f')
330*16928Ssam 			n += (*p - 'a' + 10);
331*16928Ssam 		else if (*p >= 'A' && *p <= 'F')
332*16928Ssam 			n += (*p - 'A' + 10);
333*16928Ssam 		else
334*16928Ssam 			n += (*p - '0');
3359679Slinton 	}
336*16928Ssam 	return (n);
3379679Slinton }
3389679Slinton 
3399679Slinton /*
3409679Slinton  * Scan a string.
3419679Slinton  */
342*16928Ssam private Token getstring(match)
343*16928Ssam Char match;
3449679Slinton {
345*16928Ssam 	register Char *q, c;
3469679Slinton 
347*16928Ssam 	q = yytext;
348*16928Ssam 	for (;;) {
349*16928Ssam 		c = getch();
350*16928Ssam 		if (c == '\n' || c == EOF) {
351*16928Ssam 			error("Unterminated string.");
352*16928Ssam 			break;
353*16928Ssam 		}
354*16928Ssam 		if (c == match)
355*16928Ssam 			break;
356*16928Ssam 		*q++ = charcon(c);
3579679Slinton 	}
358*16928Ssam 	*q = '\0';
359*16928Ssam 	yylval.y_string = strdup(yytext);
360*16928Ssam 	return (STRING);
3619679Slinton }
3629679Slinton 
3639679Slinton /*
3649679Slinton  * Process a character constant.
3659679Slinton  * Watch out for backslashes.
3669679Slinton  */
367*16928Ssam private Char charcon(c)
368*16928Ssam Char c;
3699679Slinton {
370*16928Ssam 	register char *cp;
3719679Slinton 
372*16928Ssam 	if (c == '\\') {
373*16928Ssam 		c = getch();
374*16928Ssam 		if (isdigit(c)) {
375*16928Ssam 			int v;
376*16928Ssam 
377*16928Ssam 			v = 0;
378*16928Ssam 			do {
379*16928Ssam 				v = (v << 3) + (c - '0');
380*16928Ssam 				c = getch();
381*16928Ssam 			} while (isdigit(c));
382*16928Ssam 			ungetch(c);
383*16928Ssam 			return (v);
384*16928Ssam 		}
385*16928Ssam 		for (cp = "f\ft\tb\bn\nr\rv\v"; *cp != c; cp += 2)
386*16928Ssam 			;
387*16928Ssam 		if (*cp != '\0')
388*16928Ssam 			c = *cp;
3899679Slinton 	}
390*16928Ssam 	return (c);
3919679Slinton }
3929679Slinton 
3939679Slinton /*
394*16928Ssam  * Parser error handling.
3959679Slinton  */
396*16928Ssam public yyerror(s)
3979679Slinton String s;
3989679Slinton {
3999679Slinton 
400*16928Ssam 	if (streq(s, "syntax error")) {
401*16928Ssam 		beginerrmsg();
402*16928Ssam 		fprintf(stderr, "Syntax error");
403*16928Ssam 		if (yytext[0] != '\0')
404*16928Ssam 			fprintf(stderr, " on \"%s\".", yytext);
405*16928Ssam 		enderrmsg();
406*16928Ssam 		return;
4079679Slinton 	}
408*16928Ssam 	error(s);
4099679Slinton }
4109679Slinton 
4119679Slinton /*
412*16928Ssam  * Eat the current line.
413*16928Ssam  */
414*16928Ssam private Char lastc = '\0';
415*16928Ssam 
416*16928Ssam public gobble()
417*16928Ssam {
418*16928Ssam 	register char c;
419*16928Ssam 
420*16928Ssam 	if (lastc != '\n' && lastc != EOF)
421*16928Ssam 		while ((c = getch()) != EOF && c != '\n')
422*16928Ssam 			;
423*16928Ssam }
424*16928Ssam 
425*16928Ssam /*
4269679Slinton  * Input file management routines.
4279679Slinton  */
4289679Slinton public setinput(filename)
4299679Slinton Filename filename;
4309679Slinton {
431*16928Ssam 	File f;
4329679Slinton 
433*16928Ssam 	f = fopen(filename, "r");
434*16928Ssam 	if (f == nil)
435*16928Ssam 		error("%s: Can't open.", filename);
436*16928Ssam 	if (!pushinput(ST_FILE, filename, f)) {
437*16928Ssam 		unwindinput(ST_FILE);
438*16928Ssam 		error("Source file nesting too deep.");
4399679Slinton 	}
4409679Slinton }
4419679Slinton 
442*16928Ssam /*
443*16928Ssam  * Send the current line to the shell.
444*16928Ssam  */
445*16928Ssam public shellline()
4469679Slinton {
447*16928Ssam 	register Char *p, c;
4489679Slinton 
449*16928Ssam 	for (p = yytext; (c = getch()) != EOF && c != '\n'; *p++ = c)
450*16928Ssam 		;
451*16928Ssam 	*p = '\0';
452*16928Ssam 	shell(yytext);
453*16928Ssam 	erecover();
4549679Slinton }
4559679Slinton 
4569679Slinton /*
457*16928Ssam  * Read the rest of the current line in "shell mode".
4589679Slinton  */
459*16928Ssam public beginshellmode()
460*16928Ssam {
4619679Slinton 
462*16928Ssam 	shellmode = true;
463*16928Ssam }
464*16928Ssam 
465*16928Ssam public endshellmode()
4669679Slinton {
4679679Slinton 
468*16928Ssam 	shellmode = false;
4699679Slinton }
4709679Slinton 
471*16928Ssam public stopaliasing()
472*16928Ssam {
473*16928Ssam 
474*16928Ssam 	doaliases = false;
475*16928Ssam }
476*16928Ssam 
477*16928Ssam public startaliasing()
478*16928Ssam {
479*16928Ssam 
480*16928Ssam 	doaliases = true;
481*16928Ssam }
482*16928Ssam 
4839679Slinton /*
484*16928Ssam  * Print out a token for debugging.
4859679Slinton  */
486*16928Ssam public print_token(f, t)
487*16928Ssam File f;
488*16928Ssam Token t;
489*16928Ssam {
4909679Slinton 
491*16928Ssam 	switch (t) {
492*16928Ssam 
493*16928Ssam 	case '\n':
494*16928Ssam 		fprintf(f, "char '\\n'");
495*16928Ssam 		return;
496*16928Ssam 
497*16928Ssam 	case EOF:
498*16928Ssam 		fprintf(f, "EOF");
499*16928Ssam 		return;
500*16928Ssam 
501*16928Ssam 	case NAME:
502*16928Ssam 	case STRING:
503*16928Ssam 		fprintf(f, "%s, \"%s\"", keywdstring(t), ident(yylval.y_name));
504*16928Ssam 		return;
505*16928Ssam 	}
506*16928Ssam 	if (t < 256)
507*16928Ssam 		fprintf(f, "char '%c'", t);
508*16928Ssam 	else
509*16928Ssam 		fprintf(f, "%s", keywdstring(t));
510*16928Ssam }
511*16928Ssam 
512*16928Ssam public int getch()
5139679Slinton {
514*16928Ssam 	int c;
515*16928Ssam 
516*16928Ssam again:
517*16928Ssam 	switch (sp->s_type) {
518*16928Ssam 
519*16928Ssam 	case ST_FILE:
520*16928Ssam 		c = getc(sp->s_file);
521*16928Ssam 		if (c == EOF && isterm(sp->s_file)) {
522*16928Ssam 			clearerr(sp->s_file);
523*16928Ssam 			putchar('\n');
524*16928Ssam 			c = '\n';
525*16928Ssam 		}
526*16928Ssam 		break;
527*16928Ssam 
528*16928Ssam 	case ST_ALIAS:
529*16928Ssam 		c = *sp->s_cur++;
530*16928Ssam 		if (c == '\0') {
531*16928Ssam 			c = EOF;
532*16928Ssam 			--sp->s_cur;
533*16928Ssam 		}
534*16928Ssam 		break;
535*16928Ssam 
536*16928Ssam 	default:
537*16928Ssam 		panic("Invalid input stream (type %d) to getch.",
538*16928Ssam 		    sp->s_type);
539*16928Ssam 	}
540*16928Ssam 	if (c == EOF && popinput())
541*16928Ssam 		goto again;
542*16928Ssam 	return (lastc = c);
5439679Slinton }
5449679Slinton 
545*16928Ssam private int ungetch(c)
546*16928Ssam Char c;
547*16928Ssam {
548*16928Ssam 	Char uc;
549*16928Ssam 
550*16928Ssam 	if (c != EOF) switch (sp->s_type) {
551*16928Ssam 
552*16928Ssam 	case ST_FILE:
553*16928Ssam 		uc = ungetc(c, sp->s_file);
554*16928Ssam 		break;
555*16928Ssam 
556*16928Ssam 	case ST_ALIAS:
557*16928Ssam 		if (sp->s_cur == sp->s_data)
558*16928Ssam 			panic("Illegal ungetch on alias.");
559*16928Ssam 		*--sp->s_cur = c;
560*16928Ssam 		uc = c;
561*16928Ssam 		break;
562*16928Ssam 
563*16928Ssam 	default:
564*16928Ssam 		panic("Invalid input stream (type %d) to ungetch.",
565*16928Ssam 		    sp->s_type);
566*16928Ssam 	}
567*16928Ssam 	lastc = '\0';
568*16928Ssam 	return (uc);
569*16928Ssam }
570*16928Ssam 
5719679Slinton /*
572*16928Ssam  * Push the current input stream and
573*16928Ssam  * make the supplied stream the current.
5749679Slinton  */
575*16928Ssam /*VARARGS3*/
576*16928Ssam public pushinput(type, name, info)
577*16928Ssam int type;
578*16928Ssam Filename name;
579*16928Ssam {
5809679Slinton 
581*16928Ssam 	if (sp >= &stack[NSTREAMS])
582*16928Ssam 		return (0);
583*16928Ssam 	++sp;
584*16928Ssam 	sp->s_type = type;
585*16928Ssam 	switch (type) {
586*16928Ssam 
587*16928Ssam 	case ST_FILE:
588*16928Ssam 		sp->s_file = (File)info;
589*16928Ssam 		errfilename = sp->s_name = name;
590*16928Ssam 		errlineno = sp->s_lineno = 1;
591*16928Ssam 		break;
592*16928Ssam 
593*16928Ssam 	case ST_ALIAS:
594*16928Ssam 		sp->s_cur = sp->s_data = (char *)info;
595*16928Ssam 		break;
596*16928Ssam 
597*16928Ssam 	default:
598*16928Ssam 		panic("Invalid input stream (type %d) to pushinput.", type);
599*16928Ssam 	}
600*16928Ssam 	return (1);
601*16928Ssam }
602*16928Ssam 
603*16928Ssam public popinput()
6049679Slinton {
6059679Slinton 
606*16928Ssam 	if (sp <= &stack[0])		/* never pop stdin or equivalent */
607*16928Ssam 		return (0);
608*16928Ssam 	if (sp->s_type == ST_FILE && sp->s_file != stdin)
609*16928Ssam 		fclose(sp->s_file);
610*16928Ssam 	--sp;
611*16928Ssam 	if (sp->s_type == ST_FILE)
612*16928Ssam 		errfilename = sp->s_name;
613*16928Ssam 	errlineno = sp->s_lineno;
614*16928Ssam 	return (1);
6159679Slinton }
6169679Slinton 
6179679Slinton /*
618*16928Ssam  * Unwind the input stack of all input types specified.
619*16928Ssam  * This is called to recover from an infinite
620*16928Ssam  * loop in alias processing or source file including.
6219679Slinton  */
622*16928Ssam public unwindinput(type)
623*16928Ssam Integer type;
624*16928Ssam {
6259679Slinton 
626*16928Ssam 	while (sp->s_type == type && popinput())
627*16928Ssam 		;
6289679Slinton }
6299679Slinton 
6309679Slinton /*
631*16928Ssam  * Return whether we are currently reading from standard input.
6329679Slinton  */
633*16928Ssam public Boolean isstdin()
634*16928Ssam {
6359679Slinton 
636*16928Ssam 	return ((Boolean)(sp->s_type == ST_FILE && sp->s_file == stdin));
637*16928Ssam }
638*16928Ssam 
639*16928Ssam public Boolean istty()
6409679Slinton {
641*16928Ssam 
642*16928Ssam 	return ((Boolean)isterm(sp->s_file));
6439679Slinton }
644