parser.c
来自「Android 一些工具」· C语言 代码 · 共 1,652 行 · 第 1/3 页
C
1,652 行
/* $NetBSD: parser.c,v 1.57 2004/06/27 10:27:57 dsl Exp $ *//*- * 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. 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. */#include <sys/cdefs.h>#ifndef lint#if 0static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95";#else__RCSID("$NetBSD: parser.c,v 1.57 2004/06/27 10:27:57 dsl Exp $");#endif#endif /* not lint */#include <stdlib.h>#include "shell.h"#include "parser.h"#include "nodes.h"#include "expand.h" /* defines rmescapes() */#include "eval.h" /* defines commandname */#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 "show.h"#ifndef SMALL#include "myhistedit.h"#endif/* * Shell command parser. */#define EOFMARKLEN 79/* values returned by readtoken */#include "token.h"#define OPENBRACE '{'#define CLOSEBRACE '}'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 */};static int noalias = 0; /* when set, don't handle aliases */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 */STATIC union node *list(int);STATIC union node *andor(void);STATIC union node *pipeline(void);STATIC union node *command(void);STATIC union node *simplecmd(union node **, union node *);STATIC union node *makename(void);STATIC void parsefname(void);STATIC void parseheredoc(void);STATIC int peektoken(void);STATIC int readtoken(void);STATIC int xxreadtoken(void);STATIC int readtoken1(int, char const *, char *, int);STATIC int noexpand(char *);STATIC void synexpect(int) __attribute__((__noreturn__));STATIC void synerror(const char *) __attribute__((__noreturn__));STATIC void setprompt(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(int interact){ int t; tokpushback = 0; 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(int nlflag){ union node *n1, *n2, *n3; int tok; checkkwd = 2; if (nlflag == 0 && tokendlist[peektoken()]) return NULL; n1 = NULL; for (;;) { n2 = andor(); tok = readtoken(); if (tok == TBACKGND) { if (n2->type == NCMD || n2->type == NPIPE) { n2->ncmd.backgnd = 1; } else if (n2->type == NREDIR) { n2->type = NBACKGND; } else { n3 = (union node *)stalloc(sizeof (struct nredir)); n3->type = NBACKGND; n3->nredir.n = n2; n3->nredir.redirect = NULL; n2 = n3; } } if (n1 == NULL) { n1 = n2; } else { n3 = (union node *)stalloc(sizeof (struct nbinary)); n3->type = NSEMI; n3->nbinary.ch1 = n1; n3->nbinary.ch2 = n2; n1 = n3; } switch (tok) { case TBACKGND: case TSEMI: tok = readtoken(); /* fall through */ case TNL: if (tok == TNL) { parseheredoc(); if (nlflag) return n1; } else { tokpushback++; } checkkwd = 2; if (tokendlist[peektoken()]) return n1; 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(void){ 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(void){ union node *n1, *n2, *pipenode; struct nodelist *lp, *prev; int negate; negate = 0; TRACE(("pipeline: entered\n")); while (readtoken() == TNOT) 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) { n2 = (union node *)stalloc(sizeof (struct nnot)); n2->type = NNOT; n2->nnot.com = n1; return n2; } else return n1;}STATIC union node *command(void){ union node *n1, *n2; union node *ap, **app; union node *cp, **cpp; union node *redir, **rpp; int t, negate = 0; checkkwd = 2; redir = NULL; n1 = NULL; rpp = &redir; /* Check for redirection which may precede command */ while (readtoken() == TREDIR) { *rpp = n2 = redirnode; rpp = &n2->nfile.next; parsefname(); } tokpushback++; while (readtoken() == TNOT) { TRACE(("command: TNOT recognized\n")); negate = !negate; } 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 { static char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'}; n2 = (union node *)stalloc(sizeof (struct narg)); n2->type = NARG; n2->narg.text = 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; noalias = 1; checkkwd = 2, readtoken(); do { *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 (checkkwd = 2, readtoken() != TPIPE) break; app = &ap->narg.next; readtoken(); } ap->narg.next = NULL; noalias = 0; if (lasttoken != TRP) { synexpect(TRP); } cp->nclist.body = list(0); checkkwd = 2; if ((t = readtoken()) != TESAC) { if (t != TENDCASE) { noalias = 0; synexpect(TENDCASE); } else { noalias = 1; checkkwd = 2; readtoken(); } } cpp = &cp->nclist.next; } while(lasttoken != TESAC); noalias = 0; *cpp = NULL; 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 TSEMI: /* * An empty command before a ; doesn't make much sense, and * should certainly be disallowed in the case of `if ;'. */ if (!redir) synexpect(-1); case TAND: case TOR: case TNL: case TEOF: case TWORD: case TRP: tokpushback++; n1 = simplecmd(rpp, redir); goto checkneg; default: synexpect(-1); /* NOTREACHED */ } /* Now check for redirection which may follow command */ while (readtoken() == TREDIR) { *rpp = n2 = redirnode; rpp = &n2->nfile.next; parsefname(); } tokpushback++; *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; }checkneg: if (negate) { n2 = (union node *)stalloc(sizeof (struct nnot)); n2->type = NNOT; n2->nnot.com = n1; return n2; } else return n1;}STATIC union node *simplecmd(union node **rpp, union node *redir){ union node *args, **app; union node **orig_rpp = rpp; union node *n = NULL, *n2; int negate = 0; /* 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; while (readtoken() == TNOT) { TRACE(("command: TNOT recognized\n"));
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?