parser.c

来自「Android 一些工具」· C语言 代码 · 共 1,652 行 · 第 1/3 页

C
1,652
字号
						 *  (don't 2nd guess - no error)						 */						pungetc();						USTPUTC(')', 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 == ARISYNTAX)		synerror("Missing '))'");	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;	if (dblquotep != NULL)	    ckfree(dblquotep);	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) {				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 {					pushstring(line, strlen(line), NULL);				}			}		}	}	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 = NCLOBBER;		else if (c == '&')			np->type = NTOFD;		else {			np->type = NTO;			pungetc();		}	} else {	/* c == '<' */		np->nfile.fd = 0;		switch (c = pgetc()) {		case '<':			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();			}			break;		case '&':			np->type = NFROMFD;			break;		case '>':			np->type = NFROMTO;			break;		default:			np->type = NFROM;			pungetc();			break;		}	}	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;	static const char types[] = "}-+?=";	c = pgetc();	if (c != '(' && c != OPENBRACE && !is_name(c) && !is_special(c)) {		USTPUTC('$', out);		pungetc();	} else if (c == '(') {	/* $(command) or $((arith)) */		if (pgetc() == '(') {			PARSEARITH();		} else {			pungetc();			PARSEBACKQNEW();		}	} else {		USTPUTC(CTLVAR, out);		typeloc = out - stackblock();		USTPUTC(VSNORMAL, out);		subtype = VSNORMAL;		if (c == OPENBRACE) {			c = pgetc();			if (c == '#') {				if ((c = pgetc()) == CLOSEBRACE)					c = '#';				else					subtype = VSLENGTH;			}			else				subtype = 0;		}		if (is_name(c)) {			do {				STPUTC(c, out);				c = pgetc();			} while (is_in_name(c));		} else if (is_digit(c)) {			do {				USTPUTC(c, out);				c = pgetc();			} while (is_digit(c));		}		else if (is_special(c)) {			USTPUTC(c, out);			c = pgetc();		}		elsebadsub:			synerror("Bad substitution");		STPUTC('=', out);		flags = 0;		if (subtype == 0) {			switch (c) {			case ':':				flags = VSNUL;				c = pgetc();				/*FALLTHROUGH*/			default:				p = strchr(types, c);				if (p == NULL)					goto badsub;				subtype = p - types + VSNORMAL;				break;			case '%':			case '#':				{					int cc = c;					subtype = c == '#' ? VSTRIMLEFT :							     VSTRIMRIGHT;					c = pgetc();					if (c == cc)						subtype++;					else						pungetc();					break;				}			}		} else {			pungetc();		}		if (ISDBLQUOTE() || arinest)			flags |= VSQUOTE;		*(stackblock() + typeloc) = subtype | flags;		if (subtype != VSNORMAL) {			varnest++;			if (varnest >= maxnest) {				dblquotep = ckrealloc(dblquotep, maxnest / 8);				dblquotep[(maxnest / 32) - 1] = 0;				maxnest += 32;			}		}	}	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 saveprompt;#ifdef __GNUC__	(void) &saveprompt;#endif	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);		memcpy(str, stackblock(), 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.  */                char *pout;                int pc;                int psavelen;                char *pstr;                STARTSTACKSTR(pout);		for (;;) {			if (needprompt) {				setprompt(2);				needprompt = 0;			}			switch (pc = pgetc()) {			case '`':				goto done;			case '\\':                                if ((pc = pgetc()) == '\n') {					plinno++;					if (doprompt)						setprompt(2);					else						setprompt(0);					/*					 * If eating a newline, avoid putting					 * the newline into the new character					 * stream (via the STPUTC after the					 * switch).					 */					continue;				}                                if (pc != '\\' && pc != '`' && pc != '$'                                    && (!ISDBLQUOTE() || pc != '"'))                                        STPUTC('\\', pout);				break;			case '\n':				plinno++;				needprompt = doprompt;				break;			case PEOF:			        startlinno = plinno;				synerror("EOF in backquote substitution"); 				break;			default:				break;			}			STPUTC(pc, pout);                }done:                STPUTC('\0', pout);                psavelen = pout - stackblock();                if (psavelen > 0) {			pstr = grabstackstr(pout);			setinputstring(pstr, 1);                }        }	nlpp = &bqlist;	while (*nlpp)		nlpp = &(*nlpp)->next;	*nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));	(*nlpp)->next = NULL;	parsebackquote = oldstyle;	if (oldstyle) {		saveprompt = doprompt;		doprompt = 0;	}	n = list(0);	if (oldstyle)		doprompt = saveprompt;	else {		if (readtoken() != TRP)			synexpect(TRP);	}	(*nlpp)->n = n;        if (oldstyle) {		/*		 * Start reading from old file again, ignoring any pushed back		 * tokens left from the backquote parsing		 */                popfile();		tokpushback = 0;	}	while (stackblocksize() <= savelen)		growstackblock();	STARTSTACKSTR(out);	if (str) {		memcpy(out, str, savelen);		STADJUST(savelen, out);		INTOFF;		ckfree(str);		str = NULL;		INTON;	}	parsebackquote = savepbq;	handler = savehandler;	if (arinest || ISDBLQUOTE())		USTPUTC(CTLBACKQ | CTLQUOTE, out);	else		USTPUTC(CTLBACKQ, out);	if (oldstyle)		goto parsebackq_oldreturn;	else		goto parsebackq_newreturn;}/* * Parse an arithmetic expansion (indicate start of one and set state) */parsearith: {	if (++arinest == 1) {		prevsyntax = syntax;		syntax = ARISYNTAX;		USTPUTC(CTLARI, out);		if (ISDBLQUOTE())			USTPUTC('"',out);		else			USTPUTC(' ',out);	} else {		/*		 * we collapse embedded arithmetic expansion to		 * parenthesis, which should be equivalent		 */		USTPUTC('(', out);	}	goto parsearith_return;}} /* end of readtoken */#ifdef mkinitRESET {	tokpushback = 0;	checkkwd = 0;}#endif/* * Returns true if the text contains nothing to expand (no dollar signs * or backquotes). */STATIC intnoexpand(char *text){	char *p;	char c;	p = text;	while ((c = *p++) != '\0') {		if (c == CTLQUOTEMARK)			continue;		if (c == CTLESC)			p++;		else if (BASESYNTAX[(int)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(char *name)	{	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(int 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);	/* NOTREACHED */}STATIC voidsynerror(const char *msg){	if (commandname)		outfmt(&errout, "%s: %d: ", commandname, startlinno);	outfmt(&errout, "Syntax error: %s\n", msg);	error((char *)NULL);	/* NOTREACHED */}STATIC voidsetprompt(int which){	whichprompt = which;#ifdef WITH_HISTORY	if (!el)#endif		out2str(getprompt(NULL));}/* * called by editline -- any expansions to the prompt *    should be added here. */const char *getprompt(void *unused)	{	switch (whichprompt) {	case 0:		return "";	case 1:		return ps1val();	case 2:		return ps2val();	default:		return "<internal prompt error>";	}}

⌨️ 快捷键说明

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