parser.c

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

C
1,652
字号
		negate = !negate;	}	tokpushback++;	for (;;) {		if (readtoken() == TWORD) {			n = (union node *)stalloc(sizeof (struct narg));			n->type = NARG;			n->narg.text = wordtext;			n->narg.backquote = backquotelist;			*app = n;			app = &n->narg.next;		} else if (lasttoken == TREDIR) {			*rpp = n = redirnode;			rpp = &n->nfile.next;			parsefname();	/* read name of redirection file */		} else if (lasttoken == TLP && app == &args->narg.next					    && rpp == orig_rpp) {			/* We have a function */			if (readtoken() != TRP)				synexpect(TRP);#ifdef notdef			if (! goodname(n->narg.text))				synerror("Bad function name");#endif			n->type = NDEFUN;			n->narg.next = command();			goto checkneg;		} else {			tokpushback++;			break;		}	}	*app = NULL;	*rpp = NULL;	n = (union node *)stalloc(sizeof (struct ncmd));	n->type = NCMD;	n->ncmd.backgnd = 0;	n->ncmd.args = args;	n->ncmd.redirect = redir;checkneg:	if (negate) {		n2 = (union node *)stalloc(sizeof (struct nnot));		n2->type = NNOT;		n2->nnot.com = n;		return n2;	}	else		return n;}STATIC union node *makename(void){	union node *n;	n = (union node *)stalloc(sizeof (struct narg));	n->type = NARG;	n->narg.next = NULL;	n->narg.text = wordtext;	n->narg.backquote = backquotelist;	return n;}void fixredir(union node *n, const char *text, int err)	{	TRACE(("Fix redir %s %d\n", text, err));	if (!err)		n->ndup.vname = NULL;	if (is_digit(text[0]) && text[1] == '\0')		n->ndup.dupfd = digit_val(text[0]);	else if (text[0] == '-' && text[1] == '\0')		n->ndup.dupfd = -1;	else {		if (err)			synerror("Bad fd number");		else			n->ndup.vname = makename();	}}STATIC voidparsefname(void){	union node *n = redirnode;	if (readtoken() != TWORD)		synexpect(-1);	if (n->type == NHERE) {		struct heredoc *here = heredoc;		struct heredoc *p;		int i;		if (quoteflag == 0)			n->type = NXHERE;		TRACE(("Here document %d\n", n->type));		if (here->striptabs) {			while (*wordtext == '\t')				wordtext++;		}		if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)			synerror("Illegal eof marker for << redirection");		rmescapes(wordtext);		here->eofmark = wordtext;		here->next = NULL;		if (heredoclist == NULL)			heredoclist = here;		else {			for (p = heredoclist ; p->next ; p = p->next);			p->next = here;		}	} else if (n->type == NTOFD || n->type == NFROMFD) {		fixredir(n, wordtext, 0);	} else {		n->nfile.fname = makename();	}}/* * Input any here documents. */STATIC voidparseheredoc(void){	struct heredoc *here;	union node *n;	while (heredoclist) {		here = heredoclist;		heredoclist = here->next;		if (needprompt) {			setprompt(2);			needprompt = 0;		}		readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,				here->eofmark, here->striptabs);		n = (union node *)stalloc(sizeof (struct narg));		n->narg.type = NARG;		n->narg.next = NULL;		n->narg.text = wordtext;		n->narg.backquote = backquotelist;		here->here->nhere.doc = n;	}}STATIC intpeektoken(void){	int t;	t = readtoken();	tokpushback++;	return (t);}STATIC intreadtoken(void){	int t;	int savecheckkwd = checkkwd;#ifdef DEBUG	int alreadyseen = tokpushback;#endif	struct alias *ap;	top:	t = xxreadtoken();	if (checkkwd) {		/*		 * eat newlines		 */		if (checkkwd == 2) {			checkkwd = 0;			while (t == TNL) {				parseheredoc();				t = xxreadtoken();			}		} else			checkkwd = 0;		/*		 * check for keywords and aliases		 */		if (t == TWORD && !quoteflag)		{			const char *const *pp;			for (pp = parsekwd; *pp; pp++) {				if (**pp == *wordtext && equal(*pp, wordtext))				{					lasttoken = t = pp - 					    parsekwd + KWDOFFSET;					TRACE(("keyword %s recognized\n", tokname[t]));					goto out;				}			}			if(!noalias &&			    (ap = lookupalias(wordtext, 1)) != NULL) {				pushstring(ap->val, strlen(ap->val), ap);				checkkwd = savecheckkwd;				goto top;			}		}out:		checkkwd = (t == TNOT) ? savecheckkwd : 0;	}#ifdef DEBUG	if (!alreadyseen)	    TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));	else	    TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));#endif	return (t);}/* * Read the next input token. * If the token is a word, we set backquotelist to the list of cmds in *	backquotes.  We set quoteflag to true if any part of the word was *	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(void){	int c;	if (tokpushback) {		tokpushback = 0;		return lasttoken;	}	if (needprompt) {		setprompt(2);		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)					setprompt(2);				else					setprompt(0);				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:;}#define	PARSEARITH()	{goto parsearith; parsearith_return:;}/* * Keep track of nested doublequotes in dblquote and doublequotep. * We use dblquote for the first 32 levels, and we expand to a malloc'ed * region for levels above that. Usually we never need to malloc. * This code assumes that an int is 32 bits. We don't use uint32_t, * because the rest of the code does not. */#define ISDBLQUOTE() ((varnest < 32) ? (dblquote & (1 << varnest)) : \    (dblquotep[(varnest / 32) - 1] & (1 << (varnest % 32))))#define SETDBLQUOTE() \    if (varnest < 32) \	dblquote |= (1 << varnest); \    else \	dblquotep[(varnest / 32) - 1] |= (1 << (varnest % 32))#define CLRDBLQUOTE() \    if (varnest < 32) \	dblquote &= ~(1 << varnest); \    else \	dblquotep[(varnest / 32) - 1] &= ~(1 << (varnest % 32))STATIC intreadtoken1(int firstc, char const *syntax, char *eofmark, int striptabs){	int c = firstc;	char *out;	int len;	char line[EOFMARKLEN + 1];	struct nodelist *bqlist;	int quotef;	int *dblquotep = NULL;	size_t maxnest = 32;	int dblquote;	int varnest;	/* levels of variables expansion */	int arinest;	/* levels of arithmetic expansion */	int parenlevel;	/* levels of parens in arithmetic */	int oldstyle;	char const *prevsyntax = NULL;	/* syntax before arithmetic */#if __GNUC__	/* Avoid longjmp clobbering */	(void) &maxnest;	(void) &dblquotep;	(void) &out;	(void) &quotef;	(void) &dblquote;	(void) &varnest;	(void) &arinest;	(void) &parenlevel;	(void) &oldstyle;	(void) &prevsyntax;	(void) &syntax;#endif	startlinno = plinno;	dblquote = 0;	varnest = 0;	if (syntax == DQSYNTAX) {		SETDBLQUOTE();	}	quotef = 0;	bqlist = NULL;	arinest = 0;	parenlevel = 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(4, out);	/* permit 4 calls to USTPUTC */			switch(syntax[c]) {			case CNL:	/* '\n' */				if (syntax == BASESYNTAX)					goto endword;	/* exit outer loop */				USTPUTC(c, out);				plinno++;				if (doprompt)					setprompt(2);				else					setprompt(0);				c = pgetc();				goto loop;		/* continue outer loop */			case CWORD:				USTPUTC(c, out);				break;			case CCTL:				if (eofmark == NULL || ISDBLQUOTE())					USTPUTC(CTLESC, out);				USTPUTC(c, out);				break;			case CBACK:	/* backslash */				c = pgetc();				if (c == PEOF) {					USTPUTC('\\', out);					pungetc();					break;				}				if (c == '\n') {					if (doprompt)						setprompt(2);					else						setprompt(0);					break;				}				quotef = 1;				if (ISDBLQUOTE() && c != '\\' &&				    c != '`' && c != '$' &&				    (c != '"' || eofmark != NULL))					USTPUTC('\\', out);				if (SQSYNTAX[c] == CCTL)					USTPUTC(CTLESC, out);				else if (eofmark == NULL) {					USTPUTC(CTLQUOTEMARK, out);					USTPUTC(c, out);					if (varnest != 0)						USTPUTC(CTLQUOTEEND, out);					break;				}				USTPUTC(c, out);				break;			case CSQUOTE:				if (syntax != SQSYNTAX) {					if (eofmark == NULL)						USTPUTC(CTLQUOTEMARK, out);					quotef = 1;					syntax = SQSYNTAX;					break;				}				if (eofmark != NULL && arinest == 0 &&				    varnest == 0) {					/* Ignore inside quoted here document */					USTPUTC(c, out);					break;				}				/* End of single quotes... */				if (arinest)					syntax = ARISYNTAX;				else {					syntax = BASESYNTAX;					if (varnest != 0)						USTPUTC(CTLQUOTEEND, out);				}				break;			case CDQUOTE:				if (eofmark != NULL && arinest == 0 &&				    varnest == 0) {					/* Ignore inside here document */					USTPUTC(c, out);					break;				}				quotef = 1;				if (arinest) {					if (ISDBLQUOTE()) {						syntax = ARISYNTAX;						CLRDBLQUOTE();					} else {						syntax = DQSYNTAX;						SETDBLQUOTE();						USTPUTC(CTLQUOTEMARK, out);					}					break;				}				if (eofmark != NULL)					break;				if (ISDBLQUOTE()) {					if (varnest != 0)						USTPUTC(CTLQUOTEEND, out);					syntax = BASESYNTAX;					CLRDBLQUOTE();				} else {					syntax = DQSYNTAX;					SETDBLQUOTE();					USTPUTC(CTLQUOTEMARK, out);				}				break;			case CVAR:	/* '$' */				PARSESUB();		/* parse substitution */				break;			case CENDVAR:	/* CLOSEBRACE */				if (varnest > 0 && !ISDBLQUOTE()) {					varnest--;					USTPUTC(CTLENDVAR, out);				} else {					USTPUTC(c, out);				}				break;			case CLP:	/* '(' in arithmetic */				parenlevel++;				USTPUTC(c, out);				break;			case CRP:	/* ')' in arithmetic */				if (parenlevel > 0) {					USTPUTC(c, out);					--parenlevel;				} else {					if (pgetc() == ')') {						if (--arinest == 0) {							USTPUTC(CTLENDARI, out);							syntax = prevsyntax;							if (syntax == DQSYNTAX)								SETDBLQUOTE();							else								CLRDBLQUOTE();						} else							USTPUTC(')', out);					} else {						/*						 * unbalanced parens

⌨️ 快捷键说明

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