⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parser.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
 *	quoted. * If the token is TREDIR, then we set redirnode to a structure containing *	the redirection. * In all cases, the variable startlinno is set to the number of the line *	on which the token starts. * * [Change comment:  here documents and internal procedures] * [Readtoken shouldn't have any arguments.  Perhaps we should make the *  word parsing code into a separate routine.  In this case, readtoken *  doesn't need to have any internal procedures, but parseword does. *  We could also make parseoperator in essence the main routine, and *  have parseword (readtoken1?) handle both words and redirection.] */#define RETURN(token)	return lasttoken = tokenSTATIC intxxreadtoken() {	register c;	if (tokpushback) {		tokpushback = 0;		return lasttoken;	}	if (needprompt) {		putprompt(ps2val());		needprompt = 0;	}	startlinno = plinno;	for (;;) {	/* until token or start of word found */		c = pgetc_macro();		if (c == ' ' || c == '\t')			continue;		/* quick check for white space first */		switch (c) {		case ' ': case '\t':			continue;		case '#':			while ((c = pgetc()) != '\n' && c != PEOF);			pungetc();			continue;		case '\\':			if (pgetc() == '\n') {				startlinno = ++plinno;				if (doprompt)					putprompt(ps2val());				continue;			}			pungetc();			goto breakloop;		case '\n':			plinno++;			needprompt = doprompt;			RETURN(TNL);		case PEOF:			RETURN(TEOF);		case '&':			if (pgetc() == '&')				RETURN(TAND);			pungetc();			RETURN(TBACKGND);		case '|':			if (pgetc() == '|')				RETURN(TOR);			pungetc();			RETURN(TPIPE);		case ';':			if (pgetc() == ';')				RETURN(TENDCASE);			pungetc();			RETURN(TSEMI);		case '(':			RETURN(TLP);		case ')':			RETURN(TRP);		default:			goto breakloop;		}	}breakloop:	return readtoken1(c, BASESYNTAX, (char *)NULL, 0);#undef RETURN}/* * If eofmark is NULL, read a word or a redirection symbol.  If eofmark * is not NULL, read a here document.  In the latter case, eofmark is the * word which marks the end of the document and striptabs is true if * leading tabs should be stripped from the document.  The argument firstc * is the first character of the input token or document. * * Because C does not have internal subroutines, I have simulated them * using goto's to implement the subroutine linkage.  The following macros * will run code that appears at the end of readtoken1. */#define CHECKEND()	{goto checkend; checkend_return:;}#define PARSEREDIR()	{goto parseredir; parseredir_return:;}#define PARSESUB()	{goto parsesub; parsesub_return:;}#define PARSEBACKQOLD()	{oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}#define PARSEBACKQNEW()	{oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}STATIC intreadtoken1(firstc, syntax, eofmark, striptabs)	int firstc;	char const *syntax;	char *eofmark;	int striptabs;	{	register c = firstc;	register char *out;	int len;	char line[EOFMARKLEN + 1];	struct nodelist *bqlist;	int quotef;	int dblquote;	int varnest;	int oldstyle;	startlinno = plinno;	dblquote = 0;	if (syntax == DQSYNTAX)		dblquote = 1;	quotef = 0;	bqlist = NULL;	varnest = 0;	STARTSTACKSTR(out);	loop: {	/* for each line, until end of word */#if ATTY		if (c == '\034' && doprompt		 && attyset() && ! equal(termval(), "emacs")) {			attyline();			if (syntax == BASESYNTAX)				return readtoken();			c = pgetc();			goto loop;		}#endif		CHECKEND();	/* set c to PEOF if at end of here document */		for (;;) {	/* until end of line or end of word */			CHECKSTRSPACE(3, out);	/* permit 3 calls to USTPUTC */			switch(syntax[c]) {			case CNL:	/* '\n' */				if (syntax == BASESYNTAX)					goto endword;	/* exit outer loop */				USTPUTC(c, out);				plinno++;				if (doprompt) {					putprompt(ps2val());				}				c = pgetc();				goto loop;		/* continue outer loop */			case CWORD:				USTPUTC(c, out);				break;			case CCTL:				if (eofmark == NULL || dblquote)					USTPUTC(CTLESC, out);				USTPUTC(c, out);				break;			case CBACK:	/* backslash */				c = pgetc();				if (c == PEOF) {					USTPUTC('\\', out);					pungetc();				} else if (c == '\n') {					if (doprompt)						putprompt(ps2val());				} else {					if (dblquote && c != '\\' && c != '`' && c != '$'							 && (c != '"' || eofmark != NULL))						USTPUTC('\\', out);					if (SQSYNTAX[c] == CCTL)						USTPUTC(CTLESC, out);					USTPUTC(c, out);					quotef++;				}				break;			case CSQUOTE:				syntax = SQSYNTAX;				break;			case CDQUOTE:				syntax = DQSYNTAX;				dblquote = 1;				break;			case CENDQUOTE:				if (eofmark) {					USTPUTC(c, out);				} else {					syntax = BASESYNTAX;					quotef++;					dblquote = 0;				}				break;			case CVAR:	/* '$' */				PARSESUB();		/* parse substitution */				break;			case CENDVAR:	/* '}' */				if (varnest > 0) {					varnest--;					USTPUTC(CTLENDVAR, out);				} else {					USTPUTC(c, out);				}				break;			case CBQUOTE:	/* '`' */				PARSEBACKQOLD();				break;			case CEOF:				goto endword;		/* exit outer loop */			default:				if (varnest == 0)					goto endword;	/* exit outer loop */				USTPUTC(c, out);			}			c = pgetc_macro();		}	}endword:	if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)		synerror("Unterminated quoted string");	if (varnest != 0) {		startlinno = plinno;		synerror("Missing '}'");	}	USTPUTC('\0', out);	len = out - stackblock();	out = stackblock();	if (eofmark == NULL) {		if ((c == '>' || c == '<')		 && quotef == 0		 && len <= 2		 && (*out == '\0' || is_digit(*out))) {			PARSEREDIR();			return lasttoken = TREDIR;		} else {			pungetc();		}	}	quoteflag = quotef;	backquotelist = bqlist;	grabstackblock(len);	wordtext = out;	return lasttoken = TWORD;/* end of readtoken routine *//* * Check to see whether we are at the end of the here document.  When this * is called, c is set to the first character of the next input line.  If * we are at the end of the here document, this routine sets the c to PEOF. */checkend: {	if (eofmark) {		if (striptabs) {			while (c == '\t')				c = pgetc();		}		if (c == *eofmark) {			if (pfgets(line, sizeof line) != NULL) {				register char *p, *q;				p = line;				for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);				if (*p == '\n' && *q == '\0') {					c = PEOF;					plinno++;					needprompt = doprompt;				} else {					ppushback(line, strlen(line));				}			}		}	}	goto checkend_return;}/* * Parse a redirection operator.  The variable "out" points to a string * specifying the fd to be redirected.  The variable "c" contains the * first character of the redirection operator. */parseredir: {	char fd = *out;	union node *np;	np = (union node *)stalloc(sizeof (struct nfile));	if (c == '>') {		np->nfile.fd = 1;		c = pgetc();		if (c == '>')			np->type = NAPPEND;		else if (c == '&')			np->type = NTOFD;		else {			np->type = NTO;			pungetc();		}	} else {	/* c == '<' */		np->nfile.fd = 0;		c = pgetc();		if (c == '<') {			if (sizeof (struct nfile) != sizeof (struct nhere)) {				np = (union node *)stalloc(sizeof (struct nhere));				np->nfile.fd = 0;			}			np->type = NHERE;			heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));			heredoc->here = np;			if ((c = pgetc()) == '-') {				heredoc->striptabs = 1;			} else {				heredoc->striptabs = 0;				pungetc();			}		} else if (c == '&')			np->type = NFROMFD;		else {			np->type = NFROM;			pungetc();		}	}	if (fd != '\0')		np->nfile.fd = digit_val(fd);	redirnode = np;	goto parseredir_return;}/* * Parse a substitution.  At this point, we have read the dollar sign * and nothing else. */parsesub: {	int subtype;	int typeloc;	int flags;	char *p;#ifndef GDB_HACK	static const char types[] = "}-+?=";#endif	c = pgetc();	if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {		USTPUTC('$', out);		pungetc();	} else if (c == '(') {	/* $(command) */		PARSEBACKQNEW();	} else {		USTPUTC(CTLVAR, out);		typeloc = out - stackblock();		USTPUTC(VSNORMAL, out);		subtype = VSNORMAL;		if (c == '{') {			c = pgetc();			subtype = 0;		}		if (is_name(c)) {			do {				STPUTC(c, out);				c = pgetc();			} while (is_in_name(c));		} else {			if (! is_special(c))badsub:				synerror("Bad substitution");			USTPUTC(c, out);			c = pgetc();		}		STPUTC('=', out);		flags = 0;		if (subtype == 0) {			if (c == ':') {				flags = VSNUL;				c = pgetc();			}			p = strchr(types, c);			if (p == NULL)				goto badsub;			subtype = p - types + VSNORMAL;		} else {			pungetc();		}		if (dblquote)			flags |= VSQUOTE;		*(stackblock() + typeloc) = subtype | flags;		if (subtype != VSNORMAL)			varnest++;	}	goto parsesub_return;}/* * Called to parse command substitutions.  Newstyle is set if the command * is enclosed inside $(...); nlpp is a pointer to the head of the linked * list of commands (passed by reference), and savelen is the number of * characters on the top of the stack which must be preserved. */parsebackq: {	struct nodelist **nlpp;	int savepbq;	union node *n;	char *volatile str;	struct jmploc jmploc;	struct jmploc *volatile savehandler;	int savelen;	int savedoprompt;	savepbq = parsebackquote;	if (setjmp(jmploc.loc)) {		if (str)			ckfree(str);		parsebackquote = 0;		handler = savehandler;		longjmp(handler->loc, 1);	}	INTOFF;	str = NULL;	savelen = out - stackblock();	if (savelen > 0) {		str = ckmalloc(savelen);		bcopy(stackblock(), str, savelen);	}	savehandler = handler;	handler = &jmploc;	INTON;	if (oldstyle) {		/* We must read until the closing backquote, giving special		   treatment to some slashes, and then push the string and		   reread it as input, interpreting it normally.  */		register char *out;		register c;		int savelen;		char *str;		STARTSTACKSTR(out);		while ((c = pgetc ()) != '`') {			if (c == '\\') {				c = pgetc ();				if (c != '\\' && c != '`' && c != '$'				    && (!dblquote || c != '"'))					STPUTC('\\', out);			}			if (c == '\n') {				plinno++;				if (doprompt)					putprompt(ps2val());			}			STPUTC(c, out);		}		STPUTC('\0', out);		savelen = out - stackblock();		if (savelen > 0) {			str = ckmalloc(savelen);			bcopy(stackblock(), str, savelen);		}		setinputstring(str, 1);		savedoprompt = doprompt;		doprompt = 0;	/* no prompts while rereading string */	}	nlpp = &bqlist;	while (*nlpp)		nlpp = &(*nlpp)->next;	*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));	(*nlpp)->next = NULL;	parsebackquote = oldstyle;	n = list(0);	if (!oldstyle && (readtoken() != TRP))		synexpect(TRP);	(*nlpp)->n = n;	/* Start reading from old file again.  */	if (oldstyle) {		popfile();		doprompt = savedoprompt;	}	while (stackblocksize() <= savelen)		growstackblock();	STARTSTACKSTR(out);	if (str) {		bcopy(str, out, savelen);		STADJUST(savelen, out);		INTOFF;		ckfree(str);		str = NULL;		INTON;	}	parsebackquote = savepbq;	handler = savehandler;	USTPUTC(CTLBACKQ + dblquote, out);	if (oldstyle)		goto parsebackq_oldreturn;	else		goto parsebackq_newreturn;}} /* end of readtoken */#ifdef mkinitRESET {	tokpushback = 0;}#endif#if READLINE/* * Remember a prompt for use with readline if input and output is a terminal. */STATIC voidputprompt(s)	char *s;	{	if (editable) {		r_use_prompt = s;	} else {		out2str(s);	}}#endif#if ATTY/* * Called to process a command generated by atty.  We execute the line, * and catch any errors that occur so they don't propagate outside of * this routine. */STATIC voidattyline() {	char line[256];	struct stackmark smark;	struct jmploc jmploc;	struct jmploc *volatile savehandler;	if (pfgets(line, sizeof line) == NULL)		return;				/* "can't happen" */	if (setjmp(jmploc.loc)) {		if (exception == EXERROR)			out2str("\033]D\n");		handler = savehandler;		longjmp(handler->loc, 1);	}	savehandler = handler;	handler = &jmploc;	setstackmark(&smark);	evalstring(line);	popstackmark(&smark);	handler = savehandler;	doprompt = 1;}/* * Output a prompt for atty.  We output the prompt as part of the * appropriate escape sequence.   */STATIC voidputprompt(s)	char *s;	{	register char *p;	if (attyset() && ! equal(termval(), "emacs")) {		if (strchr(s, '\7'))			out2c('\7');		out2str("\033]P1;");		for (p = s ; *p ; p++) {			if ((unsigned)(*p - ' ') <= '~' - ' ')				out2c(*p);		}		out2c('\n');	} else {		out2str(s);	}}#endif/* * Returns true if the text contains nothing to expand (no dollar signs * or backquotes). */STATIC intnoexpand(text)	char *text;	{	register char *p;	register char c;	p = text;	while ((c = *p++) != '\0') {		if (c == CTLESC)			p++;		else if (BASESYNTAX[c] == CCTL)			return 0;	}	return 1;}/* * Return true if the argument is a legal variable name (a letter or * underscore followed by zero or more letters, underscores, and digits). */intgoodname(name)	char *name;	{	register char *p;	p = name;	if (! is_name(*p))		return 0;	while (*++p) {		if (! is_in_name(*p))			return 0;	}	return 1;}/* * Called when an unexpected token is read during the parse.  The argument * is the token that is expected, or -1 if more than one type of token can * occur at this point. */STATIC voidsynexpect(token) {	char msg[64];	if (token >= 0) {		fmtstr(msg, 64, "%s unexpected (expecting %s)",			tokname[lasttoken], tokname[token]);	} else {		fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);	}	synerror(msg);}STATIC voidsynerror(msg)	char *msg;	{	if (commandname)		outfmt(&errout, "%s: %d: ", commandname, startlinno);	outfmt(&errout, "Syntax error: %s\n", msg);	error((char *)NULL);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -