📄 parser.c
字号:
*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) { setprompt(2); 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; int savecheckkwd = checkkwd; struct alias *ap;#ifdef DEBUG int alreadyseen = tokpushback;#endif top: t = xxreadtoken(); if (checkkwd) { /* * eat newlines */ if (checkkwd == 2) { checkkwd = 0; while (t == TNL) { parseheredoc(); t = xxreadtoken(); } } else checkkwd = 0; /* * check for keywords and aliases */ if (t == TWORD && !quoteflag) { register char * const *pp, *s; for (pp = (char **)parsekwd; *pp; pp++) { if (**pp == *wordtext && equal(*pp, wordtext)) { lasttoken = t = pp - parsekwd + KWDOFFSET; TRACE(("keyword %s recognized\n", tokname[t])); goto out; } } if (ap = lookupalias(wordtext, 1)) { pushstring(ap->val, strlen(ap->val), ap); checkkwd = savecheckkwd; goto top; } }out: checkkwd = 0; }#ifdef 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 * quoted. * If the token is TREDIR, then we set redirnode to a structure containing * the redirection. * In all cases, the variable startlinno is set to the number of the line * on which the token starts. * * [Change comment: here documents and internal procedures] * [Readtoken shouldn't have any arguments. Perhaps we should make the * word parsing code into a separate routine. In this case, readtoken * doesn't need to have any internal procedures, but parseword does. * We could also make parseoperator in essence the main routine, and * have parseword (readtoken1?) handle both words and redirection.] */#define RETURN(token) return lasttoken = tokenSTATIC intxxreadtoken() { register c; if (tokpushback) { tokpushback = 0; return lasttoken; } if (needprompt) { setprompt(2); needprompt = 0; } startlinno = plinno; for (;;) { /* until token or start of word found */ c = pgetc_macro(); if (c == ' ' || c == '\t') continue; /* quick check for white space first */ switch (c) { case ' ': case '\t': continue; case '#': while ((c = pgetc()) != '\n' && c != PEOF); pungetc(); continue; case '\\': if (pgetc() == '\n') { startlinno = ++plinno; if (doprompt) setprompt(2); else setprompt(0); continue; } pungetc(); goto breakloop; case '\n': plinno++; needprompt = doprompt; RETURN(TNL); case PEOF: RETURN(TEOF); case '&': if (pgetc() == '&') RETURN(TAND); pungetc(); RETURN(TBACKGND); case '|': if (pgetc() == '|') RETURN(TOR); pungetc(); RETURN(TPIPE); case ';': if (pgetc() == ';') RETURN(TENDCASE); pungetc(); RETURN(TSEMI); case '(': RETURN(TLP); case ')': RETURN(TRP); default: goto breakloop; } }breakloop: return readtoken1(c, BASESYNTAX, (char *)NULL, 0);#undef RETURN}/* * If eofmark is NULL, read a word or a redirection symbol. If eofmark * is not NULL, read a here document. In the latter case, eofmark is the * word which marks the end of the document and striptabs is true if * leading tabs should be stripped from the document. The argument firstc * is the first character of the input token or document. * * Because C does not have internal subroutines, I have simulated them * using goto's to implement the subroutine linkage. The following macros * will run code that appears at the end of readtoken1. */#define CHECKEND() {goto checkend; checkend_return:;}#define PARSEREDIR() {goto parseredir; parseredir_return:;}#define PARSESUB() {goto parsesub; parsesub_return:;}#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}#define PARSEARITH() {goto parsearith; parsearith_return:;}STATIC intreadtoken1(firstc, syntax, eofmark, striptabs) int firstc; char const *syntax; char *eofmark; int striptabs; { register c = firstc; register char *out; int len; char line[EOFMARKLEN + 1]; struct nodelist *bqlist; int quotef; int dblquote; int varnest; /* levels of variables expansion */ int arinest; /* levels of arithmetic expansion */ int parenlevel; /* levels of parens in arithmetic */ int oldstyle; char const *prevsyntax; /* syntax before arithmetic */ startlinno = plinno; dblquote = 0; if (syntax == DQSYNTAX) dblquote = 1; quotef = 0; bqlist = NULL; varnest = 0; arinest = 0; parenlevel = 0; STARTSTACKSTR(out); loop: { /* for each line, until end of word */#if ATTY if (c == '\034' && doprompt && attyset() && ! equal(termval(), "emacs")) { attyline(); if (syntax == BASESYNTAX) return readtoken(); c = pgetc(); goto loop; }#endif CHECKEND(); /* set c to PEOF if at end of here document */ for (;;) { /* until end of line or end of word */ CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ if (parsebackquote && c == '\\') { c = pgetc(); /* XXX - compat with old /bin/sh */ if (c != '\\' && c != '`' && c != '$') { pungetc(); c = '\\'; } } switch(syntax[c]) { case CNL: /* '\n' */ if (syntax == BASESYNTAX) goto endword; /* exit outer loop */ USTPUTC(c, out); plinno++; if (doprompt) setprompt(2); else setprompt(0); c = pgetc(); goto loop; /* continue outer loop */ case CWORD: USTPUTC(c, out); break; case CCTL: if (eofmark == NULL || dblquote) USTPUTC(CTLESC, out); USTPUTC(c, out); break; case CBACK: /* backslash */ c = pgetc(); if (c == PEOF) { USTPUTC('\\', out); pungetc(); } else if (c == '\n') { if (doprompt) setprompt(2); else setprompt(0); } else { if (dblquote && c != '\\' && c != '`' && c != '$' && (c != '"' || eofmark != NULL)) USTPUTC('\\', out); if (SQSYNTAX[c] == CCTL) USTPUTC(CTLESC, out); USTPUTC(c, out); quotef++; } break; case CSQUOTE: syntax = SQSYNTAX; break; case CDQUOTE: syntax = DQSYNTAX; dblquote = 1; break; case CENDQUOTE: if (eofmark) { USTPUTC(c, out); } else { if (arinest) syntax = ARISYNTAX; else syntax = BASESYNTAX; quotef++; dblquote = 0; } break; case CVAR: /* '$' */ PARSESUB(); /* parse substitution */ break; case CENDVAR: /* '}' */ if (varnest > 0) { varnest--; USTPUTC(CTLENDVAR, out); } else { USTPUTC(c, out); } break; case CLP: /* '(' in arithmetic */ parenlevel++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -