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

📄 syn.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * shell parser (C version) */#include "sh.h"#include "c_test.h"struct nesting_state {	int	start_token;	/* token than began nesting (eg, FOR) */	int	start_line;	/* line nesting began on */};static void	yyparse		ARGS((void));static struct op *pipeline	ARGS((int cf));static struct op *andor		ARGS((void));static struct op *c_list	ARGS((int multi));static struct ioword *synio	ARGS((int cf));static void	musthave	ARGS((int c, int cf));static struct op *nested	ARGS((int type, int smark, int emark));static struct op *get_command	ARGS((int cf));static struct op *dogroup	ARGS((void));static struct op *thenpart	ARGS((void));static struct op *elsepart	ARGS((void));static struct op *caselist	ARGS((void));static struct op *casepart	ARGS((int endtok));static struct op *function_body	ARGS((char *name, int ksh_func));static char **	wordlist	ARGS((void));static struct op *block		ARGS((int type, struct op *t1, struct op *t2,				      char **wp));static struct op *newtp		ARGS((int type));static void	syntaxerr	ARGS((const char *what))						GCC_FUNC_ATTR(noreturn);static void	nesting_push ARGS((struct nesting_state *save, int tok));static void	nesting_pop ARGS((struct nesting_state *saved));static int	assign_command ARGS((char *s));static int	inalias ARGS((struct source *s));#ifdef KSHstatic int	dbtestp_isa ARGS((Test_env *te, Test_meta meta));static const char *dbtestp_getopnd ARGS((Test_env *te, Test_op op,					int do_eval));static int	dbtestp_eval ARGS((Test_env *te, Test_op op, const char *opnd1,				const char *opnd2, int do_eval));static void	dbtestp_error ARGS((Test_env *te, int offset, const char *msg));#endif /* KSH */static	struct	op	*outtree; /* yyparse output */static struct nesting_state nesting;	/* \n changed to ; */static	int	reject;		/* token(cf) gets symbol again */static	int	symbol;		/* yylex value */#define	REJECT	(reject = 1)#define	ACCEPT	(reject = 0)#define	token(cf) \	((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf)))#define	tpeek(cf) \	((reject) ? (symbol) : (REJECT, symbol = yylex(cf)))static voidyyparse(){	int c;	ACCEPT;	outtree = c_list(source->type == SSTRING);	c = tpeek(0);	if (c == 0 && !outtree)		outtree = newtp(TEOF);	else if (c != '\n' && c != 0)		syntaxerr((char *) 0);}static struct op *pipeline(cf)	int cf;{	register struct op *t, *p, *tl = NULL;	t = get_command(cf);	if (t != NULL) {		while (token(0) == '|') {			if ((p = get_command(CONTIN)) == NULL)				syntaxerr((char *) 0);			if (tl == NULL)				t = tl = block(TPIPE, t, p, NOWORDS);			else				tl = tl->right = block(TPIPE, tl->right, p, NOWORDS);		}		REJECT;	}	return (t);}static struct op *andor(){	register struct op *t, *p;	register int c;	t = pipeline(0);	if (t != NULL) {		while ((c = token(0)) == LOGAND || c == LOGOR) {			if ((p = pipeline(CONTIN)) == NULL)				syntaxerr((char *) 0);			t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);		}		REJECT;	}	return (t);}static struct op *c_list(multi)	int multi;{	register struct op *t = NULL, *p, *tl = NULL;	register int c;	int have_sep;	while (1) {		p = andor();		/* Token has always been read/rejected at this point, so		 * we don't worry about what flags to pass token()		 */		c = token(0);		have_sep = 1;		if (c == '\n' && (multi || inalias(source))) {			if (!p) /* ignore blank lines */				continue;		} else if (!p)			break;		else if (c == '&' || c == COPROC)			p = block(c == '&' ? TASYNC : TCOPROC,				  p, NOBLOCK, NOWORDS);		else if (c != ';')			have_sep = 0;		if (!t)			t = p;		else if (!tl)			t = tl = block(TLIST, t, p, NOWORDS);		else			tl = tl->right = block(TLIST, tl->right, p, NOWORDS);		if (!have_sep)			break;	}	REJECT;	return t;}static struct ioword *synio(cf)	int cf;{	register struct ioword *iop;	int ishere;	if (tpeek(cf) != REDIR)		return NULL;	ACCEPT;	iop = yylval.iop;	ishere = (iop->flag&IOTYPE) == IOHERE;	musthave(LWORD, ishere ? HEREDELIM : 0);	if (ishere) {		iop->delim = yylval.cp;		if (*ident != 0) /* unquoted */			iop->flag |= IOEVAL;		if (herep >= &heres[HERES])			yyerror("too many <<'s\n");		*herep++ = iop;	} else		iop->name = yylval.cp;	return iop;}static voidmusthave(c, cf)	int c, cf;{	if ((token(cf)) != c)		syntaxerr((char *) 0);}static struct op *nested(type, smark, emark)	int type, smark, emark;{	register struct op *t;	struct nesting_state old_nesting;	nesting_push(&old_nesting, smark);	t = c_list(TRUE);	musthave(emark, KEYWORD|ALIAS);	nesting_pop(&old_nesting);	return (block(type, t, NOBLOCK, NOWORDS));}static struct op *get_command(cf)	int cf;{	register struct op *t;	register int c, iopn = 0, syniocf;	struct ioword *iop, **iops;	XPtrV args, vars;	struct nesting_state old_nesting;	iops = (struct ioword **) alloc(sizeofN(struct ioword *, NUFILE+1),					ATEMP);	XPinit(args, 16);	XPinit(vars, 16);	syniocf = KEYWORD|ALIAS;	switch (c = token(cf|KEYWORD|ALIAS|VARASN)) {	  default:		REJECT;		afree((void*) iops, ATEMP);		XPfree(args);		XPfree(vars);		return NULL; /* empty line */	  case LWORD:	  case REDIR:		REJECT;		syniocf &= ~(KEYWORD|ALIAS);		t = newtp(TCOM);		t->lineno = source->line;		while (1) {			cf = (t->u.evalflags ? ARRAYVAR : 0)			     | (XPsize(args) == 0 ? ALIAS|VARASN : CMDWORD);			switch (tpeek(cf)) {			  case REDIR:				if (iopn >= NUFILE)					yyerror("too many redirections\n");				iops[iopn++] = synio(cf);				break;			  case LWORD:				ACCEPT;				/* the iopn == 0 and XPsize(vars) == 0 are				 * dubious but at&t ksh acts this way				 */				if (iopn == 0 && XPsize(vars) == 0				    && XPsize(args) == 0				    && assign_command(ident))					t->u.evalflags = DOVACHECK;				if ((XPsize(args) == 0 || Flag(FKEYWORD))				    && is_wdvarassign(yylval.cp))					XPput(vars, yylval.cp);				else					XPput(args, yylval.cp);				break;			  case '(':				/* Check for "> foo (echo hi)", which at&t ksh				 * allows (not POSIX, but not disallowed)				 */				afree(t, ATEMP);				if (XPsize(args) == 0 && XPsize(vars) == 0) {					ACCEPT;					goto Subshell;				}				/* Must be a function */				if (iopn != 0 || XPsize(args) != 1				    || XPsize(vars) != 0)					syntaxerr((char *) 0);				ACCEPT;				/*(*/				musthave(')', 0);				t = function_body(XPptrv(args)[0], FALSE);				goto Leave;			  default:				goto Leave;			}		}	  Leave:		break;	  Subshell:	  case '(':		t = nested(TPAREN, '(', ')');		break;	  case '{': /*}*/		t = nested(TBRACE, '{', '}');		break;#ifdef KSH	  case MDPAREN:	  {		static const char let_cmd[] = { CHAR, 'l', CHAR, 'e',						CHAR, 't', EOS };		/* Leave KEYWORD in syniocf (allow if (( 1 )) then ...) */		t = newtp(TCOM);		t->lineno = source->line;		ACCEPT;		XPput(args, wdcopy(let_cmd, ATEMP));		musthave(LWORD,LETEXPR);		XPput(args, yylval.cp);		break;	  }#endif /* KSH */#ifdef KSH	  case DBRACKET: /* [[ .. ]] */		/* Leave KEYWORD in syniocf (allow if [[ -n 1 ]] then ...) */		t = newtp(TDBRACKET);		ACCEPT;		{			Test_env te;			te.flags = TEF_DBRACKET;			te.pos.av = &args;			te.isa = dbtestp_isa;			te.getopnd = dbtestp_getopnd;			te.eval = dbtestp_eval;			te.error = dbtestp_error;			test_parse(&te);		}		break;#endif /* KSH */	  case FOR:	  case SELECT:		t = newtp((c == FOR) ? TFOR : TSELECT);		musthave(LWORD, ARRAYVAR);		if (!is_wdvarname(yylval.cp, TRUE))			yyerror("%s: bad identifier\n",				c == FOR ? "for" : "select");		t->str = str_save(ident, ATEMP);		nesting_push(&old_nesting, c);		t->vars = wordlist();		t->left = dogroup();		nesting_pop(&old_nesting);		break;	  case WHILE:	  case UNTIL:		nesting_push(&old_nesting, c);		t = newtp((c == WHILE) ? TWHILE : TUNTIL);		t->left = c_list(TRUE);		t->right = dogroup();		nesting_pop(&old_nesting);		break;	  case CASE:		t = newtp(TCASE);		musthave(LWORD, 0);		t->str = yylval.cp;		nesting_push(&old_nesting, c);		t->left = caselist();		nesting_pop(&old_nesting);		break;	  case IF:		nesting_push(&old_nesting, c);		t = newtp(TIF);		t->left = c_list(TRUE);		t->right = thenpart();		musthave(FI, KEYWORD|ALIAS);		nesting_pop(&old_nesting);		break;	  case BANG:		syniocf &= ~(KEYWORD|ALIAS);		t = pipeline(0);		if (t == (struct op *) 0)			syntaxerr((char *) 0);		t = block(TBANG, NOBLOCK, t, NOWORDS);		break;	  case TIME:		syniocf &= ~(KEYWORD|ALIAS);		t = pipeline(0);		t = block(TTIME, t, NOBLOCK, NOWORDS);		break;	  case FUNCTION:		musthave(LWORD, 0);		t = function_body(yylval.cp, TRUE);		break;	}	while ((iop = synio(syniocf)) != NULL) {		if (iopn >= NUFILE)			yyerror("too many redirections\n");		iops[iopn++] = iop;	}	if (iopn == 0) {		afree((void*) iops, ATEMP);		t->ioact = NULL;	} else {		iops[iopn++] = NULL;		iops = (struct ioword **) aresize((void*) iops,					sizeofN(struct ioword *, iopn), ATEMP);		t->ioact = iops;	}	if (t->type == TCOM || t->type == TDBRACKET) {		XPput(args, NULL);		t->args = (char **) XPclose(args);		XPput(vars, NULL);		t->vars = (char **) XPclose(vars);	} else {		XPfree(args);		XPfree(vars);	}	return t;}static struct op *dogroup(){	register int c;	register struct op *list;	c = token(CONTIN|KEYWORD|ALIAS);	/* A {...} can be used instead of do...done for for/select loops	 * but not for while/until loops - we don't need to check if it	 * is a while loop because it would have been parsed as part of	 * the conditional command list...	 */	if (c == DO)		c = DONE;	else if (c == '{')		c = '}';	else		syntaxerr((char *) 0);	list = c_list(TRUE);	musthave(c, KEYWORD|ALIAS);	return list;}static struct op *thenpart(){	register struct op *t;	musthave(THEN, KEYWORD|ALIAS);	t = newtp(0);	t->left = c_list(TRUE);	if (t->left == NULL)		syntaxerr((char *) 0);	t->right = elsepart();	return (t);}static struct op *elsepart(){	register struct op *t;	switch (token(KEYWORD|ALIAS|VARASN)) {	  case ELSE:		if ((t = c_list(TRUE)) == NULL)			syntaxerr((char *) 0);		return (t);	  case ELIF:		t = newtp(TELIF);		t->left = c_list(TRUE);		t->right = thenpart();		return (t);	  default:		REJECT;	}	return NULL;

⌨️ 快捷键说明

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