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*54322Smarc static char sccsid[] = "@(#)parser.c 5.6 (Berkeley) 06/23/92"; 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" 28*54322Smarc #include "alias.h" 29*54322Smarc #include "histedit.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 */ 59*54322Smarc 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)); 7847981Smarc STATIC union node *simplecmd __P((void)); 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 *)); 87*54322Smarc 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) 100*54322Smarc setprompt(1); 101*54322Smarc else 102*54322Smarc setprompt(0); 10347139Sbostic needprompt = 0; 104*54322Smarc t = readtoken(); 105*54322Smarc 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; 25147139Sbostic switch (readtoken()) { 25247139Sbostic case TIF: 25347139Sbostic n1 = (union node *)stalloc(sizeof (struct nif)); 25447139Sbostic n1->type = NIF; 25547139Sbostic n1->nif.test = list(0); 25647139Sbostic if (readtoken() != TTHEN) 25747139Sbostic synexpect(TTHEN); 25847139Sbostic n1->nif.ifpart = list(0); 25947139Sbostic n2 = n1; 26047139Sbostic while (readtoken() == TELIF) { 26147139Sbostic n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 26247139Sbostic n2 = n2->nif.elsepart; 26347139Sbostic n2->type = NIF; 26447139Sbostic n2->nif.test = list(0); 26547139Sbostic if (readtoken() != TTHEN) 26647139Sbostic synexpect(TTHEN); 26747139Sbostic n2->nif.ifpart = list(0); 26847139Sbostic } 26947139Sbostic if (lasttoken == TELSE) 27047139Sbostic n2->nif.elsepart = list(0); 27147139Sbostic else { 27247139Sbostic n2->nif.elsepart = NULL; 27347139Sbostic tokpushback++; 27447139Sbostic } 27547139Sbostic if (readtoken() != TFI) 27647139Sbostic synexpect(TFI); 27747981Smarc checkkwd = 1; 27847139Sbostic break; 27947139Sbostic case TWHILE: 28047981Smarc case TUNTIL: { 28147981Smarc int got; 28247139Sbostic n1 = (union node *)stalloc(sizeof (struct nbinary)); 28347139Sbostic n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 28447139Sbostic n1->nbinary.ch1 = list(0); 28547981Smarc if ((got=readtoken()) != TDO) { 28647981Smarc TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 28747139Sbostic synexpect(TDO); 28847981Smarc } 28947139Sbostic n1->nbinary.ch2 = list(0); 29047139Sbostic if (readtoken() != TDONE) 29147139Sbostic synexpect(TDONE); 29247981Smarc checkkwd = 1; 29347139Sbostic break; 29447981Smarc } 29547139Sbostic case TFOR: 29647139Sbostic if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 29747139Sbostic synerror("Bad for loop variable"); 29847139Sbostic n1 = (union node *)stalloc(sizeof (struct nfor)); 29947139Sbostic n1->type = NFOR; 30047139Sbostic n1->nfor.var = wordtext; 30147139Sbostic if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { 30247139Sbostic app = ≈ 30347139Sbostic while (readtoken() == TWORD) { 30447139Sbostic n2 = (union node *)stalloc(sizeof (struct narg)); 30547139Sbostic n2->type = NARG; 30647139Sbostic n2->narg.text = wordtext; 30747139Sbostic n2->narg.backquote = backquotelist; 30847139Sbostic *app = n2; 30947139Sbostic app = &n2->narg.next; 31047139Sbostic } 31147139Sbostic *app = NULL; 31247139Sbostic n1->nfor.args = ap; 31347139Sbostic } else { 31447139Sbostic #ifndef GDB_HACK 31547139Sbostic static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, 31647139Sbostic '@', '=', '\0'}; 31747139Sbostic #endif 31847139Sbostic n2 = (union node *)stalloc(sizeof (struct narg)); 31947139Sbostic n2->type = NARG; 32047139Sbostic n2->narg.text = (char *)argvars; 32147139Sbostic n2->narg.backquote = NULL; 32247139Sbostic n2->narg.next = NULL; 32347139Sbostic n1->nfor.args = n2; 32447139Sbostic } 32547139Sbostic if (lasttoken != TNL && lasttoken != TSEMI) 32647139Sbostic synexpect(-1); 32747981Smarc checkkwd = 2; 32847139Sbostic if ((t = readtoken()) == TDO) 32947139Sbostic t = TDONE; 33047139Sbostic else if (t == TBEGIN) 33147139Sbostic t = TEND; 33247139Sbostic else 33347139Sbostic synexpect(-1); 33447139Sbostic n1->nfor.body = list(0); 33547139Sbostic if (readtoken() != t) 33647139Sbostic synexpect(t); 33747981Smarc checkkwd = 1; 33847139Sbostic break; 33947139Sbostic case TCASE: 34047139Sbostic n1 = (union node *)stalloc(sizeof (struct ncase)); 34147139Sbostic n1->type = NCASE; 34247139Sbostic if (readtoken() != TWORD) 34347139Sbostic synexpect(TWORD); 34447139Sbostic n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); 34547139Sbostic n2->type = NARG; 34647139Sbostic n2->narg.text = wordtext; 34747139Sbostic n2->narg.backquote = backquotelist; 34847139Sbostic n2->narg.next = NULL; 34947139Sbostic while (readtoken() == TNL); 35047139Sbostic if (lasttoken != TWORD || ! equal(wordtext, "in")) 35147139Sbostic synerror("expecting \"in\""); 35247139Sbostic cpp = &n1->ncase.cases; 35347981Smarc while (checkkwd = 2, readtoken() == TWORD) { 35447139Sbostic *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 35547139Sbostic cp->type = NCLIST; 35647139Sbostic app = &cp->nclist.pattern; 35747139Sbostic for (;;) { 35847139Sbostic *app = ap = (union node *)stalloc(sizeof (struct narg)); 35947139Sbostic ap->type = NARG; 36047139Sbostic ap->narg.text = wordtext; 36147139Sbostic ap->narg.backquote = backquotelist; 36247139Sbostic if (readtoken() != TPIPE) 36347139Sbostic break; 36447139Sbostic app = &ap->narg.next; 36547139Sbostic if (readtoken() != TWORD) 36647139Sbostic synexpect(TWORD); 36747139Sbostic } 36847139Sbostic ap->narg.next = NULL; 36947139Sbostic if (lasttoken != TRP) 37047139Sbostic synexpect(TRP); 37147139Sbostic cp->nclist.body = list(0); 37247139Sbostic if ((t = readtoken()) == TESAC) 37347139Sbostic tokpushback++; 37447139Sbostic else if (t != TENDCASE) 37547139Sbostic synexpect(TENDCASE); 37647139Sbostic cpp = &cp->nclist.next; 37747139Sbostic } 37847139Sbostic *cpp = NULL; 37947139Sbostic if (lasttoken != TESAC) 38047139Sbostic synexpect(TESAC); 38147981Smarc checkkwd = 1; 38247139Sbostic break; 38347139Sbostic case TLP: 38447139Sbostic n1 = (union node *)stalloc(sizeof (struct nredir)); 38547139Sbostic n1->type = NSUBSHELL; 38647139Sbostic n1->nredir.n = list(0); 38747139Sbostic n1->nredir.redirect = NULL; 38847139Sbostic if (readtoken() != TRP) 38947139Sbostic synexpect(TRP); 39047981Smarc checkkwd = 1; 39147139Sbostic break; 39247139Sbostic case TBEGIN: 39347139Sbostic n1 = list(0); 39447139Sbostic if (readtoken() != TEND) 39547139Sbostic synexpect(TEND); 39647981Smarc checkkwd = 1; 39747139Sbostic break; 39847139Sbostic case TWORD: 39947139Sbostic case TREDIR: 40047139Sbostic tokpushback++; 40147139Sbostic return simplecmd(); 40247139Sbostic default: 40347139Sbostic synexpect(-1); 40447139Sbostic } 40547139Sbostic 40647139Sbostic /* Now check for redirection which may follow command */ 40747139Sbostic rpp = &redir; 40847139Sbostic while (readtoken() == TREDIR) { 40947139Sbostic *rpp = n2 = redirnode; 41047139Sbostic rpp = &n2->nfile.next; 41147139Sbostic parsefname(); 41247139Sbostic } 41347139Sbostic tokpushback++; 41447139Sbostic *rpp = NULL; 41547139Sbostic if (redir) { 41647139Sbostic if (n1->type != NSUBSHELL) { 41747139Sbostic n2 = (union node *)stalloc(sizeof (struct nredir)); 41847139Sbostic n2->type = NREDIR; 41947139Sbostic n2->nredir.n = n1; 42047139Sbostic n1 = n2; 42147139Sbostic } 42247139Sbostic n1->nredir.redirect = redir; 42347139Sbostic } 42447139Sbostic return n1; 42547139Sbostic } 42647139Sbostic 42747139Sbostic 42847139Sbostic STATIC union node * 42947139Sbostic simplecmd() { 43047139Sbostic union node *args, **app; 43147139Sbostic union node *redir, **rpp; 43247139Sbostic union node *n; 43347139Sbostic 43447139Sbostic args = NULL; 43547139Sbostic app = &args; 43647139Sbostic rpp = &redir; 43747139Sbostic for (;;) { 43847139Sbostic if (readtoken() == TWORD) { 43947139Sbostic n = (union node *)stalloc(sizeof (struct narg)); 44047139Sbostic n->type = NARG; 44147139Sbostic n->narg.text = wordtext; 44247139Sbostic n->narg.backquote = backquotelist; 44347139Sbostic *app = n; 44447139Sbostic app = &n->narg.next; 44547139Sbostic } else if (lasttoken == TREDIR) { 44647139Sbostic *rpp = n = redirnode; 44747139Sbostic rpp = &n->nfile.next; 44847139Sbostic parsefname(); /* read name of redirection file */ 44947139Sbostic } else if (lasttoken == TLP && app == &args->narg.next 45047139Sbostic && rpp == &redir) { 45147139Sbostic /* We have a function */ 45247139Sbostic if (readtoken() != TRP) 45347139Sbostic synexpect(TRP); 45447300Smarc #ifdef notdef 45547139Sbostic if (! goodname(n->narg.text)) 45647139Sbostic synerror("Bad function name"); 45747300Smarc #endif 45847139Sbostic n->type = NDEFUN; 45947139Sbostic n->narg.next = command(); 46047139Sbostic return n; 46147139Sbostic } else { 46247139Sbostic tokpushback++; 46347139Sbostic break; 46447139Sbostic } 46547139Sbostic } 46647139Sbostic *app = NULL; 46747139Sbostic *rpp = NULL; 46847139Sbostic n = (union node *)stalloc(sizeof (struct ncmd)); 46947139Sbostic n->type = NCMD; 47047139Sbostic n->ncmd.backgnd = 0; 47147139Sbostic n->ncmd.args = args; 47247139Sbostic n->ncmd.redirect = redir; 47347139Sbostic return n; 47447139Sbostic } 47547139Sbostic 47647139Sbostic 47747139Sbostic STATIC void 47847139Sbostic parsefname() { 47947139Sbostic union node *n = redirnode; 48047139Sbostic 48147139Sbostic if (readtoken() != TWORD) 48247139Sbostic synexpect(-1); 48347139Sbostic if (n->type == NHERE) { 48447139Sbostic struct heredoc *here = heredoc; 48547139Sbostic struct heredoc *p; 48647139Sbostic int i; 48747139Sbostic 48847139Sbostic if (quoteflag == 0) 48947139Sbostic n->type = NXHERE; 49047139Sbostic TRACE(("Here document %d\n", n->type)); 49147139Sbostic if (here->striptabs) { 49247139Sbostic while (*wordtext == '\t') 49347139Sbostic wordtext++; 49447139Sbostic } 49547139Sbostic if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 49647139Sbostic synerror("Illegal eof marker for << redirection"); 49747139Sbostic rmescapes(wordtext); 49847139Sbostic here->eofmark = wordtext; 49947139Sbostic here->next = NULL; 50047139Sbostic if (heredoclist == NULL) 50147139Sbostic heredoclist = here; 50247139Sbostic else { 50347139Sbostic for (p = heredoclist ; p->next ; p = p->next); 50447139Sbostic p->next = here; 50547139Sbostic } 50647139Sbostic } else if (n->type == NTOFD || n->type == NFROMFD) { 50747139Sbostic if (is_digit(wordtext[0])) 50847139Sbostic n->ndup.dupfd = digit_val(wordtext[0]); 50947139Sbostic else if (wordtext[0] == '-') 51047139Sbostic n->ndup.dupfd = -1; 51147139Sbostic else 51247139Sbostic goto bad; 51347139Sbostic if (wordtext[1] != '\0') { 51447139Sbostic bad: 51547139Sbostic synerror("Bad fd number"); 51647139Sbostic } 51747139Sbostic } else { 51847139Sbostic n->nfile.fname = (union node *)stalloc(sizeof (struct narg)); 51947139Sbostic n = n->nfile.fname; 52047139Sbostic n->type = NARG; 52147139Sbostic n->narg.next = NULL; 52247139Sbostic n->narg.text = wordtext; 52347139Sbostic n->narg.backquote = backquotelist; 52447139Sbostic } 52547139Sbostic } 52647139Sbostic 52747139Sbostic 52847139Sbostic /* 52947139Sbostic * Input any here documents. 53047139Sbostic */ 53147139Sbostic 53247139Sbostic STATIC void 53347139Sbostic parseheredoc() { 53447139Sbostic struct heredoc *here; 53547139Sbostic union node *n; 53647139Sbostic 53747139Sbostic while (heredoclist) { 53847139Sbostic here = heredoclist; 53947139Sbostic heredoclist = here->next; 54047139Sbostic if (needprompt) { 541*54322Smarc setprompt(2); 54247139Sbostic needprompt = 0; 54347139Sbostic } 54447139Sbostic readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 54547139Sbostic here->eofmark, here->striptabs); 54647139Sbostic n = (union node *)stalloc(sizeof (struct narg)); 54747139Sbostic n->narg.type = NARG; 54847139Sbostic n->narg.next = NULL; 54947139Sbostic n->narg.text = wordtext; 55047139Sbostic n->narg.backquote = backquotelist; 55147139Sbostic here->here->nhere.doc = n; 55247139Sbostic } 55347139Sbostic } 55447139Sbostic 55547981Smarc STATIC int 55647981Smarc peektoken() { 55747139Sbostic int t; 55847139Sbostic 55947981Smarc t = readtoken(); 56047139Sbostic tokpushback++; 56147981Smarc return (t); 56247139Sbostic } 56347139Sbostic 56447139Sbostic STATIC int xxreadtoken(); 56547139Sbostic 56647139Sbostic STATIC int 56747139Sbostic readtoken() { 56847139Sbostic int t; 569*54322Smarc int savecheckkwd = checkkwd; 570*54322Smarc struct alias *ap; 57147981Smarc #ifdef DEBUG 57247981Smarc int alreadyseen = tokpushback; 57347981Smarc #endif 57447981Smarc 575*54322Smarc top: 57647981Smarc t = xxreadtoken(); 57747139Sbostic 57847981Smarc if (checkkwd) { 57947981Smarc /* 58047981Smarc * eat newlines 58147981Smarc */ 58247981Smarc if (checkkwd == 2) { 58347981Smarc checkkwd = 0; 58447981Smarc while (t == TNL) { 58547981Smarc parseheredoc(); 58647981Smarc t = xxreadtoken(); 58747981Smarc } 58847981Smarc } else 58947981Smarc checkkwd = 0; 59047981Smarc /* 591*54322Smarc * check for keywords and aliases 59247981Smarc */ 59347981Smarc if (t == TWORD && !quoteflag) { 594*54322Smarc register char * const *pp, *s; 59547981Smarc 59647981Smarc for (pp = parsekwd; *pp; pp++) { 59747981Smarc if (**pp == *wordtext && equal(*pp, wordtext)) { 59847981Smarc lasttoken = t = pp - parsekwd + KWDOFFSET; 59947981Smarc TRACE(("keyword %s recognized\n", tokname[t])); 600*54322Smarc goto out; 60147981Smarc } 60247981Smarc } 603*54322Smarc if (ap = lookupalias(wordtext, 1)) { 604*54322Smarc pushstring(ap->val, strlen(ap->val), ap); 605*54322Smarc checkkwd = savecheckkwd; 606*54322Smarc goto top; 607*54322Smarc } 60847981Smarc } 609*54322Smarc out: 610*54322Smarc checkkwd = 0; 61147139Sbostic } 61247981Smarc #ifdef DEBUG 61347981Smarc if (!alreadyseen) 61447981Smarc TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 61547981Smarc else 61647981Smarc TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 61747981Smarc #endif 61847981Smarc return (t); 61947139Sbostic } 62047139Sbostic 62147139Sbostic 62247139Sbostic /* 62347139Sbostic * Read the next input token. 62447139Sbostic * If the token is a word, we set backquotelist to the list of cmds in 62547139Sbostic * backquotes. We set quoteflag to true if any part of the word was 62647139Sbostic * quoted. 62747139Sbostic * If the token is TREDIR, then we set redirnode to a structure containing 62847139Sbostic * the redirection. 62947139Sbostic * In all cases, the variable startlinno is set to the number of the line 63047139Sbostic * on which the token starts. 63147139Sbostic * 63247139Sbostic * [Change comment: here documents and internal procedures] 63347139Sbostic * [Readtoken shouldn't have any arguments. Perhaps we should make the 63447139Sbostic * word parsing code into a separate routine. In this case, readtoken 63547139Sbostic * doesn't need to have any internal procedures, but parseword does. 63647139Sbostic * We could also make parseoperator in essence the main routine, and 63747139Sbostic * have parseword (readtoken1?) handle both words and redirection.] 63847139Sbostic */ 63947139Sbostic 64047139Sbostic #define RETURN(token) return lasttoken = token 64147139Sbostic 64247139Sbostic STATIC int 64347139Sbostic xxreadtoken() { 64447139Sbostic register c; 64547139Sbostic 64647139Sbostic if (tokpushback) { 64747139Sbostic tokpushback = 0; 64847139Sbostic return lasttoken; 64947139Sbostic } 65047139Sbostic if (needprompt) { 651*54322Smarc setprompt(2); 65247139Sbostic needprompt = 0; 65347139Sbostic } 65447139Sbostic startlinno = plinno; 65547139Sbostic for (;;) { /* until token or start of word found */ 65647139Sbostic c = pgetc_macro(); 65747139Sbostic if (c == ' ' || c == '\t') 65847139Sbostic continue; /* quick check for white space first */ 65947139Sbostic switch (c) { 66047139Sbostic case ' ': case '\t': 66147139Sbostic continue; 66247139Sbostic case '#': 66347139Sbostic while ((c = pgetc()) != '\n' && c != PEOF); 66447139Sbostic pungetc(); 66547139Sbostic continue; 66647139Sbostic case '\\': 66747139Sbostic if (pgetc() == '\n') { 66847139Sbostic startlinno = ++plinno; 66947139Sbostic if (doprompt) 670*54322Smarc setprompt(2); 671*54322Smarc else 672*54322Smarc setprompt(0); 67347139Sbostic continue; 67447139Sbostic } 67547139Sbostic pungetc(); 67647139Sbostic goto breakloop; 67747139Sbostic case '\n': 67847139Sbostic plinno++; 67947139Sbostic needprompt = doprompt; 68047139Sbostic RETURN(TNL); 68147139Sbostic case PEOF: 68247139Sbostic RETURN(TEOF); 68347139Sbostic case '&': 68447139Sbostic if (pgetc() == '&') 68547139Sbostic RETURN(TAND); 68647139Sbostic pungetc(); 68747139Sbostic RETURN(TBACKGND); 68847139Sbostic case '|': 68947139Sbostic if (pgetc() == '|') 69047139Sbostic RETURN(TOR); 69147139Sbostic pungetc(); 69247139Sbostic RETURN(TPIPE); 69347139Sbostic case ';': 69447139Sbostic if (pgetc() == ';') 69547139Sbostic RETURN(TENDCASE); 69647139Sbostic pungetc(); 69747139Sbostic RETURN(TSEMI); 69847139Sbostic case '(': 69947139Sbostic RETURN(TLP); 70047139Sbostic case ')': 70147139Sbostic RETURN(TRP); 70247139Sbostic default: 70347139Sbostic goto breakloop; 70447139Sbostic } 70547139Sbostic } 70647139Sbostic breakloop: 70747139Sbostic return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 70847139Sbostic #undef RETURN 70947139Sbostic } 71047139Sbostic 71147139Sbostic 71247139Sbostic 71347139Sbostic /* 71447139Sbostic * If eofmark is NULL, read a word or a redirection symbol. If eofmark 71547139Sbostic * is not NULL, read a here document. In the latter case, eofmark is the 71647139Sbostic * word which marks the end of the document and striptabs is true if 71747139Sbostic * leading tabs should be stripped from the document. The argument firstc 71847139Sbostic * is the first character of the input token or document. 71947139Sbostic * 72047139Sbostic * Because C does not have internal subroutines, I have simulated them 72147139Sbostic * using goto's to implement the subroutine linkage. The following macros 72247139Sbostic * will run code that appears at the end of readtoken1. 72347139Sbostic */ 72447139Sbostic 72547139Sbostic #define CHECKEND() {goto checkend; checkend_return:;} 72647139Sbostic #define PARSEREDIR() {goto parseredir; parseredir_return:;} 72747139Sbostic #define PARSESUB() {goto parsesub; parsesub_return:;} 72847139Sbostic #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} 72947139Sbostic #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 73053302Smarc #define PARSEARITH() {goto parsearith; parsearith_return:;} 73147139Sbostic 73247139Sbostic STATIC int 73347139Sbostic readtoken1(firstc, syntax, eofmark, striptabs) 73447139Sbostic int firstc; 73547139Sbostic char const *syntax; 73647139Sbostic char *eofmark; 73747139Sbostic int striptabs; 73847139Sbostic { 73947139Sbostic register c = firstc; 74047139Sbostic register char *out; 74147139Sbostic int len; 74247139Sbostic char line[EOFMARKLEN + 1]; 74347139Sbostic struct nodelist *bqlist; 74447139Sbostic int quotef; 74547139Sbostic int dblquote; 74653302Smarc int varnest; /* levels of variables expansion */ 74753302Smarc int arinest; /* levels of arithmetic expansion */ 74853302Smarc int parenlevel; /* levels of parens in arithmetic */ 74947139Sbostic int oldstyle; 75053302Smarc char const *prevsyntax; /* syntax before arithmetic */ 75147139Sbostic 75247139Sbostic startlinno = plinno; 75347139Sbostic dblquote = 0; 75447139Sbostic if (syntax == DQSYNTAX) 75547139Sbostic dblquote = 1; 75647139Sbostic quotef = 0; 75747139Sbostic bqlist = NULL; 75847139Sbostic varnest = 0; 75953302Smarc arinest = 0; 76053302Smarc parenlevel = 0; 76153302Smarc 76247139Sbostic STARTSTACKSTR(out); 76347139Sbostic loop: { /* for each line, until end of word */ 76447139Sbostic #if ATTY 76547139Sbostic if (c == '\034' && doprompt 76647139Sbostic && attyset() && ! equal(termval(), "emacs")) { 76747139Sbostic attyline(); 76847139Sbostic if (syntax == BASESYNTAX) 76947139Sbostic return readtoken(); 77047139Sbostic c = pgetc(); 77147139Sbostic goto loop; 77247139Sbostic } 77347139Sbostic #endif 77447139Sbostic CHECKEND(); /* set c to PEOF if at end of here document */ 77547139Sbostic for (;;) { /* until end of line or end of word */ 77647139Sbostic CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ 77747139Sbostic switch(syntax[c]) { 77847139Sbostic case CNL: /* '\n' */ 77947139Sbostic if (syntax == BASESYNTAX) 78047139Sbostic goto endword; /* exit outer loop */ 78147139Sbostic USTPUTC(c, out); 78247139Sbostic plinno++; 783*54322Smarc if (doprompt) 784*54322Smarc setprompt(2); 785*54322Smarc else 786*54322Smarc setprompt(0); 78747139Sbostic c = pgetc(); 78847139Sbostic goto loop; /* continue outer loop */ 78947139Sbostic case CWORD: 79047139Sbostic USTPUTC(c, out); 79147139Sbostic break; 79247139Sbostic case CCTL: 79347139Sbostic if (eofmark == NULL || dblquote) 79447139Sbostic USTPUTC(CTLESC, out); 79547139Sbostic USTPUTC(c, out); 79647139Sbostic break; 79747139Sbostic case CBACK: /* backslash */ 79847139Sbostic c = pgetc(); 79947139Sbostic if (c == PEOF) { 80047139Sbostic USTPUTC('\\', out); 80147139Sbostic pungetc(); 80247139Sbostic } else if (c == '\n') { 80347139Sbostic if (doprompt) 804*54322Smarc setprompt(2); 805*54322Smarc else 806*54322Smarc setprompt(0); 80747139Sbostic } else { 80847139Sbostic if (dblquote && c != '\\' && c != '`' && c != '$' 80947139Sbostic && (c != '"' || eofmark != NULL)) 81047139Sbostic USTPUTC('\\', out); 81147139Sbostic if (SQSYNTAX[c] == CCTL) 81247139Sbostic USTPUTC(CTLESC, out); 81347139Sbostic USTPUTC(c, out); 81447139Sbostic quotef++; 81547139Sbostic } 81647139Sbostic break; 81747139Sbostic case CSQUOTE: 81847139Sbostic syntax = SQSYNTAX; 81947139Sbostic break; 82047139Sbostic case CDQUOTE: 82147139Sbostic syntax = DQSYNTAX; 82247139Sbostic dblquote = 1; 82347139Sbostic break; 82447139Sbostic case CENDQUOTE: 82547139Sbostic if (eofmark) { 82647139Sbostic USTPUTC(c, out); 82747139Sbostic } else { 82853302Smarc if (arinest) 82953302Smarc syntax = ARISYNTAX; 83053302Smarc else 83153302Smarc syntax = BASESYNTAX; 83247139Sbostic quotef++; 83347139Sbostic dblquote = 0; 83447139Sbostic } 83547139Sbostic break; 83647139Sbostic case CVAR: /* '$' */ 83747139Sbostic PARSESUB(); /* parse substitution */ 83847139Sbostic break; 83947139Sbostic case CENDVAR: /* '}' */ 84047139Sbostic if (varnest > 0) { 84147139Sbostic varnest--; 84247139Sbostic USTPUTC(CTLENDVAR, out); 84347139Sbostic } else { 84447139Sbostic USTPUTC(c, out); 84547139Sbostic } 84647139Sbostic break; 84753302Smarc case CLP: /* '(' in arithmetic */ 84853302Smarc parenlevel++; 84953302Smarc USTPUTC(c, out); 85053302Smarc break; 85153302Smarc case CRP: /* ')' in arithmetic */ 85253302Smarc if (parenlevel > 0) { 85353302Smarc USTPUTC(c, out); 85453302Smarc --parenlevel; 85553302Smarc } else { 85653302Smarc if (pgetc() == ')') { 85753302Smarc if (--arinest == 0) { 85853302Smarc USTPUTC(CTLENDARI, out); 85953302Smarc syntax = prevsyntax; 86053302Smarc } else 86153302Smarc USTPUTC(')', out); 86253302Smarc } else { 86353302Smarc /* 86453302Smarc * unbalanced parens 86553302Smarc * (don't 2nd guess - no error) 86653302Smarc */ 86753302Smarc pungetc(); 86853302Smarc USTPUTC(')', out); 86953302Smarc } 87053302Smarc } 87153302Smarc break; 87247139Sbostic case CBQUOTE: /* '`' */ 87347139Sbostic if (parsebackquote && syntax == BASESYNTAX) { 87447139Sbostic if (out == stackblock()) 87547139Sbostic return lasttoken = TENDBQUOTE; 87647139Sbostic else 87747139Sbostic goto endword; /* exit outer loop */ 87847139Sbostic } 87947139Sbostic PARSEBACKQOLD(); 88047139Sbostic break; 88147139Sbostic case CEOF: 88247139Sbostic goto endword; /* exit outer loop */ 88347139Sbostic default: 88447139Sbostic if (varnest == 0) 88547139Sbostic goto endword; /* exit outer loop */ 88647139Sbostic USTPUTC(c, out); 88747139Sbostic } 88847139Sbostic c = pgetc_macro(); 88947139Sbostic } 89047139Sbostic } 89147139Sbostic endword: 89253302Smarc if (syntax == ARISYNTAX) 89353302Smarc synerror("Missing '))'"); 89447139Sbostic if (syntax != BASESYNTAX && eofmark == NULL) 89547139Sbostic synerror("Unterminated quoted string"); 89647139Sbostic if (varnest != 0) { 89747139Sbostic startlinno = plinno; 89847139Sbostic synerror("Missing '}'"); 89947139Sbostic } 90047139Sbostic USTPUTC('\0', out); 90147139Sbostic len = out - stackblock(); 90247139Sbostic out = stackblock(); 90347139Sbostic if (eofmark == NULL) { 90447139Sbostic if ((c == '>' || c == '<') 90547139Sbostic && quotef == 0 90647139Sbostic && len <= 2 90747139Sbostic && (*out == '\0' || is_digit(*out))) { 90847139Sbostic PARSEREDIR(); 90947139Sbostic return lasttoken = TREDIR; 91047139Sbostic } else { 91147139Sbostic pungetc(); 91247139Sbostic } 91347139Sbostic } 91447139Sbostic quoteflag = quotef; 91547139Sbostic backquotelist = bqlist; 91647139Sbostic grabstackblock(len); 91747139Sbostic wordtext = out; 91847139Sbostic return lasttoken = TWORD; 91947139Sbostic /* end of readtoken routine */ 92047139Sbostic 92147139Sbostic 92247139Sbostic 92347139Sbostic /* 92447139Sbostic * Check to see whether we are at the end of the here document. When this 92547139Sbostic * is called, c is set to the first character of the next input line. If 92647139Sbostic * we are at the end of the here document, this routine sets the c to PEOF. 92747139Sbostic */ 92847139Sbostic 92947139Sbostic checkend: { 93047139Sbostic if (eofmark) { 93147139Sbostic if (striptabs) { 93247139Sbostic while (c == '\t') 93347139Sbostic c = pgetc(); 93447139Sbostic } 93547139Sbostic if (c == *eofmark) { 93647139Sbostic if (pfgets(line, sizeof line) != NULL) { 93747139Sbostic register char *p, *q; 93847139Sbostic 93947139Sbostic p = line; 94047139Sbostic for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); 94147139Sbostic if (*p == '\n' && *q == '\0') { 94247139Sbostic c = PEOF; 94347139Sbostic plinno++; 94447139Sbostic needprompt = doprompt; 94547139Sbostic } else { 946*54322Smarc pushstring(line, strlen(line), NULL); 94747139Sbostic } 94847139Sbostic } 94947139Sbostic } 95047139Sbostic } 95147139Sbostic goto checkend_return; 95247139Sbostic } 95347139Sbostic 95447139Sbostic 95547139Sbostic /* 95647139Sbostic * Parse a redirection operator. The variable "out" points to a string 95747139Sbostic * specifying the fd to be redirected. The variable "c" contains the 95847139Sbostic * first character of the redirection operator. 95947139Sbostic */ 96047139Sbostic 96147139Sbostic parseredir: { 96247139Sbostic char fd = *out; 96347139Sbostic union node *np; 96447139Sbostic 96547139Sbostic np = (union node *)stalloc(sizeof (struct nfile)); 96647139Sbostic if (c == '>') { 96747139Sbostic np->nfile.fd = 1; 96847139Sbostic c = pgetc(); 96947139Sbostic if (c == '>') 97047139Sbostic np->type = NAPPEND; 97147139Sbostic else if (c == '&') 97247139Sbostic np->type = NTOFD; 97347139Sbostic else { 97447139Sbostic np->type = NTO; 97547139Sbostic pungetc(); 97647139Sbostic } 97747139Sbostic } else { /* c == '<' */ 97847139Sbostic np->nfile.fd = 0; 97947139Sbostic c = pgetc(); 98047139Sbostic if (c == '<') { 98147139Sbostic if (sizeof (struct nfile) != sizeof (struct nhere)) { 98247139Sbostic np = (union node *)stalloc(sizeof (struct nhere)); 98347139Sbostic np->nfile.fd = 0; 98447139Sbostic } 98547139Sbostic np->type = NHERE; 98647139Sbostic heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); 98747139Sbostic heredoc->here = np; 98847139Sbostic if ((c = pgetc()) == '-') { 98947139Sbostic heredoc->striptabs = 1; 99047139Sbostic } else { 99147139Sbostic heredoc->striptabs = 0; 99247139Sbostic pungetc(); 99347139Sbostic } 99447139Sbostic } else if (c == '&') 99547139Sbostic np->type = NFROMFD; 99647139Sbostic else { 99747139Sbostic np->type = NFROM; 99847139Sbostic pungetc(); 99947139Sbostic } 100047139Sbostic } 100147139Sbostic if (fd != '\0') 100247139Sbostic np->nfile.fd = digit_val(fd); 100347139Sbostic redirnode = np; 100447139Sbostic goto parseredir_return; 100547139Sbostic } 100647139Sbostic 100747139Sbostic 100847139Sbostic /* 100947139Sbostic * Parse a substitution. At this point, we have read the dollar sign 101047139Sbostic * and nothing else. 101147139Sbostic */ 101247139Sbostic 101347139Sbostic parsesub: { 101447139Sbostic int subtype; 101547139Sbostic int typeloc; 101647139Sbostic int flags; 101747139Sbostic char *p; 101847139Sbostic #ifndef GDB_HACK 101947139Sbostic static const char types[] = "}-+?="; 102047139Sbostic #endif 102147139Sbostic 102247139Sbostic c = pgetc(); 102347300Smarc if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) { 102447139Sbostic USTPUTC('$', out); 102547139Sbostic pungetc(); 102653302Smarc } else if (c == '(') { /* $(command) or $((arith)) */ 102753302Smarc if (pgetc() == '(') { 102853302Smarc PARSEARITH(); 102953302Smarc } else { 103053302Smarc pungetc(); 103153302Smarc PARSEBACKQNEW(); 103253302Smarc } 103347139Sbostic } else { 103447139Sbostic USTPUTC(CTLVAR, out); 103547139Sbostic typeloc = out - stackblock(); 103647139Sbostic USTPUTC(VSNORMAL, out); 103747139Sbostic subtype = VSNORMAL; 103847139Sbostic if (c == '{') { 103947139Sbostic c = pgetc(); 104047139Sbostic subtype = 0; 104147139Sbostic } 104247139Sbostic if (is_name(c)) { 104347139Sbostic do { 104447139Sbostic STPUTC(c, out); 104547139Sbostic c = pgetc(); 104647139Sbostic } while (is_in_name(c)); 104747139Sbostic } else { 104847139Sbostic if (! is_special(c)) 104947300Smarc badsub: synerror("Bad substitution"); 105047139Sbostic USTPUTC(c, out); 105147139Sbostic c = pgetc(); 105247139Sbostic } 105347139Sbostic STPUTC('=', out); 105447139Sbostic flags = 0; 105547139Sbostic if (subtype == 0) { 105647139Sbostic if (c == ':') { 105747139Sbostic flags = VSNUL; 105847139Sbostic c = pgetc(); 105947139Sbostic } 106047139Sbostic p = strchr(types, c); 106147139Sbostic if (p == NULL) 106247139Sbostic goto badsub; 106347139Sbostic subtype = p - types + VSNORMAL; 106447139Sbostic } else { 106547139Sbostic pungetc(); 106647139Sbostic } 106753302Smarc if (dblquote || arinest) 106847139Sbostic flags |= VSQUOTE; 106947139Sbostic *(stackblock() + typeloc) = subtype | flags; 107047139Sbostic if (subtype != VSNORMAL) 107147139Sbostic varnest++; 107247139Sbostic } 107347139Sbostic goto parsesub_return; 107447139Sbostic } 107547139Sbostic 107647139Sbostic 107747139Sbostic /* 107847139Sbostic * Called to parse command substitutions. Newstyle is set if the command 107947139Sbostic * is enclosed inside $(...); nlpp is a pointer to the head of the linked 108047139Sbostic * list of commands (passed by reference), and savelen is the number of 108147139Sbostic * characters on the top of the stack which must be preserved. 108247139Sbostic */ 108347139Sbostic 108447139Sbostic parsebackq: { 108547139Sbostic struct nodelist **nlpp; 108647139Sbostic int savepbq; 108747139Sbostic union node *n; 108847139Sbostic char *volatile str; 108947139Sbostic struct jmploc jmploc; 109047139Sbostic struct jmploc *volatile savehandler; 109147139Sbostic int savelen; 109247139Sbostic int t; 109347139Sbostic 109447139Sbostic savepbq = parsebackquote; 109547139Sbostic if (setjmp(jmploc.loc)) { 109647139Sbostic if (str) 109747139Sbostic ckfree(str); 109847139Sbostic parsebackquote = 0; 109947139Sbostic handler = savehandler; 1100*54322Smarc longjmp(handler->loc, 1); 110147139Sbostic } 110247139Sbostic INTOFF; 110347139Sbostic str = NULL; 110447139Sbostic savelen = out - stackblock(); 110547139Sbostic if (savelen > 0) { 110647139Sbostic str = ckmalloc(savelen); 110747139Sbostic bcopy(stackblock(), str, savelen); 110847139Sbostic } 110947139Sbostic savehandler = handler; 111047139Sbostic handler = &jmploc; 111147139Sbostic INTON; 111247139Sbostic nlpp = &bqlist; 111347139Sbostic while (*nlpp) 111447139Sbostic nlpp = &(*nlpp)->next; 111547139Sbostic *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 111647139Sbostic (*nlpp)->next = NULL; 111747139Sbostic parsebackquote = oldstyle; 111847139Sbostic n = list(0); 111947139Sbostic t = oldstyle? TENDBQUOTE : TRP; 112047139Sbostic if (readtoken() != t) 112147139Sbostic synexpect(t); 112247139Sbostic (*nlpp)->n = n; 112347139Sbostic while (stackblocksize() <= savelen) 112447139Sbostic growstackblock(); 112547139Sbostic STARTSTACKSTR(out); 112647139Sbostic if (str) { 112747139Sbostic bcopy(str, out, savelen); 112847139Sbostic STADJUST(savelen, out); 112947139Sbostic INTOFF; 113047139Sbostic ckfree(str); 113147139Sbostic str = NULL; 113247139Sbostic INTON; 113347139Sbostic } 113447139Sbostic parsebackquote = savepbq; 113547139Sbostic handler = savehandler; 113653302Smarc if (arinest || dblquote) 113753302Smarc USTPUTC(CTLBACKQ | CTLQUOTE, out); 113853302Smarc else 113953302Smarc USTPUTC(CTLBACKQ, out); 114047139Sbostic if (oldstyle) 114147139Sbostic goto parsebackq_oldreturn; 114247139Sbostic else 114347139Sbostic goto parsebackq_newreturn; 114447139Sbostic } 114547139Sbostic 114653302Smarc /* 114753302Smarc * Parse an arithmetic expansion (indicate start of one and set state) 114853302Smarc */ 114953302Smarc parsearith: { 115053302Smarc 115153302Smarc if (++arinest == 1) { 115253302Smarc prevsyntax = syntax; 115353302Smarc syntax = ARISYNTAX; 115453302Smarc USTPUTC(CTLARI, out); 115553302Smarc } else { 115653302Smarc /* 115753302Smarc * we collapse embedded arithmetic expansion to 115853302Smarc * parenthesis, which should be equivalent 115953302Smarc */ 116053302Smarc USTPUTC('(', out); 116153302Smarc } 116253302Smarc goto parsearith_return; 116353302Smarc } 116453302Smarc 116547139Sbostic } /* end of readtoken */ 116647139Sbostic 116747139Sbostic 116847139Sbostic 116947139Sbostic #ifdef mkinit 117047139Sbostic RESET { 117147139Sbostic tokpushback = 0; 1172*54322Smarc checkkwd = 0; 117347139Sbostic } 117447139Sbostic #endif 117547139Sbostic 117647139Sbostic /* 117747139Sbostic * Returns true if the text contains nothing to expand (no dollar signs 117847139Sbostic * or backquotes). 117947139Sbostic */ 118047139Sbostic 118147139Sbostic STATIC int 118247139Sbostic noexpand(text) 118347139Sbostic char *text; 118447139Sbostic { 118547139Sbostic register char *p; 118647139Sbostic register char c; 118747139Sbostic 118847139Sbostic p = text; 118947139Sbostic while ((c = *p++) != '\0') { 119047139Sbostic if (c == CTLESC) 119147139Sbostic p++; 119247139Sbostic else if (BASESYNTAX[c] == CCTL) 119347139Sbostic return 0; 119447139Sbostic } 119547139Sbostic return 1; 119647139Sbostic } 119747139Sbostic 119847139Sbostic 119947139Sbostic /* 120047139Sbostic * Return true if the argument is a legal variable name (a letter or 120147139Sbostic * underscore followed by zero or more letters, underscores, and digits). 120247139Sbostic */ 120347139Sbostic 120447139Sbostic int 120547139Sbostic goodname(name) 120647139Sbostic char *name; 120747139Sbostic { 120847139Sbostic register char *p; 120947139Sbostic 121047139Sbostic p = name; 121147139Sbostic if (! is_name(*p)) 121247139Sbostic return 0; 121347139Sbostic while (*++p) { 121447139Sbostic if (! is_in_name(*p)) 121547139Sbostic return 0; 121647139Sbostic } 121747139Sbostic return 1; 121847139Sbostic } 121947139Sbostic 122047139Sbostic 122147139Sbostic /* 122247139Sbostic * Called when an unexpected token is read during the parse. The argument 122347139Sbostic * is the token that is expected, or -1 if more than one type of token can 122447139Sbostic * occur at this point. 122547139Sbostic */ 122647139Sbostic 122747139Sbostic STATIC void 122847139Sbostic synexpect(token) { 122947139Sbostic char msg[64]; 123047139Sbostic 123147139Sbostic if (token >= 0) { 123247139Sbostic fmtstr(msg, 64, "%s unexpected (expecting %s)", 123347139Sbostic tokname[lasttoken], tokname[token]); 123447139Sbostic } else { 123547139Sbostic fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); 123647139Sbostic } 123747139Sbostic synerror(msg); 123847139Sbostic } 123947139Sbostic 124047139Sbostic 124147139Sbostic STATIC void 124247139Sbostic synerror(msg) 124347139Sbostic char *msg; 124447139Sbostic { 124547139Sbostic if (commandname) 124647139Sbostic outfmt(&errout, "%s: %d: ", commandname, startlinno); 124747139Sbostic outfmt(&errout, "Syntax error: %s\n", msg); 124847139Sbostic error((char *)NULL); 124947139Sbostic } 1250*54322Smarc 1251*54322Smarc STATIC void 1252*54322Smarc setprompt(which) 1253*54322Smarc int which; 1254*54322Smarc { 1255*54322Smarc whichprompt = which; 1256*54322Smarc 1257*54322Smarc if (!el) 1258*54322Smarc out2str(getprompt(NULL)); 1259*54322Smarc } 1260*54322Smarc 1261*54322Smarc /* 1262*54322Smarc * called by editline -- any expansions to the prompt 1263*54322Smarc * should be added here. 1264*54322Smarc */ 1265*54322Smarc char * 1266*54322Smarc getprompt(unused) 1267*54322Smarc void *unused; 1268*54322Smarc { 1269*54322Smarc switch (whichprompt) { 1270*54322Smarc case 0: 1271*54322Smarc return ""; 1272*54322Smarc case 1: 1273*54322Smarc return ps1val(); 1274*54322Smarc case 2: 1275*54322Smarc return ps2val(); 1276*54322Smarc default: 1277*54322Smarc return "<internal prompt error>"; 1278*54322Smarc } 1279*54322Smarc } 1280