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

📄 parser.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/*- * Copyright (c) 1991, 1993 *	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	8.1 (Berkeley) 5/31/93";#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"#include "alias.h"#include "myhistedit.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 */MKINIT 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 *));STATIC void setprompt __P((int));/* * 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;	doprompt = interact;	if (doprompt)		setprompt(1);	else		setprompt(0);	needprompt = 0;	t = readtoken();	if (t == TEOF)		return NEOF;	if (t == TNL)		return NULL;	tokpushback++;	return list(1);}STATIC union node *list(nlflag) {	union node *n1, *n2, *n3;	checkkwd = 2;	if (nlflag == 0 && tokendlist[peektoken()])		return NULL;	n1 = andor();	for (;;) {		switch (readtoken()) {		case TBACKGND:			if (n1->type == NCMD || n1->type == NPIPE) {				n1->ncmd.backgnd = 1;			} else if (n1->type == NREDIR) {				n1->type = NBACKGND;			} else {				n3 = (union node *)stalloc(sizeof (struct nredir));				n3->type = NBACKGND;				n3->nredir.n = n1;				n3->nredir.redirect = NULL;				n1 = 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, *notnode;	struct nodelist *lp, *prev;	int negate = 0;	TRACE(("pipeline: entered\n"));	while (readtoken() == TNOT) {		TRACE(("pipeline: TNOT recognized\n"));		negate = !negate;	}	tokpushback++;	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++;	if (negate) {		notnode = (union node *)stalloc(sizeof (struct nnot));		notnode->type = NNOT;		notnode->nnot.com = n1;		n1 = notnode;	}	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 = ≈			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;			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;			/*			 * Newline or semicolon here is optional (but note			 * that the original Bourne shell only allowed NL).			 */			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 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++;

⌨️ 快捷键说明

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