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

📄 parser.c

📁 操作系统源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*- * Copyright (c) 1991 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)parser.c	5.3 (Berkeley) 4/12/91";#endif /* not lint */#include "shell.h"#include "parser.h"#include "nodes.h"#include "expand.h"	/* defines rmescapes() */#include "redir.h"	/* defines copyfd() */#include "syntax.h"#include "options.h"#include "input.h"#include "output.h"#include "var.h"#include "error.h"#include "memalloc.h"#include "mystring.h"/* * Shell command parser. */#define EOFMARKLEN 79/* values returned by readtoken */#include "token.def"struct heredoc {	struct heredoc *next;	/* next here document in list */	union node *here;		/* redirection node */	char *eofmark;		/* string indicating end of input */	int striptabs;		/* if set, strip leading tabs */};struct heredoc *heredoclist;	/* list of here documents to read */int parsebackquote;		/* nonzero if we are inside backquotes */int doprompt;			/* if set, prompt the user */int needprompt;			/* true if interactive and at start of line */int lasttoken;			/* last token read */MKINIT int tokpushback;		/* last token pushed back */char *wordtext;			/* text of last word returned by readtoken */int checkkwd;               /* 1 == check for kwds, 2 == also eat newlines */struct nodelist *backquotelist;union node *redirnode;struct heredoc *heredoc;int quoteflag;			/* set if (part of) last token was quoted */int startlinno;			/* line # where last token started */#define GDB_HACK 1 /* avoid local declarations which gdb can't handle */#ifdef GDB_HACKstatic const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'};static const char types[] = "}-+?=";#endifSTATIC union node *list __P((int));STATIC union node *andor __P((void));STATIC union node *pipeline __P((void));STATIC union node *command __P((void));STATIC union node *simplecmd __P((union node **, union node *));STATIC void parsefname __P((void));STATIC void parseheredoc __P((void));STATIC int readtoken __P((void));STATIC int readtoken1 __P((int, char const *, char *, int));STATIC void attyline __P((void));STATIC int noexpand __P((char *));STATIC void synexpect __P((int));STATIC void synerror __P((char *));#if ATTY || READLINESTATIC void putprompt __P((char *));#else /* not ATTY */#define putprompt(s)	out2str(s)#endif/* * Read and parse a command.  Returns NEOF on end of file.  (NULL is a * valid parse tree indicating a blank line.) */union node *parsecmd(interact) {	int t;	extern int exitstatus;	doprompt = interact;	if (doprompt)		putprompt(exitstatus == 0 || vpse.flags & VUNSET					? ps1val() : pseval());	needprompt = 0;	if ((t = readtoken()) == TEOF)		return NEOF;	if (t == TNL)		return NULL;	tokpushback++;	return list(1);}STATIC union node *list(nlflag) {	union node *n1, *n2, *n3, **pn;	int first;	checkkwd = 2;	if (nlflag == 0 && tokendlist[peektoken()])		return NULL;	n1 = andor();	for (first = 1; ; first = 0) {		switch (readtoken()) {		case TBACKGND:			pn = &n1;			if (!first && n1->type == NSEMI) pn = &n1->nbinary.ch2;			if ((*pn)->type == NCMD || (*pn)->type == NPIPE) {				(*pn)->ncmd.backgnd = 1;			} else if ((*pn)->type == NREDIR) {				(*pn)->type = NBACKGND;			} else {				n3 = (union node *)stalloc(sizeof (struct nredir));				n3->type = NBACKGND;				n3->nredir.n = *pn;				n3->nredir.redirect = NULL;				*pn = n3;			}			goto tsemi;		case TNL:			tokpushback++;			/* fall through */tsemi:		case TSEMI:			if (readtoken() == TNL) {				parseheredoc();				if (nlflag)					return n1;			} else {				tokpushback++;			}			checkkwd = 2;			if (tokendlist[peektoken()])				return n1;			n2 = andor();			n3 = (union node *)stalloc(sizeof (struct nbinary));			n3->type = NSEMI;			n3->nbinary.ch1 = n1;			n3->nbinary.ch2 = n2;			n1 = n3;			break;		case TEOF:			if (heredoclist)				parseheredoc();			else				pungetc();		/* push back EOF on input */			return n1;		default:			if (nlflag)				synexpect(-1);			tokpushback++;			return n1;		}	}}STATIC union node *andor() {	union node *n1, *n2, *n3;	int t;	n1 = pipeline();	for (;;) {		if ((t = readtoken()) == TAND) {			t = NAND;		} else if (t == TOR) {			t = NOR;		} else {			tokpushback++;			return n1;		}		n2 = pipeline();		n3 = (union node *)stalloc(sizeof (struct nbinary));		n3->type = t;		n3->nbinary.ch1 = n1;		n3->nbinary.ch2 = n2;		n1 = n3;	}}STATIC union node *pipeline() {	union node *n1, *pipenode;	struct nodelist *lp, *prev;	n1 = command();	if (readtoken() == TPIPE) {		pipenode = (union node *)stalloc(sizeof (struct npipe));		pipenode->type = NPIPE;		pipenode->npipe.backgnd = 0;		lp = (struct nodelist *)stalloc(sizeof (struct nodelist));		pipenode->npipe.cmdlist = lp;		lp->n = n1;		do {			prev = lp;			lp = (struct nodelist *)stalloc(sizeof (struct nodelist));			lp->n = command();			prev->next = lp;		} while (readtoken() == TPIPE);		lp->next = NULL;		n1 = pipenode;	}	tokpushback++;	return n1;}STATIC union node *command() {	union node *n1, *n2;	union node *ap, **app;	union node *cp, **cpp;	union node *redir, **rpp;	int t;	checkkwd = 2;	redir = 0;	rpp = &redir;	/* Check for redirection which may precede command */	while (readtoken() == TREDIR) {		*rpp = n2 = redirnode;		rpp = &n2->nfile.next;		parsefname();	}	tokpushback++;	switch (readtoken()) {	case TIF:		n1 = (union node *)stalloc(sizeof (struct nif));		n1->type = NIF;		n1->nif.test = list(0);		if (readtoken() != TTHEN)			synexpect(TTHEN);		n1->nif.ifpart = list(0);		n2 = n1;		while (readtoken() == TELIF) {			n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));			n2 = n2->nif.elsepart;			n2->type = NIF;			n2->nif.test = list(0);			if (readtoken() != TTHEN)				synexpect(TTHEN);			n2->nif.ifpart = list(0);		}		if (lasttoken == TELSE)			n2->nif.elsepart = list(0);		else {			n2->nif.elsepart = NULL;			tokpushback++;		}		if (readtoken() != TFI)			synexpect(TFI);		checkkwd = 1;		break;	case TWHILE:	case TUNTIL: {		int got;		n1 = (union node *)stalloc(sizeof (struct nbinary));		n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;		n1->nbinary.ch1 = list(0);		if ((got=readtoken()) != TDO) {TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));			synexpect(TDO);		}		n1->nbinary.ch2 = list(0);		if (readtoken() != TDONE)			synexpect(TDONE);		checkkwd = 1;		break;	}	case TFOR:		if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))			synerror("Bad for loop variable");		n1 = (union node *)stalloc(sizeof (struct nfor));		n1->type = NFOR;		n1->nfor.var = wordtext;		if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {			app = &ap;			while (readtoken() == TWORD) {				n2 = (union node *)stalloc(sizeof (struct narg));				n2->type = NARG;				n2->narg.text = wordtext;				n2->narg.backquote = backquotelist;				*app = n2;				app = &n2->narg.next;			}			*app = NULL;			n1->nfor.args = ap;			/* A newline or semicolon is required here to end			   the list.  */			if (lasttoken != TNL && lasttoken != TSEMI)				synexpect(-1);		} else {#ifndef GDB_HACK			static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,								   '@', '=', '\0'};#endif			n2 = (union node *)stalloc(sizeof (struct narg));			n2->type = NARG;			n2->narg.text = (char *)argvars;			n2->narg.backquote = NULL;			n2->narg.next = NULL;			n1->nfor.args = n2;			/* A newline or semicolon is optional here. Anything			   else gets pushed back so we can read it again.  */			if (lasttoken != TNL && lasttoken != TSEMI)				tokpushback++;		}		checkkwd = 2;		if ((t = readtoken()) == TDO)			t = TDONE;		else if (t == TBEGIN)			t = TEND;		else			synexpect(-1);		n1->nfor.body = list(0);		if (readtoken() != t)			synexpect(t);		checkkwd = 1;		break;	case TCASE:		n1 = (union node *)stalloc(sizeof (struct ncase));		n1->type = NCASE;		if (readtoken() != TWORD)			synexpect(TWORD);		n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));		n2->type = NARG;		n2->narg.text = wordtext;		n2->narg.backquote = backquotelist;		n2->narg.next = NULL;		while (readtoken() == TNL);		if (lasttoken != TWORD || ! equal(wordtext, "in"))			synerror("expecting \"in\"");		cpp = &n1->ncase.cases;		while (checkkwd = 2, readtoken() == TWORD) {			*cpp = cp = (union node *)stalloc(sizeof (struct nclist));			cp->type = NCLIST;			app = &cp->nclist.pattern;			for (;;) {				*app = ap = (union node *)stalloc(sizeof (struct narg));				ap->type = NARG;				ap->narg.text = wordtext;				ap->narg.backquote = backquotelist;				if (readtoken() != TPIPE)					break;				app = &ap->narg.next;				if (readtoken() != TWORD)					synexpect(TWORD);			}			ap->narg.next = NULL;			if (lasttoken != TRP)				synexpect(TRP);			cp->nclist.body = list(0);			if ((t = readtoken()) == TESAC)				tokpushback++;			else if (t != TENDCASE)				synexpect(TENDCASE);			cpp = &cp->nclist.next;		}		*cpp = NULL;		if (lasttoken != TESAC)			synexpect(TESAC);		checkkwd = 1;		break;	case TLP:		n1 = (union node *)stalloc(sizeof (struct nredir));		n1->type = NSUBSHELL;		n1->nredir.n = list(0);		n1->nredir.redirect = NULL;		if (readtoken() != TRP)			synexpect(TRP);		checkkwd = 1;		break;	case TBEGIN:		n1 = list(0);		if (readtoken() != TEND)			synexpect(TEND);		checkkwd = 1;		break;	/* Handle an empty command like other simple commands.  */	case TNL:	case TSEMI:	case TEND:	case TRP:	case TEOF:	case TWORD:		tokpushback++;		return simplecmd(rpp, redir);	default:		synexpect(-1);	}	/* Now check for redirection which may follow command */	while (readtoken() == TREDIR) {		*rpp = n2 = redirnode;		rpp = &n2->nfile.next;		parsefname();	}	tokpushback++;	*rpp = NULL;	if (redir) {		if (n1->type != NSUBSHELL) {			n2 = (union node *)stalloc(sizeof (struct nredir));			n2->type = NREDIR;			n2->nredir.n = n1;			n1 = n2;		}		n1->nredir.redirect = redir;	}	return n1;}STATIC union node *simplecmd(rpp, redir)	union node **rpp, *redir;	{	union node *args, **app;	union node **orig_rpp = rpp;	union node *n;	/* If we don't have any redirections already, then we must reset	   rpp to be the address of the local redir variable.  */	if (redir == 0)		rpp = &redir;	args = NULL;	app = &args;	/* We save the incoming value, because we need this for shell	   functions.  There can not be a redirect or an argument between	   the function name and the open parenthesis.  */	orig_rpp = rpp;	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();			return n;		} 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;	return n;}STATIC voidparsefname() {	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) {		if (is_digit(wordtext[0]))			n->ndup.dupfd = digit_val(wordtext[0]);		else if (wordtext[0] == '-')			n->ndup.dupfd = -1;		else			goto bad;		if (wordtext[1] != '\0') {bad:			synerror("Bad fd number");		}	} else {		n->nfile.fname = (union node *)stalloc(sizeof (struct narg));		n = n->nfile.fname;		n->type = NARG;		n->narg.next = NULL;		n->narg.text = wordtext;		n->narg.backquote = backquotelist;	}}/* * Input any here documents. */STATIC voidparseheredoc() {	struct heredoc *here;	union node *n;	while (heredoclist) {		here = heredoclist;		heredoclist = here->next;		if (needprompt) {			putprompt(ps2val());			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() {	int t;	t = readtoken();	tokpushback++;	return (t);}STATIC int xxreadtoken();STATIC intreadtoken() {	int t;#if DEBUG	int alreadyseen = tokpushback;#endif		t = xxreadtoken();	if (checkkwd) {		/*		 * eat newlines		 */		if (checkkwd == 2) {			checkkwd = 0;			while (t == TNL) {				parseheredoc();				t = xxreadtoken();			}		} else			checkkwd = 0;		/*		 * check for keywords		 */		if (t == TWORD && !quoteflag) {			register 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]));					break;				}			}		}	}#if 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

⌨️ 快捷键说明

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