📄 syn.c
字号:
/* * 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 + -