147139Sbostic /*- 247139Sbostic * Copyright (c) 1991 The Regents of the University of California. 347139Sbostic * All rights reserved. 447139Sbostic * 547139Sbostic * This code is derived from software contributed to Berkeley by 647139Sbostic * Kenneth Almquist. 747139Sbostic * 847139Sbostic * %sccs.include.redist.c% 947139Sbostic */ 1047139Sbostic 1147139Sbostic #ifndef lint 12*60296Smarc static char sccsid[] = "@(#)parser.c 5.11 (Berkeley) 05/24/93"; 1347139Sbostic #endif /* not lint */ 1447139Sbostic 1547139Sbostic #include "shell.h" 1647139Sbostic #include "parser.h" 1747139Sbostic #include "nodes.h" 1847139Sbostic #include "expand.h" /* defines rmescapes() */ 1947139Sbostic #include "redir.h" /* defines copyfd() */ 2047139Sbostic #include "syntax.h" 2147139Sbostic #include "options.h" 2247139Sbostic #include "input.h" 2347139Sbostic #include "output.h" 2447139Sbostic #include "var.h" 2547139Sbostic #include "error.h" 2647139Sbostic #include "memalloc.h" 2747139Sbostic #include "mystring.h" 2854322Smarc #include "alias.h" 2954330Smarc #include "myhistedit.h" 3047139Sbostic 3147139Sbostic 3247139Sbostic /* 3347139Sbostic * Shell command parser. 3447139Sbostic */ 3547139Sbostic 3647139Sbostic #define EOFMARKLEN 79 3747139Sbostic 3847139Sbostic /* values returned by readtoken */ 3947139Sbostic #include "token.def" 4047139Sbostic 4147139Sbostic 4247139Sbostic 4347139Sbostic struct heredoc { 4447139Sbostic struct heredoc *next; /* next here document in list */ 4547139Sbostic union node *here; /* redirection node */ 4647139Sbostic char *eofmark; /* string indicating end of input */ 4747139Sbostic int striptabs; /* if set, strip leading tabs */ 4847139Sbostic }; 4947139Sbostic 5047139Sbostic 5147139Sbostic 5247139Sbostic struct heredoc *heredoclist; /* list of here documents to read */ 5347139Sbostic int parsebackquote; /* nonzero if we are inside backquotes */ 5447139Sbostic int doprompt; /* if set, prompt the user */ 5547139Sbostic int needprompt; /* true if interactive and at start of line */ 5647139Sbostic int lasttoken; /* last token read */ 5747139Sbostic MKINIT int tokpushback; /* last token pushed back */ 5847139Sbostic char *wordtext; /* text of last word returned by readtoken */ 5954322Smarc MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ 6047139Sbostic struct nodelist *backquotelist; 6147139Sbostic union node *redirnode; 6247139Sbostic struct heredoc *heredoc; 6347139Sbostic int quoteflag; /* set if (part of) last token was quoted */ 6447139Sbostic int startlinno; /* line # where last token started */ 6547139Sbostic 6647139Sbostic 6747139Sbostic #define GDB_HACK 1 /* avoid local declarations which gdb can't handle */ 6847139Sbostic #ifdef GDB_HACK 6947139Sbostic static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'}; 7047139Sbostic static const char types[] = "}-+?="; 7147139Sbostic #endif 7247139Sbostic 7347139Sbostic 7447981Smarc STATIC union node *list __P((int)); 7547981Smarc STATIC union node *andor __P((void)); 7647981Smarc STATIC union node *pipeline __P((void)); 7747981Smarc STATIC union node *command __P((void)); 78*60296Smarc STATIC union node *simplecmd __P((union node **, union node *)); 7947981Smarc STATIC void parsefname __P((void)); 8047981Smarc STATIC void parseheredoc __P((void)); 8147981Smarc STATIC int readtoken __P((void)); 8247981Smarc STATIC int readtoken1 __P((int, char const *, char *, int)); 8347981Smarc STATIC void attyline __P((void)); 8447981Smarc STATIC int noexpand __P((char *)); 8547981Smarc STATIC void synexpect __P((int)); 8647981Smarc STATIC void synerror __P((char *)); 8754322Smarc STATIC void setprompt __P((int)); 8847139Sbostic 8947139Sbostic /* 9047139Sbostic * Read and parse a command. Returns NEOF on end of file. (NULL is a 9147139Sbostic * valid parse tree indicating a blank line.) 9247139Sbostic */ 9347139Sbostic 9447139Sbostic union node * 9547139Sbostic parsecmd(interact) { 9647139Sbostic int t; 9747139Sbostic 9847139Sbostic doprompt = interact; 9947139Sbostic if (doprompt) 10054322Smarc setprompt(1); 10154322Smarc else 10254322Smarc setprompt(0); 10347139Sbostic needprompt = 0; 10454322Smarc t = readtoken(); 10554322Smarc if (t == TEOF) 10647139Sbostic return NEOF; 10747139Sbostic if (t == TNL) 10847139Sbostic return NULL; 10947139Sbostic tokpushback++; 11047139Sbostic return list(1); 11147139Sbostic } 11247139Sbostic 11347139Sbostic 11447139Sbostic STATIC union node * 11547139Sbostic list(nlflag) { 11647139Sbostic union node *n1, *n2, *n3; 11747139Sbostic 11847981Smarc checkkwd = 2; 11947981Smarc if (nlflag == 0 && tokendlist[peektoken()]) 12047139Sbostic return NULL; 12147139Sbostic n1 = andor(); 12247139Sbostic for (;;) { 12347139Sbostic switch (readtoken()) { 12447139Sbostic case TBACKGND: 12547139Sbostic if (n1->type == NCMD || n1->type == NPIPE) { 12647139Sbostic n1->ncmd.backgnd = 1; 12747139Sbostic } else if (n1->type == NREDIR) { 12847139Sbostic n1->type = NBACKGND; 12947139Sbostic } else { 13047139Sbostic n3 = (union node *)stalloc(sizeof (struct nredir)); 13147139Sbostic n3->type = NBACKGND; 13247139Sbostic n3->nredir.n = n1; 13347139Sbostic n3->nredir.redirect = NULL; 13447139Sbostic n1 = n3; 13547139Sbostic } 13647139Sbostic goto tsemi; 13747139Sbostic case TNL: 13847139Sbostic tokpushback++; 13947139Sbostic /* fall through */ 14047139Sbostic tsemi: case TSEMI: 14147139Sbostic if (readtoken() == TNL) { 14247139Sbostic parseheredoc(); 14347139Sbostic if (nlflag) 14447139Sbostic return n1; 14547139Sbostic } else { 14647139Sbostic tokpushback++; 14747139Sbostic } 14847981Smarc checkkwd = 2; 14947981Smarc if (tokendlist[peektoken()]) 15047139Sbostic return n1; 15147139Sbostic n2 = andor(); 15247139Sbostic n3 = (union node *)stalloc(sizeof (struct nbinary)); 15347139Sbostic n3->type = NSEMI; 15447139Sbostic n3->nbinary.ch1 = n1; 15547139Sbostic n3->nbinary.ch2 = n2; 15647139Sbostic n1 = n3; 15747139Sbostic break; 15847139Sbostic case TEOF: 15947139Sbostic if (heredoclist) 16047139Sbostic parseheredoc(); 16147139Sbostic else 16247139Sbostic pungetc(); /* push back EOF on input */ 16347139Sbostic return n1; 16447139Sbostic default: 16547139Sbostic if (nlflag) 16647139Sbostic synexpect(-1); 16747139Sbostic tokpushback++; 16847139Sbostic return n1; 16947139Sbostic } 17047139Sbostic } 17147139Sbostic } 17247139Sbostic 17347139Sbostic 17447139Sbostic 17547139Sbostic STATIC union node * 17647139Sbostic andor() { 17747139Sbostic union node *n1, *n2, *n3; 17847139Sbostic int t; 17947139Sbostic 18047139Sbostic n1 = pipeline(); 18147139Sbostic for (;;) { 18247139Sbostic if ((t = readtoken()) == TAND) { 18347139Sbostic t = NAND; 18447139Sbostic } else if (t == TOR) { 18547139Sbostic t = NOR; 18647139Sbostic } else { 18747139Sbostic tokpushback++; 18847139Sbostic return n1; 18947139Sbostic } 19047139Sbostic n2 = pipeline(); 19147139Sbostic n3 = (union node *)stalloc(sizeof (struct nbinary)); 19247139Sbostic n3->type = t; 19347139Sbostic n3->nbinary.ch1 = n1; 19447139Sbostic n3->nbinary.ch2 = n2; 19547139Sbostic n1 = n3; 19647139Sbostic } 19747139Sbostic } 19847139Sbostic 19947139Sbostic 20047139Sbostic 20147139Sbostic STATIC union node * 20247139Sbostic pipeline() { 20353178Smarc union node *n1, *pipenode, *notnode; 20447139Sbostic struct nodelist *lp, *prev; 20553178Smarc int negate = 0; 20647139Sbostic 20753178Smarc TRACE(("pipeline: entered\n")); 20853178Smarc while (readtoken() == TNOT) { 20953178Smarc TRACE(("pipeline: TNOT recognized\n")); 21053178Smarc negate = !negate; 21153178Smarc } 21253178Smarc tokpushback++; 21347139Sbostic n1 = command(); 21447139Sbostic if (readtoken() == TPIPE) { 21547139Sbostic pipenode = (union node *)stalloc(sizeof (struct npipe)); 21647139Sbostic pipenode->type = NPIPE; 21747139Sbostic pipenode->npipe.backgnd = 0; 21847139Sbostic lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 21947139Sbostic pipenode->npipe.cmdlist = lp; 22047139Sbostic lp->n = n1; 22147139Sbostic do { 22247139Sbostic prev = lp; 22347139Sbostic lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 22447139Sbostic lp->n = command(); 22547139Sbostic prev->next = lp; 22647139Sbostic } while (readtoken() == TPIPE); 22747139Sbostic lp->next = NULL; 22847139Sbostic n1 = pipenode; 22947139Sbostic } 23047139Sbostic tokpushback++; 23153178Smarc if (negate) { 23253178Smarc notnode = (union node *)stalloc(sizeof (struct nnot)); 23353178Smarc notnode->type = NNOT; 23453178Smarc notnode->nnot.com = n1; 23553178Smarc n1 = notnode; 23653178Smarc } 23747139Sbostic return n1; 23847139Sbostic } 23947139Sbostic 24047139Sbostic 24147139Sbostic 24247139Sbostic STATIC union node * 24347139Sbostic command() { 24447139Sbostic union node *n1, *n2; 24547139Sbostic union node *ap, **app; 24647139Sbostic union node *cp, **cpp; 24747139Sbostic union node *redir, **rpp; 24847139Sbostic int t; 24947139Sbostic 25047981Smarc checkkwd = 2; 251*60296Smarc redir = 0; 252*60296Smarc rpp = &redir; 253*60296Smarc /* Check for redirection which may precede command */ 254*60296Smarc while (readtoken() == TREDIR) { 255*60296Smarc *rpp = n2 = redirnode; 256*60296Smarc rpp = &n2->nfile.next; 257*60296Smarc parsefname(); 258*60296Smarc } 259*60296Smarc tokpushback++; 260*60296Smarc 26147139Sbostic switch (readtoken()) { 26247139Sbostic case TIF: 26347139Sbostic n1 = (union node *)stalloc(sizeof (struct nif)); 26447139Sbostic n1->type = NIF; 26547139Sbostic n1->nif.test = list(0); 26647139Sbostic if (readtoken() != TTHEN) 26747139Sbostic synexpect(TTHEN); 26847139Sbostic n1->nif.ifpart = list(0); 26947139Sbostic n2 = n1; 27047139Sbostic while (readtoken() == TELIF) { 27147139Sbostic n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 27247139Sbostic n2 = n2->nif.elsepart; 27347139Sbostic n2->type = NIF; 27447139Sbostic n2->nif.test = list(0); 27547139Sbostic if (readtoken() != TTHEN) 27647139Sbostic synexpect(TTHEN); 27747139Sbostic n2->nif.ifpart = list(0); 27847139Sbostic } 27947139Sbostic if (lasttoken == TELSE) 28047139Sbostic n2->nif.elsepart = list(0); 28147139Sbostic else { 28247139Sbostic n2->nif.elsepart = NULL; 28347139Sbostic tokpushback++; 28447139Sbostic } 28547139Sbostic if (readtoken() != TFI) 28647139Sbostic synexpect(TFI); 28747981Smarc checkkwd = 1; 28847139Sbostic break; 28947139Sbostic case TWHILE: 29047981Smarc case TUNTIL: { 29147981Smarc int got; 29247139Sbostic n1 = (union node *)stalloc(sizeof (struct nbinary)); 29347139Sbostic n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 29447139Sbostic n1->nbinary.ch1 = list(0); 29547981Smarc if ((got=readtoken()) != TDO) { 29647981Smarc TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 29747139Sbostic synexpect(TDO); 29847981Smarc } 29947139Sbostic n1->nbinary.ch2 = list(0); 30047139Sbostic if (readtoken() != TDONE) 30147139Sbostic synexpect(TDONE); 30247981Smarc checkkwd = 1; 30347139Sbostic break; 30447981Smarc } 30547139Sbostic case TFOR: 30647139Sbostic if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 30747139Sbostic synerror("Bad for loop variable"); 30847139Sbostic n1 = (union node *)stalloc(sizeof (struct nfor)); 30947139Sbostic n1->type = NFOR; 31047139Sbostic n1->nfor.var = wordtext; 31147139Sbostic if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { 31247139Sbostic app = ≈ 31347139Sbostic while (readtoken() == TWORD) { 31447139Sbostic n2 = (union node *)stalloc(sizeof (struct narg)); 31547139Sbostic n2->type = NARG; 31647139Sbostic n2->narg.text = wordtext; 31747139Sbostic n2->narg.backquote = backquotelist; 31847139Sbostic *app = n2; 31947139Sbostic app = &n2->narg.next; 32047139Sbostic } 32147139Sbostic *app = NULL; 32247139Sbostic n1->nfor.args = ap; 32359178Storek if (lasttoken != TNL && lasttoken != TSEMI) 32459178Storek synexpect(-1); 32547139Sbostic } else { 32647139Sbostic #ifndef GDB_HACK 32747139Sbostic static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, 32847139Sbostic '@', '=', '\0'}; 32947139Sbostic #endif 33047139Sbostic n2 = (union node *)stalloc(sizeof (struct narg)); 33147139Sbostic n2->type = NARG; 33247139Sbostic n2->narg.text = (char *)argvars; 33347139Sbostic n2->narg.backquote = NULL; 33447139Sbostic n2->narg.next = NULL; 33547139Sbostic n1->nfor.args = n2; 33659178Storek /* 33759178Storek * Newline or semicolon here is optional (but note 33859178Storek * that the original Bourne shell only allowed NL). 33959178Storek */ 34059178Storek if (lasttoken != TNL && lasttoken != TSEMI) 34159178Storek tokpushback++; 34247139Sbostic } 34347981Smarc checkkwd = 2; 34447139Sbostic if ((t = readtoken()) == TDO) 34547139Sbostic t = TDONE; 34647139Sbostic else if (t == TBEGIN) 34747139Sbostic t = TEND; 34847139Sbostic else 34947139Sbostic synexpect(-1); 35047139Sbostic n1->nfor.body = list(0); 35147139Sbostic if (readtoken() != t) 35247139Sbostic synexpect(t); 35347981Smarc checkkwd = 1; 35447139Sbostic break; 35547139Sbostic case TCASE: 35647139Sbostic n1 = (union node *)stalloc(sizeof (struct ncase)); 35747139Sbostic n1->type = NCASE; 35847139Sbostic if (readtoken() != TWORD) 35947139Sbostic synexpect(TWORD); 36047139Sbostic n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); 36147139Sbostic n2->type = NARG; 36247139Sbostic n2->narg.text = wordtext; 36347139Sbostic n2->narg.backquote = backquotelist; 36447139Sbostic n2->narg.next = NULL; 36547139Sbostic while (readtoken() == TNL); 36647139Sbostic if (lasttoken != TWORD || ! equal(wordtext, "in")) 36747139Sbostic synerror("expecting \"in\""); 36847139Sbostic cpp = &n1->ncase.cases; 36947981Smarc while (checkkwd = 2, readtoken() == TWORD) { 37047139Sbostic *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 37147139Sbostic cp->type = NCLIST; 37247139Sbostic app = &cp->nclist.pattern; 37347139Sbostic for (;;) { 37447139Sbostic *app = ap = (union node *)stalloc(sizeof (struct narg)); 37547139Sbostic ap->type = NARG; 37647139Sbostic ap->narg.text = wordtext; 37747139Sbostic ap->narg.backquote = backquotelist; 37847139Sbostic if (readtoken() != TPIPE) 37947139Sbostic break; 38047139Sbostic app = &ap->narg.next; 38147139Sbostic if (readtoken() != TWORD) 38247139Sbostic synexpect(TWORD); 38347139Sbostic } 38447139Sbostic ap->narg.next = NULL; 38547139Sbostic if (lasttoken != TRP) 38647139Sbostic synexpect(TRP); 38747139Sbostic cp->nclist.body = list(0); 38847139Sbostic if ((t = readtoken()) == TESAC) 38947139Sbostic tokpushback++; 39047139Sbostic else if (t != TENDCASE) 39147139Sbostic synexpect(TENDCASE); 39247139Sbostic cpp = &cp->nclist.next; 39347139Sbostic } 39447139Sbostic *cpp = NULL; 39547139Sbostic if (lasttoken != TESAC) 39647139Sbostic synexpect(TESAC); 39747981Smarc checkkwd = 1; 39847139Sbostic break; 39947139Sbostic case TLP: 40047139Sbostic n1 = (union node *)stalloc(sizeof (struct nredir)); 40147139Sbostic n1->type = NSUBSHELL; 40247139Sbostic n1->nredir.n = list(0); 40347139Sbostic n1->nredir.redirect = NULL; 40447139Sbostic if (readtoken() != TRP) 40547139Sbostic synexpect(TRP); 40647981Smarc checkkwd = 1; 40747139Sbostic break; 40847139Sbostic case TBEGIN: 40947139Sbostic n1 = list(0); 41047139Sbostic if (readtoken() != TEND) 41147139Sbostic synexpect(TEND); 41247981Smarc checkkwd = 1; 41347139Sbostic break; 414*60296Smarc /* Handle an empty command like other simple commands. */ 415*60296Smarc case TNL: 41647139Sbostic case TWORD: 41747139Sbostic tokpushback++; 418*60296Smarc return simplecmd(rpp, redir); 41947139Sbostic default: 42047139Sbostic synexpect(-1); 42147139Sbostic } 42247139Sbostic 42347139Sbostic /* Now check for redirection which may follow command */ 42447139Sbostic while (readtoken() == TREDIR) { 42547139Sbostic *rpp = n2 = redirnode; 42647139Sbostic rpp = &n2->nfile.next; 42747139Sbostic parsefname(); 42847139Sbostic } 42947139Sbostic tokpushback++; 43047139Sbostic *rpp = NULL; 43147139Sbostic if (redir) { 43247139Sbostic if (n1->type != NSUBSHELL) { 43347139Sbostic n2 = (union node *)stalloc(sizeof (struct nredir)); 43447139Sbostic n2->type = NREDIR; 43547139Sbostic n2->nredir.n = n1; 43647139Sbostic n1 = n2; 43747139Sbostic } 43847139Sbostic n1->nredir.redirect = redir; 43947139Sbostic } 44047139Sbostic return n1; 44147139Sbostic } 44247139Sbostic 44347139Sbostic 44447139Sbostic STATIC union node * 445*60296Smarc simplecmd(rpp, redir) 446*60296Smarc union node **rpp, *redir; 447*60296Smarc { 44847139Sbostic union node *args, **app; 449*60296Smarc union node **orig_rpp = rpp; 45047139Sbostic union node *n; 45147139Sbostic 452*60296Smarc /* If we don't have any redirections already, then we must reset */ 453*60296Smarc /* rpp to be the address of the local redir variable. */ 454*60296Smarc if (redir == 0) 455*60296Smarc rpp = &redir; 456*60296Smarc 45747139Sbostic args = NULL; 45847139Sbostic app = &args; 459*60296Smarc /* 460*60296Smarc * We save the incoming value, because we need this for shell 461*60296Smarc * functions. There can not be a redirect or an argument between 462*60296Smarc * the function name and the open parenthesis. 463*60296Smarc */ 464*60296Smarc orig_rpp = rpp; 465*60296Smarc 46647139Sbostic for (;;) { 46747139Sbostic if (readtoken() == TWORD) { 46847139Sbostic n = (union node *)stalloc(sizeof (struct narg)); 46947139Sbostic n->type = NARG; 47047139Sbostic n->narg.text = wordtext; 47147139Sbostic n->narg.backquote = backquotelist; 47247139Sbostic *app = n; 47347139Sbostic app = &n->narg.next; 47447139Sbostic } else if (lasttoken == TREDIR) { 47547139Sbostic *rpp = n = redirnode; 47647139Sbostic rpp = &n->nfile.next; 47747139Sbostic parsefname(); /* read name of redirection file */ 47847139Sbostic } else if (lasttoken == TLP && app == &args->narg.next 479*60296Smarc && rpp == orig_rpp) { 48047139Sbostic /* We have a function */ 48147139Sbostic if (readtoken() != TRP) 48247139Sbostic synexpect(TRP); 48347300Smarc #ifdef notdef 48447139Sbostic if (! goodname(n->narg.text)) 48547139Sbostic synerror("Bad function name"); 48647300Smarc #endif 48747139Sbostic n->type = NDEFUN; 48847139Sbostic n->narg.next = command(); 48947139Sbostic return n; 49047139Sbostic } else { 49147139Sbostic tokpushback++; 49247139Sbostic break; 49347139Sbostic } 49447139Sbostic } 49547139Sbostic *app = NULL; 49647139Sbostic *rpp = NULL; 49747139Sbostic n = (union node *)stalloc(sizeof (struct ncmd)); 49847139Sbostic n->type = NCMD; 49947139Sbostic n->ncmd.backgnd = 0; 50047139Sbostic n->ncmd.args = args; 50147139Sbostic n->ncmd.redirect = redir; 50247139Sbostic return n; 50347139Sbostic } 50447139Sbostic 50547139Sbostic 50647139Sbostic STATIC void 50747139Sbostic parsefname() { 50847139Sbostic union node *n = redirnode; 50947139Sbostic 51047139Sbostic if (readtoken() != TWORD) 51147139Sbostic synexpect(-1); 51247139Sbostic if (n->type == NHERE) { 51347139Sbostic struct heredoc *here = heredoc; 51447139Sbostic struct heredoc *p; 51547139Sbostic int i; 51647139Sbostic 51747139Sbostic if (quoteflag == 0) 51847139Sbostic n->type = NXHERE; 51947139Sbostic TRACE(("Here document %d\n", n->type)); 52047139Sbostic if (here->striptabs) { 52147139Sbostic while (*wordtext == '\t') 52247139Sbostic wordtext++; 52347139Sbostic } 52447139Sbostic if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 52547139Sbostic synerror("Illegal eof marker for << redirection"); 52647139Sbostic rmescapes(wordtext); 52747139Sbostic here->eofmark = wordtext; 52847139Sbostic here->next = NULL; 52947139Sbostic if (heredoclist == NULL) 53047139Sbostic heredoclist = here; 53147139Sbostic else { 53247139Sbostic for (p = heredoclist ; p->next ; p = p->next); 53347139Sbostic p->next = here; 53447139Sbostic } 53547139Sbostic } else if (n->type == NTOFD || n->type == NFROMFD) { 53647139Sbostic if (is_digit(wordtext[0])) 53747139Sbostic n->ndup.dupfd = digit_val(wordtext[0]); 53847139Sbostic else if (wordtext[0] == '-') 53947139Sbostic n->ndup.dupfd = -1; 54047139Sbostic else 54147139Sbostic goto bad; 54247139Sbostic if (wordtext[1] != '\0') { 54347139Sbostic bad: 54447139Sbostic synerror("Bad fd number"); 54547139Sbostic } 54647139Sbostic } else { 54747139Sbostic n->nfile.fname = (union node *)stalloc(sizeof (struct narg)); 54847139Sbostic n = n->nfile.fname; 54947139Sbostic n->type = NARG; 55047139Sbostic n->narg.next = NULL; 55147139Sbostic n->narg.text = wordtext; 55247139Sbostic n->narg.backquote = backquotelist; 55347139Sbostic } 55447139Sbostic } 55547139Sbostic 55647139Sbostic 55747139Sbostic /* 55847139Sbostic * Input any here documents. 55947139Sbostic */ 56047139Sbostic 56147139Sbostic STATIC void 56247139Sbostic parseheredoc() { 56347139Sbostic struct heredoc *here; 56447139Sbostic union node *n; 56547139Sbostic 56647139Sbostic while (heredoclist) { 56747139Sbostic here = heredoclist; 56847139Sbostic heredoclist = here->next; 56947139Sbostic if (needprompt) { 57054322Smarc setprompt(2); 57147139Sbostic needprompt = 0; 57247139Sbostic } 57347139Sbostic readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 57447139Sbostic here->eofmark, here->striptabs); 57547139Sbostic n = (union node *)stalloc(sizeof (struct narg)); 57647139Sbostic n->narg.type = NARG; 57747139Sbostic n->narg.next = NULL; 57847139Sbostic n->narg.text = wordtext; 57947139Sbostic n->narg.backquote = backquotelist; 58047139Sbostic here->here->nhere.doc = n; 58147139Sbostic } 58247139Sbostic } 58347139Sbostic 58447981Smarc STATIC int 58547981Smarc peektoken() { 58647139Sbostic int t; 58747139Sbostic 58847981Smarc t = readtoken(); 58947139Sbostic tokpushback++; 59047981Smarc return (t); 59147139Sbostic } 59247139Sbostic 59347139Sbostic STATIC int xxreadtoken(); 59447139Sbostic 59547139Sbostic STATIC int 59647139Sbostic readtoken() { 59747139Sbostic int t; 59854322Smarc int savecheckkwd = checkkwd; 59954322Smarc struct alias *ap; 60047981Smarc #ifdef DEBUG 60147981Smarc int alreadyseen = tokpushback; 60247981Smarc #endif 60347981Smarc 60454322Smarc top: 60547981Smarc t = xxreadtoken(); 60647139Sbostic 60747981Smarc if (checkkwd) { 60847981Smarc /* 60947981Smarc * eat newlines 61047981Smarc */ 61147981Smarc if (checkkwd == 2) { 61247981Smarc checkkwd = 0; 61347981Smarc while (t == TNL) { 61447981Smarc parseheredoc(); 61547981Smarc t = xxreadtoken(); 61647981Smarc } 61747981Smarc } else 61847981Smarc checkkwd = 0; 61947981Smarc /* 62054322Smarc * check for keywords and aliases 62147981Smarc */ 62247981Smarc if (t == TWORD && !quoteflag) { 62354322Smarc register char * const *pp, *s; 62447981Smarc 625*60296Smarc for (pp = (char **)parsekwd; *pp; pp++) { 62647981Smarc if (**pp == *wordtext && equal(*pp, wordtext)) { 62747981Smarc lasttoken = t = pp - parsekwd + KWDOFFSET; 62847981Smarc TRACE(("keyword %s recognized\n", tokname[t])); 62954322Smarc goto out; 63047981Smarc } 63147981Smarc } 63254322Smarc if (ap = lookupalias(wordtext, 1)) { 63354322Smarc pushstring(ap->val, strlen(ap->val), ap); 63454322Smarc checkkwd = savecheckkwd; 63554322Smarc goto top; 63654322Smarc } 63747981Smarc } 63854322Smarc out: 63954322Smarc checkkwd = 0; 64047139Sbostic } 64147981Smarc #ifdef DEBUG 64247981Smarc if (!alreadyseen) 64347981Smarc TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 64447981Smarc else 64547981Smarc TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 64647981Smarc #endif 64747981Smarc return (t); 64847139Sbostic } 64947139Sbostic 65047139Sbostic 65147139Sbostic /* 65247139Sbostic * Read the next input token. 65347139Sbostic * If the token is a word, we set backquotelist to the list of cmds in 65447139Sbostic * backquotes. We set quoteflag to true if any part of the word was 65547139Sbostic * quoted. 65647139Sbostic * If the token is TREDIR, then we set redirnode to a structure containing 65747139Sbostic * the redirection. 65847139Sbostic * In all cases, the variable startlinno is set to the number of the line 65947139Sbostic * on which the token starts. 66047139Sbostic * 66147139Sbostic * [Change comment: here documents and internal procedures] 66247139Sbostic * [Readtoken shouldn't have any arguments. Perhaps we should make the 66347139Sbostic * word parsing code into a separate routine. In this case, readtoken 66447139Sbostic * doesn't need to have any internal procedures, but parseword does. 66547139Sbostic * We could also make parseoperator in essence the main routine, and 66647139Sbostic * have parseword (readtoken1?) handle both words and redirection.] 66747139Sbostic */ 66847139Sbostic 66947139Sbostic #define RETURN(token) return lasttoken = token 67047139Sbostic 67147139Sbostic STATIC int 67247139Sbostic xxreadtoken() { 67347139Sbostic register c; 67447139Sbostic 67547139Sbostic if (tokpushback) { 67647139Sbostic tokpushback = 0; 67747139Sbostic return lasttoken; 67847139Sbostic } 67947139Sbostic if (needprompt) { 68054322Smarc setprompt(2); 68147139Sbostic needprompt = 0; 68247139Sbostic } 68347139Sbostic startlinno = plinno; 68447139Sbostic for (;;) { /* until token or start of word found */ 68547139Sbostic c = pgetc_macro(); 68647139Sbostic if (c == ' ' || c == '\t') 68747139Sbostic continue; /* quick check for white space first */ 68847139Sbostic switch (c) { 68947139Sbostic case ' ': case '\t': 69047139Sbostic continue; 69147139Sbostic case '#': 69247139Sbostic while ((c = pgetc()) != '\n' && c != PEOF); 69347139Sbostic pungetc(); 69447139Sbostic continue; 69547139Sbostic case '\\': 69647139Sbostic if (pgetc() == '\n') { 69747139Sbostic startlinno = ++plinno; 69847139Sbostic if (doprompt) 69954322Smarc setprompt(2); 70054322Smarc else 70154322Smarc setprompt(0); 70247139Sbostic continue; 70347139Sbostic } 70447139Sbostic pungetc(); 70547139Sbostic goto breakloop; 70647139Sbostic case '\n': 70747139Sbostic plinno++; 70847139Sbostic needprompt = doprompt; 70947139Sbostic RETURN(TNL); 71047139Sbostic case PEOF: 71147139Sbostic RETURN(TEOF); 71247139Sbostic case '&': 71347139Sbostic if (pgetc() == '&') 71447139Sbostic RETURN(TAND); 71547139Sbostic pungetc(); 71647139Sbostic RETURN(TBACKGND); 71747139Sbostic case '|': 71847139Sbostic if (pgetc() == '|') 71947139Sbostic RETURN(TOR); 72047139Sbostic pungetc(); 72147139Sbostic RETURN(TPIPE); 72247139Sbostic case ';': 72347139Sbostic if (pgetc() == ';') 72447139Sbostic RETURN(TENDCASE); 72547139Sbostic pungetc(); 72647139Sbostic RETURN(TSEMI); 72747139Sbostic case '(': 72847139Sbostic RETURN(TLP); 72947139Sbostic case ')': 73047139Sbostic RETURN(TRP); 73147139Sbostic default: 73247139Sbostic goto breakloop; 73347139Sbostic } 73447139Sbostic } 73547139Sbostic breakloop: 73647139Sbostic return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 73747139Sbostic #undef RETURN 73847139Sbostic } 73947139Sbostic 74047139Sbostic 74147139Sbostic 74247139Sbostic /* 74347139Sbostic * If eofmark is NULL, read a word or a redirection symbol. If eofmark 74447139Sbostic * is not NULL, read a here document. In the latter case, eofmark is the 74547139Sbostic * word which marks the end of the document and striptabs is true if 74647139Sbostic * leading tabs should be stripped from the document. The argument firstc 74747139Sbostic * is the first character of the input token or document. 74847139Sbostic * 74947139Sbostic * Because C does not have internal subroutines, I have simulated them 75047139Sbostic * using goto's to implement the subroutine linkage. The following macros 75147139Sbostic * will run code that appears at the end of readtoken1. 75247139Sbostic */ 75347139Sbostic 75447139Sbostic #define CHECKEND() {goto checkend; checkend_return:;} 75547139Sbostic #define PARSEREDIR() {goto parseredir; parseredir_return:;} 75647139Sbostic #define PARSESUB() {goto parsesub; parsesub_return:;} 75747139Sbostic #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} 75847139Sbostic #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 75953302Smarc #define PARSEARITH() {goto parsearith; parsearith_return:;} 76047139Sbostic 76147139Sbostic STATIC int 76247139Sbostic readtoken1(firstc, syntax, eofmark, striptabs) 76347139Sbostic int firstc; 76447139Sbostic char const *syntax; 76547139Sbostic char *eofmark; 76647139Sbostic int striptabs; 76747139Sbostic { 76847139Sbostic register c = firstc; 76947139Sbostic register char *out; 77047139Sbostic int len; 77147139Sbostic char line[EOFMARKLEN + 1]; 77247139Sbostic struct nodelist *bqlist; 77347139Sbostic int quotef; 77447139Sbostic int dblquote; 77553302Smarc int varnest; /* levels of variables expansion */ 77653302Smarc int arinest; /* levels of arithmetic expansion */ 77753302Smarc int parenlevel; /* levels of parens in arithmetic */ 77847139Sbostic int oldstyle; 77953302Smarc char const *prevsyntax; /* syntax before arithmetic */ 78047139Sbostic 78147139Sbostic startlinno = plinno; 78247139Sbostic dblquote = 0; 78347139Sbostic if (syntax == DQSYNTAX) 78447139Sbostic dblquote = 1; 78547139Sbostic quotef = 0; 78647139Sbostic bqlist = NULL; 78747139Sbostic varnest = 0; 78853302Smarc arinest = 0; 78953302Smarc parenlevel = 0; 79053302Smarc 79147139Sbostic STARTSTACKSTR(out); 79247139Sbostic loop: { /* for each line, until end of word */ 79347139Sbostic #if ATTY 79447139Sbostic if (c == '\034' && doprompt 79547139Sbostic && attyset() && ! equal(termval(), "emacs")) { 79647139Sbostic attyline(); 79747139Sbostic if (syntax == BASESYNTAX) 79847139Sbostic return readtoken(); 79947139Sbostic c = pgetc(); 80047139Sbostic goto loop; 80147139Sbostic } 80247139Sbostic #endif 80347139Sbostic CHECKEND(); /* set c to PEOF if at end of here document */ 80447139Sbostic for (;;) { /* until end of line or end of word */ 80547139Sbostic CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ 80659177Smarc if (parsebackquote && c == '\\') { 80758381Smarc c = pgetc(); /* XXX - compat with old /bin/sh */ 80859177Smarc if (c != '\\' && c != '`' && c != '$') { 80959177Smarc pungetc(); 81059177Smarc c = '\\'; 81159177Smarc } 81259177Smarc } 81347139Sbostic switch(syntax[c]) { 81447139Sbostic case CNL: /* '\n' */ 81547139Sbostic if (syntax == BASESYNTAX) 81647139Sbostic goto endword; /* exit outer loop */ 81747139Sbostic USTPUTC(c, out); 81847139Sbostic plinno++; 81954322Smarc if (doprompt) 82054322Smarc setprompt(2); 82154322Smarc else 82254322Smarc setprompt(0); 82347139Sbostic c = pgetc(); 82447139Sbostic goto loop; /* continue outer loop */ 82547139Sbostic case CWORD: 82647139Sbostic USTPUTC(c, out); 82747139Sbostic break; 82847139Sbostic case CCTL: 82947139Sbostic if (eofmark == NULL || dblquote) 83047139Sbostic USTPUTC(CTLESC, out); 83147139Sbostic USTPUTC(c, out); 83247139Sbostic break; 83347139Sbostic case CBACK: /* backslash */ 83447139Sbostic c = pgetc(); 83547139Sbostic if (c == PEOF) { 83647139Sbostic USTPUTC('\\', out); 83747139Sbostic pungetc(); 83847139Sbostic } else if (c == '\n') { 83947139Sbostic if (doprompt) 84054322Smarc setprompt(2); 84154322Smarc else 84254322Smarc setprompt(0); 84347139Sbostic } else { 84447139Sbostic if (dblquote && c != '\\' && c != '`' && c != '$' 84547139Sbostic && (c != '"' || eofmark != NULL)) 84647139Sbostic USTPUTC('\\', out); 84747139Sbostic if (SQSYNTAX[c] == CCTL) 84847139Sbostic USTPUTC(CTLESC, out); 84947139Sbostic USTPUTC(c, out); 85047139Sbostic quotef++; 85147139Sbostic } 85247139Sbostic break; 85347139Sbostic case CSQUOTE: 85447139Sbostic syntax = SQSYNTAX; 85547139Sbostic break; 85647139Sbostic case CDQUOTE: 85747139Sbostic syntax = DQSYNTAX; 85847139Sbostic dblquote = 1; 85947139Sbostic break; 86047139Sbostic case CENDQUOTE: 86147139Sbostic if (eofmark) { 86247139Sbostic USTPUTC(c, out); 86347139Sbostic } else { 86453302Smarc if (arinest) 86553302Smarc syntax = ARISYNTAX; 86653302Smarc else 86753302Smarc syntax = BASESYNTAX; 86847139Sbostic quotef++; 86947139Sbostic dblquote = 0; 87047139Sbostic } 87147139Sbostic break; 87247139Sbostic case CVAR: /* '$' */ 87347139Sbostic PARSESUB(); /* parse substitution */ 87447139Sbostic break; 87547139Sbostic case CENDVAR: /* '}' */ 87647139Sbostic if (varnest > 0) { 87747139Sbostic varnest--; 87847139Sbostic USTPUTC(CTLENDVAR, out); 87947139Sbostic } else { 88047139Sbostic USTPUTC(c, out); 88147139Sbostic } 88247139Sbostic break; 88353302Smarc case CLP: /* '(' in arithmetic */ 88453302Smarc parenlevel++; 88553302Smarc USTPUTC(c, out); 88653302Smarc break; 88753302Smarc case CRP: /* ')' in arithmetic */ 88853302Smarc if (parenlevel > 0) { 88953302Smarc USTPUTC(c, out); 89053302Smarc --parenlevel; 89153302Smarc } else { 89253302Smarc if (pgetc() == ')') { 89353302Smarc if (--arinest == 0) { 89453302Smarc USTPUTC(CTLENDARI, out); 89553302Smarc syntax = prevsyntax; 89653302Smarc } else 89753302Smarc USTPUTC(')', out); 89853302Smarc } else { 89953302Smarc /* 90053302Smarc * unbalanced parens 90153302Smarc * (don't 2nd guess - no error) 90253302Smarc */ 90353302Smarc pungetc(); 90453302Smarc USTPUTC(')', out); 90553302Smarc } 90653302Smarc } 90753302Smarc break; 90847139Sbostic case CBQUOTE: /* '`' */ 90947139Sbostic PARSEBACKQOLD(); 91047139Sbostic break; 91147139Sbostic case CEOF: 91247139Sbostic goto endword; /* exit outer loop */ 91347139Sbostic default: 91447139Sbostic if (varnest == 0) 91547139Sbostic goto endword; /* exit outer loop */ 91647139Sbostic USTPUTC(c, out); 91747139Sbostic } 91847139Sbostic c = pgetc_macro(); 91947139Sbostic } 92047139Sbostic } 92147139Sbostic endword: 92253302Smarc if (syntax == ARISYNTAX) 92353302Smarc synerror("Missing '))'"); 924*60296Smarc if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) 92547139Sbostic synerror("Unterminated quoted string"); 92647139Sbostic if (varnest != 0) { 92747139Sbostic startlinno = plinno; 92847139Sbostic synerror("Missing '}'"); 92947139Sbostic } 93047139Sbostic USTPUTC('\0', out); 93147139Sbostic len = out - stackblock(); 93247139Sbostic out = stackblock(); 93347139Sbostic if (eofmark == NULL) { 93447139Sbostic if ((c == '>' || c == '<') 93547139Sbostic && quotef == 0 93647139Sbostic && len <= 2 93747139Sbostic && (*out == '\0' || is_digit(*out))) { 93847139Sbostic PARSEREDIR(); 93947139Sbostic return lasttoken = TREDIR; 94047139Sbostic } else { 94147139Sbostic pungetc(); 94247139Sbostic } 94347139Sbostic } 94447139Sbostic quoteflag = quotef; 94547139Sbostic backquotelist = bqlist; 94647139Sbostic grabstackblock(len); 94747139Sbostic wordtext = out; 94847139Sbostic return lasttoken = TWORD; 94947139Sbostic /* end of readtoken routine */ 95047139Sbostic 95147139Sbostic 95247139Sbostic 95347139Sbostic /* 95447139Sbostic * Check to see whether we are at the end of the here document. When this 95547139Sbostic * is called, c is set to the first character of the next input line. If 95647139Sbostic * we are at the end of the here document, this routine sets the c to PEOF. 95747139Sbostic */ 95847139Sbostic 95947139Sbostic checkend: { 96047139Sbostic if (eofmark) { 96147139Sbostic if (striptabs) { 96247139Sbostic while (c == '\t') 96347139Sbostic c = pgetc(); 96447139Sbostic } 96547139Sbostic if (c == *eofmark) { 96647139Sbostic if (pfgets(line, sizeof line) != NULL) { 96747139Sbostic register char *p, *q; 96847139Sbostic 96947139Sbostic p = line; 97047139Sbostic for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); 97147139Sbostic if (*p == '\n' && *q == '\0') { 97247139Sbostic c = PEOF; 97347139Sbostic plinno++; 97447139Sbostic needprompt = doprompt; 97547139Sbostic } else { 97654322Smarc pushstring(line, strlen(line), NULL); 97747139Sbostic } 97847139Sbostic } 97947139Sbostic } 98047139Sbostic } 98147139Sbostic goto checkend_return; 98247139Sbostic } 98347139Sbostic 98447139Sbostic 98547139Sbostic /* 98647139Sbostic * Parse a redirection operator. The variable "out" points to a string 98747139Sbostic * specifying the fd to be redirected. The variable "c" contains the 98847139Sbostic * first character of the redirection operator. 98947139Sbostic */ 99047139Sbostic 99147139Sbostic parseredir: { 99247139Sbostic char fd = *out; 99347139Sbostic union node *np; 99447139Sbostic 99547139Sbostic np = (union node *)stalloc(sizeof (struct nfile)); 99647139Sbostic if (c == '>') { 99747139Sbostic np->nfile.fd = 1; 99847139Sbostic c = pgetc(); 99947139Sbostic if (c == '>') 100047139Sbostic np->type = NAPPEND; 100147139Sbostic else if (c == '&') 100247139Sbostic np->type = NTOFD; 100347139Sbostic else { 100447139Sbostic np->type = NTO; 100547139Sbostic pungetc(); 100647139Sbostic } 100747139Sbostic } else { /* c == '<' */ 100847139Sbostic np->nfile.fd = 0; 100947139Sbostic c = pgetc(); 101047139Sbostic if (c == '<') { 101147139Sbostic if (sizeof (struct nfile) != sizeof (struct nhere)) { 101247139Sbostic np = (union node *)stalloc(sizeof (struct nhere)); 101347139Sbostic np->nfile.fd = 0; 101447139Sbostic } 101547139Sbostic np->type = NHERE; 101647139Sbostic heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); 101747139Sbostic heredoc->here = np; 101847139Sbostic if ((c = pgetc()) == '-') { 101947139Sbostic heredoc->striptabs = 1; 102047139Sbostic } else { 102147139Sbostic heredoc->striptabs = 0; 102247139Sbostic pungetc(); 102347139Sbostic } 102447139Sbostic } else if (c == '&') 102547139Sbostic np->type = NFROMFD; 102647139Sbostic else { 102747139Sbostic np->type = NFROM; 102847139Sbostic pungetc(); 102947139Sbostic } 103047139Sbostic } 103147139Sbostic if (fd != '\0') 103247139Sbostic np->nfile.fd = digit_val(fd); 103347139Sbostic redirnode = np; 103447139Sbostic goto parseredir_return; 103547139Sbostic } 103647139Sbostic 103747139Sbostic 103847139Sbostic /* 103947139Sbostic * Parse a substitution. At this point, we have read the dollar sign 104047139Sbostic * and nothing else. 104147139Sbostic */ 104247139Sbostic 104347139Sbostic parsesub: { 104447139Sbostic int subtype; 104547139Sbostic int typeloc; 104647139Sbostic int flags; 104747139Sbostic char *p; 104847139Sbostic #ifndef GDB_HACK 104947139Sbostic static const char types[] = "}-+?="; 105047139Sbostic #endif 105147139Sbostic 105247139Sbostic c = pgetc(); 105347300Smarc if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) { 105447139Sbostic USTPUTC('$', out); 105547139Sbostic pungetc(); 105653302Smarc } else if (c == '(') { /* $(command) or $((arith)) */ 105753302Smarc if (pgetc() == '(') { 105853302Smarc PARSEARITH(); 105953302Smarc } else { 106053302Smarc pungetc(); 106153302Smarc PARSEBACKQNEW(); 106253302Smarc } 106347139Sbostic } else { 106447139Sbostic USTPUTC(CTLVAR, out); 106547139Sbostic typeloc = out - stackblock(); 106647139Sbostic USTPUTC(VSNORMAL, out); 106747139Sbostic subtype = VSNORMAL; 106847139Sbostic if (c == '{') { 106947139Sbostic c = pgetc(); 107047139Sbostic subtype = 0; 107147139Sbostic } 107247139Sbostic if (is_name(c)) { 107347139Sbostic do { 107447139Sbostic STPUTC(c, out); 107547139Sbostic c = pgetc(); 107647139Sbostic } while (is_in_name(c)); 107747139Sbostic } else { 107847139Sbostic if (! is_special(c)) 107947300Smarc badsub: synerror("Bad substitution"); 108047139Sbostic USTPUTC(c, out); 108147139Sbostic c = pgetc(); 108247139Sbostic } 108347139Sbostic STPUTC('=', out); 108447139Sbostic flags = 0; 108547139Sbostic if (subtype == 0) { 108647139Sbostic if (c == ':') { 108747139Sbostic flags = VSNUL; 108847139Sbostic c = pgetc(); 108947139Sbostic } 109047139Sbostic p = strchr(types, c); 109147139Sbostic if (p == NULL) 109247139Sbostic goto badsub; 109347139Sbostic subtype = p - types + VSNORMAL; 109447139Sbostic } else { 109547139Sbostic pungetc(); 109647139Sbostic } 109753302Smarc if (dblquote || arinest) 109847139Sbostic flags |= VSQUOTE; 109947139Sbostic *(stackblock() + typeloc) = subtype | flags; 110047139Sbostic if (subtype != VSNORMAL) 110147139Sbostic varnest++; 110247139Sbostic } 110347139Sbostic goto parsesub_return; 110447139Sbostic } 110547139Sbostic 110647139Sbostic 110747139Sbostic /* 110847139Sbostic * Called to parse command substitutions. Newstyle is set if the command 110947139Sbostic * is enclosed inside $(...); nlpp is a pointer to the head of the linked 111047139Sbostic * list of commands (passed by reference), and savelen is the number of 111147139Sbostic * characters on the top of the stack which must be preserved. 111247139Sbostic */ 111347139Sbostic 111447139Sbostic parsebackq: { 111547139Sbostic struct nodelist **nlpp; 111647139Sbostic int savepbq; 111747139Sbostic union node *n; 111847139Sbostic char *volatile str; 111947139Sbostic struct jmploc jmploc; 112047139Sbostic struct jmploc *volatile savehandler; 112147139Sbostic int savelen; 112247139Sbostic 112347139Sbostic savepbq = parsebackquote; 112447139Sbostic if (setjmp(jmploc.loc)) { 112547139Sbostic if (str) 112647139Sbostic ckfree(str); 112747139Sbostic parsebackquote = 0; 112847139Sbostic handler = savehandler; 112954322Smarc longjmp(handler->loc, 1); 113047139Sbostic } 113147139Sbostic INTOFF; 113247139Sbostic str = NULL; 113347139Sbostic savelen = out - stackblock(); 113447139Sbostic if (savelen > 0) { 113547139Sbostic str = ckmalloc(savelen); 113647139Sbostic bcopy(stackblock(), str, savelen); 113747139Sbostic } 113847139Sbostic savehandler = handler; 113947139Sbostic handler = &jmploc; 114047139Sbostic INTON; 1141*60296Smarc if (oldstyle) { 1142*60296Smarc /* We must read until the closing backquote, giving special 1143*60296Smarc treatment to some slashes, and then push the string and 1144*60296Smarc reread it as input, interpreting it normally. */ 1145*60296Smarc register char *out; 1146*60296Smarc register c; 1147*60296Smarc int savelen; 1148*60296Smarc char *str; 1149*60296Smarc 1150*60296Smarc STARTSTACKSTR(out); 1151*60296Smarc while ((c = pgetc ()) != '`') { 1152*60296Smarc if (c == '\\') { 1153*60296Smarc c = pgetc (); 1154*60296Smarc if (c != '\\' && c != '`' && c != '$' 1155*60296Smarc && (!dblquote || c != '"')) 1156*60296Smarc STPUTC('\\', out); 1157*60296Smarc } 1158*60296Smarc STPUTC(c, out); 1159*60296Smarc } 1160*60296Smarc STPUTC('\0', out); 1161*60296Smarc savelen = out - stackblock(); 1162*60296Smarc if (savelen > 0) { 1163*60296Smarc str = ckmalloc(savelen); 1164*60296Smarc bcopy(stackblock(), str, savelen); 1165*60296Smarc } 1166*60296Smarc setinputstring(str, 1); 1167*60296Smarc } 116847139Sbostic nlpp = &bqlist; 116947139Sbostic while (*nlpp) 117047139Sbostic nlpp = &(*nlpp)->next; 117147139Sbostic *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 117247139Sbostic (*nlpp)->next = NULL; 117347139Sbostic parsebackquote = oldstyle; 117447139Sbostic n = list(0); 1175*60296Smarc if (!oldstyle && (readtoken() != TRP)) 1176*60296Smarc synexpect(TRP); 117747139Sbostic (*nlpp)->n = n; 1178*60296Smarc /* Start reading from old file again. */ 1179*60296Smarc if (oldstyle) 1180*60296Smarc popfile(); 118147139Sbostic while (stackblocksize() <= savelen) 118247139Sbostic growstackblock(); 118347139Sbostic STARTSTACKSTR(out); 118447139Sbostic if (str) { 118547139Sbostic bcopy(str, out, savelen); 118647139Sbostic STADJUST(savelen, out); 118747139Sbostic INTOFF; 118847139Sbostic ckfree(str); 118947139Sbostic str = NULL; 119047139Sbostic INTON; 119147139Sbostic } 119247139Sbostic parsebackquote = savepbq; 119347139Sbostic handler = savehandler; 119453302Smarc if (arinest || dblquote) 119553302Smarc USTPUTC(CTLBACKQ | CTLQUOTE, out); 119653302Smarc else 119753302Smarc USTPUTC(CTLBACKQ, out); 119847139Sbostic if (oldstyle) 119947139Sbostic goto parsebackq_oldreturn; 120047139Sbostic else 120147139Sbostic goto parsebackq_newreturn; 120247139Sbostic } 120347139Sbostic 120453302Smarc /* 120553302Smarc * Parse an arithmetic expansion (indicate start of one and set state) 120653302Smarc */ 120753302Smarc parsearith: { 120853302Smarc 120953302Smarc if (++arinest == 1) { 121053302Smarc prevsyntax = syntax; 121153302Smarc syntax = ARISYNTAX; 121253302Smarc USTPUTC(CTLARI, out); 121353302Smarc } else { 121453302Smarc /* 121553302Smarc * we collapse embedded arithmetic expansion to 121653302Smarc * parenthesis, which should be equivalent 121753302Smarc */ 121853302Smarc USTPUTC('(', out); 121953302Smarc } 122053302Smarc goto parsearith_return; 122153302Smarc } 122253302Smarc 122347139Sbostic } /* end of readtoken */ 122447139Sbostic 122547139Sbostic 122647139Sbostic 122747139Sbostic #ifdef mkinit 122847139Sbostic RESET { 122947139Sbostic tokpushback = 0; 123054322Smarc checkkwd = 0; 123147139Sbostic } 123247139Sbostic #endif 123347139Sbostic 123447139Sbostic /* 123547139Sbostic * Returns true if the text contains nothing to expand (no dollar signs 123647139Sbostic * or backquotes). 123747139Sbostic */ 123847139Sbostic 123947139Sbostic STATIC int 124047139Sbostic noexpand(text) 124147139Sbostic char *text; 124247139Sbostic { 124347139Sbostic register char *p; 124447139Sbostic register char c; 124547139Sbostic 124647139Sbostic p = text; 124747139Sbostic while ((c = *p++) != '\0') { 124847139Sbostic if (c == CTLESC) 124947139Sbostic p++; 125047139Sbostic else if (BASESYNTAX[c] == CCTL) 125147139Sbostic return 0; 125247139Sbostic } 125347139Sbostic return 1; 125447139Sbostic } 125547139Sbostic 125647139Sbostic 125747139Sbostic /* 125847139Sbostic * Return true if the argument is a legal variable name (a letter or 125947139Sbostic * underscore followed by zero or more letters, underscores, and digits). 126047139Sbostic */ 126147139Sbostic 126247139Sbostic int 126347139Sbostic goodname(name) 126447139Sbostic char *name; 126547139Sbostic { 126647139Sbostic register char *p; 126747139Sbostic 126847139Sbostic p = name; 126947139Sbostic if (! is_name(*p)) 127047139Sbostic return 0; 127147139Sbostic while (*++p) { 127247139Sbostic if (! is_in_name(*p)) 127347139Sbostic return 0; 127447139Sbostic } 127547139Sbostic return 1; 127647139Sbostic } 127747139Sbostic 127847139Sbostic 127947139Sbostic /* 128047139Sbostic * Called when an unexpected token is read during the parse. The argument 128147139Sbostic * is the token that is expected, or -1 if more than one type of token can 128247139Sbostic * occur at this point. 128347139Sbostic */ 128447139Sbostic 128547139Sbostic STATIC void 128647139Sbostic synexpect(token) { 128747139Sbostic char msg[64]; 128847139Sbostic 128947139Sbostic if (token >= 0) { 129047139Sbostic fmtstr(msg, 64, "%s unexpected (expecting %s)", 129147139Sbostic tokname[lasttoken], tokname[token]); 129247139Sbostic } else { 129347139Sbostic fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); 129447139Sbostic } 129547139Sbostic synerror(msg); 129647139Sbostic } 129747139Sbostic 129847139Sbostic 129947139Sbostic STATIC void 130047139Sbostic synerror(msg) 130147139Sbostic char *msg; 130247139Sbostic { 130347139Sbostic if (commandname) 130447139Sbostic outfmt(&errout, "%s: %d: ", commandname, startlinno); 130547139Sbostic outfmt(&errout, "Syntax error: %s\n", msg); 130647139Sbostic error((char *)NULL); 130747139Sbostic } 130854322Smarc 130954322Smarc STATIC void 131054322Smarc setprompt(which) 131154322Smarc int which; 131254322Smarc { 131354322Smarc whichprompt = which; 131454322Smarc 131554322Smarc if (!el) 131654322Smarc out2str(getprompt(NULL)); 131754322Smarc } 131854322Smarc 131954322Smarc /* 132054322Smarc * called by editline -- any expansions to the prompt 132154322Smarc * should be added here. 132254322Smarc */ 132354322Smarc char * 132454322Smarc getprompt(unused) 132554322Smarc void *unused; 132654322Smarc { 132754322Smarc switch (whichprompt) { 132854322Smarc case 0: 132954322Smarc return ""; 133054322Smarc case 1: 133154322Smarc return ps1val(); 133254322Smarc case 2: 133354322Smarc return ps2val(); 133454322Smarc default: 133554322Smarc return "<internal prompt error>"; 133654322Smarc } 133754322Smarc } 1338