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

📄 syn.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
}static struct op *caselist(){	register struct op *t, *tl;	int c;	c = token(CONTIN|KEYWORD|ALIAS);	/* A {...} can be used instead of in...esac for case statements */	if (c == IN)		c = ESAC;	else if (c == '{')		c = '}';	else		syntaxerr((char *) 0);	t = tl = NULL;	while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) { /* no ALIAS here */		struct op *tc = casepart(c);		if (tl == NULL)			t = tl = tc, tl->right = NULL;		else			tl->right = tc, tl = tc;	}	musthave(c, KEYWORD|ALIAS);	return (t);}static struct op *casepart(endtok)	int endtok;{	register struct op *t;	register int c;	XPtrV ptns;	XPinit(ptns, 16);	t = newtp(TPAT);	c = token(CONTIN|KEYWORD); /* no ALIAS here */	if (c != '(')		REJECT;	do {		musthave(LWORD, 0);		XPput(ptns, yylval.cp);	} while ((c = token(0)) == '|');	REJECT;	XPput(ptns, NULL);	t->vars = (char **) XPclose(ptns);	musthave(')', 0);	t->left = c_list(TRUE);	/* Note: Posix requires the ;; */	if ((tpeek(CONTIN|KEYWORD|ALIAS)) != endtok)		musthave(BREAK, CONTIN|KEYWORD|ALIAS);	return (t);}static struct op *function_body(name, ksh_func)	char *name;	int ksh_func;	/* function foo { ... } vs foo() { .. } */{	char *sname, *p;	struct op *t;	int old_func_parse;	sname = wdstrip(name);	/* Check for valid characters in name.  posix and ksh93 say only	 * allow [a-zA-Z_0-9] but this allows more as old pdksh's have	 * allowed more (the following were never allowed:	 *	nul space nl tab $ ' " \ ` ( ) & | ; = < >	 *  C_QUOTE covers all but = and adds # [ ? *)	 */	for (p = sname; *p; p++)		if (ctype(*p, C_QUOTE) || *p == '=')			yyerror("%s: invalid function name\n", sname);	t = newtp(TFUNCT);	t->str = sname;	t->u.ksh_func = ksh_func;	t->lineno = source->line;	/* Note that POSIX allows only compound statements after foo(), sh and	 * at&t ksh allow any command, go with the later since it shouldn't	 * break anything.  However, for function foo, at&t ksh only accepts	 * an open-brace.	 */	if (ksh_func) {		musthave('{', CONTIN|KEYWORD|ALIAS); /* } */		REJECT;	}	old_func_parse = e->flags & EF_FUNC_PARSE;	e->flags |= EF_FUNC_PARSE;	if ((t->left = get_command(CONTIN)) == (struct op *) 0) {		/*		 * Probably something like foo() followed by eof or ;.		 * This is accepted by sh and ksh88.		 * To make "typset -f foo" work reliably (so its output can		 * be used as input), we pretend there is a colon here.		 */		t->left = newtp(TCOM);		t->left->args = (char **) alloc(sizeof(char *) * 2, ATEMP);		t->left->args[0] = alloc(sizeof(char) * 3, ATEMP);		t->left->args[0][0] = CHAR;		t->left->args[0][1] = ':';		t->left->args[0][2] = EOS;		t->left->args[1] = (char *) 0;		t->left->vars = (char **) alloc(sizeof(char *), ATEMP);		t->left->vars[0] = (char *) 0;		t->left->lineno = 1;	}	if (!old_func_parse)		e->flags &= ~EF_FUNC_PARSE;	return t;}static char **wordlist(){	register int c;	XPtrV args;	XPinit(args, 16);	/* Posix does not do alias expansion here... */	if ((c = token(CONTIN|KEYWORD|ALIAS)) != IN) {		if (c != ';') /* non-POSIX, but at&t ksh accepts a ; here */			REJECT;		return NULL;	}	while ((c = token(0)) == LWORD)		XPput(args, yylval.cp);	if (c != '\n' && c != ';')		syntaxerr((char *) 0);	if (XPsize(args) == 0) {		XPfree(args);		return NULL;	} else {		XPput(args, NULL);		return (char **) XPclose(args);	}}/* * supporting functions */static struct op *block(type, t1, t2, wp)	int type;	struct op *t1, *t2;	char **wp;{	register struct op *t;	t = newtp(type);	t->left = t1;	t->right = t2;	t->vars = wp;	return (t);}const	struct tokeninfo {	const char *name;	short	val;	short	reserved;} tokentab[] = {	/* Reserved words */	{ "if",		IF,	TRUE },	{ "then",	THEN,	TRUE },	{ "else",	ELSE,	TRUE },	{ "elif",	ELIF,	TRUE },	{ "fi",		FI,	TRUE },	{ "case",	CASE,	TRUE },	{ "esac",	ESAC,	TRUE },	{ "for",	FOR,	TRUE },#ifdef KSH	{ "select",	SELECT,	TRUE },#endif /* KSH */	{ "while",	WHILE,	TRUE },	{ "until",	UNTIL,	TRUE },	{ "do",		DO,	TRUE },	{ "done",	DONE,	TRUE },	{ "in",		IN,	TRUE },	{ "function",	FUNCTION, TRUE },	{ "time",	TIME,	TRUE },	{ "{",		'{',	TRUE },	{ "}",		'}',	TRUE },	{ "!",		BANG,	TRUE },#ifdef KSH	{ "[[",		DBRACKET, TRUE },#endif /* KSH */	/* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */	{ "&&",		LOGAND,	FALSE },	{ "||",		LOGOR,	FALSE },	{ ";;",		BREAK,	FALSE },#ifdef KSH	{ "((",		MDPAREN, FALSE },	{ "|&",		COPROC,	FALSE },#endif /* KSH */	/* and some special cases... */	{ "newline",	'\n',	FALSE },	{ 0 }};voidinitkeywords(){	register struct tokeninfo const *tt;	register struct tbl *p;	tinit(&keywords, APERM, 32); /* must be 2^n (currently 20 keywords) */	for (tt = tokentab; tt->name; tt++) {		if (tt->reserved) {			p = tenter(&keywords, tt->name, hash(tt->name));			p->flag |= DEFINED|ISSET;			p->type = CKEYWD;			p->val.i = tt->val;		}	}}static voidsyntaxerr(what)	const char *what;{	char redir[6];	/* 2<<- is the longest redirection, I think */	const char *s;	struct tokeninfo const *tt;	int c;	if (!what)		what = "unexpected";	REJECT;	c = token(0);    Again:	switch (c) {	case 0:		if (nesting.start_token) {			c = nesting.start_token;			source->errline = nesting.start_line;			what = "unmatched";			goto Again;		}		/* don't quote the EOF */		yyerror("syntax error: unexpected EOF\n");		/*NOTREACHED*/	case LWORD:		s = snptreef((char *) 0, 32, "%S", yylval.cp);		break;	case REDIR:		s = snptreef(redir, sizeof(redir), "%R", yylval.iop);		break;	default:		for (tt = tokentab; tt->name; tt++)			if (tt->val == c)			    break;		if (tt->name)			s = tt->name;		else {			if (c > 0 && c < 256) {				redir[0] = c;				redir[1] = '\0';			} else				shf_snprintf(redir, sizeof(redir),					"?%d", c);			s = redir;		}	}	yyerror("syntax error: `%s' %s\n", s, what);}static voidnesting_push(save, tok)	struct nesting_state *save;	int tok;{	*save = nesting;	nesting.start_token = tok;	nesting.start_line = source->line;}static voidnesting_pop(saved)	struct nesting_state *saved;{	nesting = *saved;}static struct op *newtp(type)	int type;{	register struct op *t;	t = (struct op *) alloc(sizeof(*t), ATEMP);	t->type = type;	t->u.evalflags = 0;	t->args = t->vars = NULL;	t->ioact = NULL;	t->left = t->right = NULL;	t->str = NULL;	return (t);}struct op *compile(s)	Source *s;{	nesting.start_token = 0;	nesting.start_line = 0;	herep = heres;	source = s;	yyparse();	return outtree;}/* This kludge exists to take care of sh/at&t ksh oddity in which * the arguments of alias/export/readonly/typeset have no field * splitting, file globbing, or (normal) tilde expansion done. * at&t ksh seems to do something similar to this since *	$ touch a=a; typeset a=[ab]; echo "$a" *	a=[ab] *	$ x=typeset; $x a=[ab]; echo "$a" *	a=a *	$  */static intassign_command(s)	char *s;{	char c = *s;	if (Flag(FPOSIX) || !*s)		return 0;	return     (c == 'a' && strcmp(s, "alias") == 0)		|| (c == 'e' && strcmp(s, "export") == 0)		|| (c == 'r' && strcmp(s, "readonly") == 0)		|| (c == 't' && strcmp(s, "typeset") == 0);}/* Check if we are in the middle of reading an alias */static intinalias(s)	struct source *s;{	for (; s && s->type == SALIAS; s = s->next)		if (!(s->flags & SF_ALIASEND))			return 1;	return 0;}#ifdef KSH/* Order important - indexed by Test_meta values * Note that ||, &&, ( and ) can't appear in as unquoted strings * in normal shell input, so these can be interpreted unambiguously * in the evaluation pass. */static const char dbtest_or[] = { CHAR, '|', CHAR, '|', EOS };static const char dbtest_and[] = { CHAR, '&', CHAR, '&', EOS };static const char dbtest_not[] = { CHAR, '!', EOS };static const char dbtest_oparen[] = { CHAR, '(', EOS };static const char dbtest_cparen[] = { CHAR, ')', EOS };const char *const dbtest_tokens[] = {			dbtest_or, dbtest_and, dbtest_not,			dbtest_oparen, dbtest_cparen		};const char db_close[] = { CHAR, ']', CHAR, ']', EOS };const char db_lthan[] = { CHAR, '<', EOS };const char db_gthan[] = { CHAR, '>', EOS };/* Test if the current token is a whatever.  Accepts the current token if * it is.  Returns 0 if it is not, non-zero if it is (in the case of * TM_UNOP and TM_BINOP, the returned value is a Test_op). */static intdbtestp_isa(te, meta)	Test_env *te;	Test_meta meta;{	int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN));	int uqword = 0;	char *save = (char *) 0;	int ret = 0;	/* unquoted word? */	uqword = c == LWORD && *ident;	if (meta == TM_OR)		ret = c == LOGOR;	else if (meta == TM_AND)		ret = c == LOGAND;	else if (meta == TM_NOT)		ret = uqword && strcmp(yylval.cp, dbtest_tokens[(int) TM_NOT]) == 0;	else if (meta == TM_OPAREN)		ret = c == '(' /*)*/;	else if (meta == TM_CPAREN)		ret = c == /*(*/ ')';	else if (meta == TM_UNOP || meta == TM_BINOP) {		if (meta == TM_BINOP && c == REDIR		    && (yylval.iop->flag == IOREAD			|| yylval.iop->flag == IOWRITE))		{			ret = 1;			save = wdcopy(yylval.iop->flag == IOREAD ?				db_lthan : db_gthan, ATEMP);		} else if (uqword && (ret = (int) test_isop(te, meta, ident)))			save = yylval.cp;	} else /* meta == TM_END */		ret = uqword && strcmp(yylval.cp, db_close) == 0;	if (ret) {		ACCEPT;		if (meta != TM_END) {			if (!save)				save = wdcopy(dbtest_tokens[(int) meta], ATEMP);			XPput(*te->pos.av, save);		}	}	return ret;}static const char *dbtestp_getopnd(te, op, do_eval)	Test_env *te;	Test_op op;	int do_eval;{	int c = tpeek(ARRAYVAR);	if (c != LWORD)		return (const char *) 0;	ACCEPT;	XPput(*te->pos.av, yylval.cp);	return null;}static intdbtestp_eval(te, op, opnd1, opnd2, do_eval)	Test_env *te;	Test_op op;	const char *opnd1;	const char *opnd2;	int do_eval;{	return 1;}static voiddbtestp_error(te, offset, msg)	Test_env *te;	int offset;	const char *msg;{	te->flags |= TEF_ERROR;	if (offset < 0) {		REJECT;		/* Kludgy to say the least... */		symbol = LWORD;		yylval.cp = *(XPptrv(*te->pos.av) + XPsize(*te->pos.av)				+ offset);	}	syntaxerr(msg);}#endif /* KSH */

⌨️ 快捷键说明

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