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*53302Smarc static char sccsid[] = "@(#)parser.c 5.5 (Berkeley) 04/30/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" 2847139Sbostic 2947139Sbostic 3047139Sbostic /* 3147139Sbostic * Shell command parser. 3247139Sbostic */ 3347139Sbostic 3447139Sbostic #define EOFMARKLEN 79 3547139Sbostic 3647139Sbostic /* values returned by readtoken */ 3747139Sbostic #include "token.def" 3847139Sbostic 3947139Sbostic 4047139Sbostic 4147139Sbostic struct heredoc { 4247139Sbostic struct heredoc *next; /* next here document in list */ 4347139Sbostic union node *here; /* redirection node */ 4447139Sbostic char *eofmark; /* string indicating end of input */ 4547139Sbostic int striptabs; /* if set, strip leading tabs */ 4647139Sbostic }; 4747139Sbostic 4847139Sbostic 4947139Sbostic 5047139Sbostic struct heredoc *heredoclist; /* list of here documents to read */ 5147139Sbostic int parsebackquote; /* nonzero if we are inside backquotes */ 5247139Sbostic int doprompt; /* if set, prompt the user */ 5347139Sbostic int needprompt; /* true if interactive and at start of line */ 5447139Sbostic int lasttoken; /* last token read */ 5547139Sbostic MKINIT int tokpushback; /* last token pushed back */ 5647139Sbostic char *wordtext; /* text of last word returned by readtoken */ 5747981Smarc int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ 5847139Sbostic struct nodelist *backquotelist; 5947139Sbostic union node *redirnode; 6047139Sbostic struct heredoc *heredoc; 6147139Sbostic int quoteflag; /* set if (part of) last token was quoted */ 6247139Sbostic int startlinno; /* line # where last token started */ 6347139Sbostic 6447139Sbostic 6547139Sbostic #define GDB_HACK 1 /* avoid local declarations which gdb can't handle */ 6647139Sbostic #ifdef GDB_HACK 6747139Sbostic static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'}; 6847139Sbostic static const char types[] = "}-+?="; 6947139Sbostic #endif 7047139Sbostic 7147139Sbostic 7247981Smarc STATIC union node *list __P((int)); 7347981Smarc STATIC union node *andor __P((void)); 7447981Smarc STATIC union node *pipeline __P((void)); 7547981Smarc STATIC union node *command __P((void)); 7647981Smarc STATIC union node *simplecmd __P((void)); 7747981Smarc STATIC void parsefname __P((void)); 7847981Smarc STATIC void parseheredoc __P((void)); 7947981Smarc STATIC int readtoken __P((void)); 8047981Smarc STATIC int readtoken1 __P((int, char const *, char *, int)); 8147981Smarc STATIC void attyline __P((void)); 8247981Smarc STATIC int noexpand __P((char *)); 8347981Smarc STATIC void synexpect __P((int)); 8447981Smarc STATIC void synerror __P((char *)); 8547139Sbostic 8647139Sbostic #if ATTY 8747981Smarc STATIC void putprompt __P((char *)); 8847139Sbostic #else /* not ATTY */ 8947139Sbostic #define putprompt(s) out2str(s) 9047139Sbostic #endif 9147139Sbostic 9247139Sbostic 9347139Sbostic 9447139Sbostic 9547139Sbostic /* 9647139Sbostic * Read and parse a command. Returns NEOF on end of file. (NULL is a 9747139Sbostic * valid parse tree indicating a blank line.) 9847139Sbostic */ 9947139Sbostic 10047139Sbostic union node * 10147139Sbostic parsecmd(interact) { 10247139Sbostic int t; 10347139Sbostic 10447139Sbostic doprompt = interact; 10547139Sbostic if (doprompt) 10647139Sbostic putprompt(ps1val()); 10747139Sbostic needprompt = 0; 10847139Sbostic if ((t = readtoken()) == TEOF) 10947139Sbostic return NEOF; 11047139Sbostic if (t == TNL) 11147139Sbostic return NULL; 11247139Sbostic tokpushback++; 11347139Sbostic return list(1); 11447139Sbostic } 11547139Sbostic 11647139Sbostic 11747139Sbostic STATIC union node * 11847139Sbostic list(nlflag) { 11947139Sbostic union node *n1, *n2, *n3; 12047139Sbostic 12147981Smarc checkkwd = 2; 12247981Smarc if (nlflag == 0 && tokendlist[peektoken()]) 12347139Sbostic return NULL; 12447139Sbostic n1 = andor(); 12547139Sbostic for (;;) { 12647139Sbostic switch (readtoken()) { 12747139Sbostic case TBACKGND: 12847139Sbostic if (n1->type == NCMD || n1->type == NPIPE) { 12947139Sbostic n1->ncmd.backgnd = 1; 13047139Sbostic } else if (n1->type == NREDIR) { 13147139Sbostic n1->type = NBACKGND; 13247139Sbostic } else { 13347139Sbostic n3 = (union node *)stalloc(sizeof (struct nredir)); 13447139Sbostic n3->type = NBACKGND; 13547139Sbostic n3->nredir.n = n1; 13647139Sbostic n3->nredir.redirect = NULL; 13747139Sbostic n1 = n3; 13847139Sbostic } 13947139Sbostic goto tsemi; 14047139Sbostic case TNL: 14147139Sbostic tokpushback++; 14247139Sbostic /* fall through */ 14347139Sbostic tsemi: case TSEMI: 14447139Sbostic if (readtoken() == TNL) { 14547139Sbostic parseheredoc(); 14647139Sbostic if (nlflag) 14747139Sbostic return n1; 14847139Sbostic } else { 14947139Sbostic tokpushback++; 15047139Sbostic } 15147981Smarc checkkwd = 2; 15247981Smarc if (tokendlist[peektoken()]) 15347139Sbostic return n1; 15447139Sbostic n2 = andor(); 15547139Sbostic n3 = (union node *)stalloc(sizeof (struct nbinary)); 15647139Sbostic n3->type = NSEMI; 15747139Sbostic n3->nbinary.ch1 = n1; 15847139Sbostic n3->nbinary.ch2 = n2; 15947139Sbostic n1 = n3; 16047139Sbostic break; 16147139Sbostic case TEOF: 16247139Sbostic if (heredoclist) 16347139Sbostic parseheredoc(); 16447139Sbostic else 16547139Sbostic pungetc(); /* push back EOF on input */ 16647139Sbostic return n1; 16747139Sbostic default: 16847139Sbostic if (nlflag) 16947139Sbostic synexpect(-1); 17047139Sbostic tokpushback++; 17147139Sbostic return n1; 17247139Sbostic } 17347139Sbostic } 17447139Sbostic } 17547139Sbostic 17647139Sbostic 17747139Sbostic 17847139Sbostic STATIC union node * 17947139Sbostic andor() { 18047139Sbostic union node *n1, *n2, *n3; 18147139Sbostic int t; 18247139Sbostic 18347139Sbostic n1 = pipeline(); 18447139Sbostic for (;;) { 18547139Sbostic if ((t = readtoken()) == TAND) { 18647139Sbostic t = NAND; 18747139Sbostic } else if (t == TOR) { 18847139Sbostic t = NOR; 18947139Sbostic } else { 19047139Sbostic tokpushback++; 19147139Sbostic return n1; 19247139Sbostic } 19347139Sbostic n2 = pipeline(); 19447139Sbostic n3 = (union node *)stalloc(sizeof (struct nbinary)); 19547139Sbostic n3->type = t; 19647139Sbostic n3->nbinary.ch1 = n1; 19747139Sbostic n3->nbinary.ch2 = n2; 19847139Sbostic n1 = n3; 19947139Sbostic } 20047139Sbostic } 20147139Sbostic 20247139Sbostic 20347139Sbostic 20447139Sbostic STATIC union node * 20547139Sbostic pipeline() { 20653178Smarc union node *n1, *pipenode, *notnode; 20747139Sbostic struct nodelist *lp, *prev; 20853178Smarc int negate = 0; 20947139Sbostic 21053178Smarc TRACE(("pipeline: entered\n")); 21153178Smarc while (readtoken() == TNOT) { 21253178Smarc TRACE(("pipeline: TNOT recognized\n")); 21353178Smarc negate = !negate; 21453178Smarc } 21553178Smarc tokpushback++; 21647139Sbostic n1 = command(); 21747139Sbostic if (readtoken() == TPIPE) { 21847139Sbostic pipenode = (union node *)stalloc(sizeof (struct npipe)); 21947139Sbostic pipenode->type = NPIPE; 22047139Sbostic pipenode->npipe.backgnd = 0; 22147139Sbostic lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 22247139Sbostic pipenode->npipe.cmdlist = lp; 22347139Sbostic lp->n = n1; 22447139Sbostic do { 22547139Sbostic prev = lp; 22647139Sbostic lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 22747139Sbostic lp->n = command(); 22847139Sbostic prev->next = lp; 22947139Sbostic } while (readtoken() == TPIPE); 23047139Sbostic lp->next = NULL; 23147139Sbostic n1 = pipenode; 23247139Sbostic } 23347139Sbostic tokpushback++; 23453178Smarc if (negate) { 23553178Smarc notnode = (union node *)stalloc(sizeof (struct nnot)); 23653178Smarc notnode->type = NNOT; 23753178Smarc notnode->nnot.com = n1; 23853178Smarc n1 = notnode; 23953178Smarc } 24047139Sbostic return n1; 24147139Sbostic } 24247139Sbostic 24347139Sbostic 24447139Sbostic 24547139Sbostic STATIC union node * 24647139Sbostic command() { 24747139Sbostic union node *n1, *n2; 24847139Sbostic union node *ap, **app; 24947139Sbostic union node *cp, **cpp; 25047139Sbostic union node *redir, **rpp; 25147139Sbostic int t; 25247139Sbostic 25347981Smarc checkkwd = 2; 25447139Sbostic switch (readtoken()) { 25547139Sbostic case TIF: 25647139Sbostic n1 = (union node *)stalloc(sizeof (struct nif)); 25747139Sbostic n1->type = NIF; 25847139Sbostic n1->nif.test = list(0); 25947139Sbostic if (readtoken() != TTHEN) 26047139Sbostic synexpect(TTHEN); 26147139Sbostic n1->nif.ifpart = list(0); 26247139Sbostic n2 = n1; 26347139Sbostic while (readtoken() == TELIF) { 26447139Sbostic n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); 26547139Sbostic n2 = n2->nif.elsepart; 26647139Sbostic n2->type = NIF; 26747139Sbostic n2->nif.test = list(0); 26847139Sbostic if (readtoken() != TTHEN) 26947139Sbostic synexpect(TTHEN); 27047139Sbostic n2->nif.ifpart = list(0); 27147139Sbostic } 27247139Sbostic if (lasttoken == TELSE) 27347139Sbostic n2->nif.elsepart = list(0); 27447139Sbostic else { 27547139Sbostic n2->nif.elsepart = NULL; 27647139Sbostic tokpushback++; 27747139Sbostic } 27847139Sbostic if (readtoken() != TFI) 27947139Sbostic synexpect(TFI); 28047981Smarc checkkwd = 1; 28147139Sbostic break; 28247139Sbostic case TWHILE: 28347981Smarc case TUNTIL: { 28447981Smarc int got; 28547139Sbostic n1 = (union node *)stalloc(sizeof (struct nbinary)); 28647139Sbostic n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; 28747139Sbostic n1->nbinary.ch1 = list(0); 28847981Smarc if ((got=readtoken()) != TDO) { 28947981Smarc TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); 29047139Sbostic synexpect(TDO); 29147981Smarc } 29247139Sbostic n1->nbinary.ch2 = list(0); 29347139Sbostic if (readtoken() != TDONE) 29447139Sbostic synexpect(TDONE); 29547981Smarc checkkwd = 1; 29647139Sbostic break; 29747981Smarc } 29847139Sbostic case TFOR: 29947139Sbostic if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) 30047139Sbostic synerror("Bad for loop variable"); 30147139Sbostic n1 = (union node *)stalloc(sizeof (struct nfor)); 30247139Sbostic n1->type = NFOR; 30347139Sbostic n1->nfor.var = wordtext; 30447139Sbostic if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { 30547139Sbostic app = ≈ 30647139Sbostic while (readtoken() == TWORD) { 30747139Sbostic n2 = (union node *)stalloc(sizeof (struct narg)); 30847139Sbostic n2->type = NARG; 30947139Sbostic n2->narg.text = wordtext; 31047139Sbostic n2->narg.backquote = backquotelist; 31147139Sbostic *app = n2; 31247139Sbostic app = &n2->narg.next; 31347139Sbostic } 31447139Sbostic *app = NULL; 31547139Sbostic n1->nfor.args = ap; 31647139Sbostic } else { 31747139Sbostic #ifndef GDB_HACK 31847139Sbostic static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, 31947139Sbostic '@', '=', '\0'}; 32047139Sbostic #endif 32147139Sbostic n2 = (union node *)stalloc(sizeof (struct narg)); 32247139Sbostic n2->type = NARG; 32347139Sbostic n2->narg.text = (char *)argvars; 32447139Sbostic n2->narg.backquote = NULL; 32547139Sbostic n2->narg.next = NULL; 32647139Sbostic n1->nfor.args = n2; 32747139Sbostic } 32847139Sbostic if (lasttoken != TNL && lasttoken != TSEMI) 32947139Sbostic synexpect(-1); 33047981Smarc checkkwd = 2; 33147139Sbostic if ((t = readtoken()) == TDO) 33247139Sbostic t = TDONE; 33347139Sbostic else if (t == TBEGIN) 33447139Sbostic t = TEND; 33547139Sbostic else 33647139Sbostic synexpect(-1); 33747139Sbostic n1->nfor.body = list(0); 33847139Sbostic if (readtoken() != t) 33947139Sbostic synexpect(t); 34047981Smarc checkkwd = 1; 34147139Sbostic break; 34247139Sbostic case TCASE: 34347139Sbostic n1 = (union node *)stalloc(sizeof (struct ncase)); 34447139Sbostic n1->type = NCASE; 34547139Sbostic if (readtoken() != TWORD) 34647139Sbostic synexpect(TWORD); 34747139Sbostic n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); 34847139Sbostic n2->type = NARG; 34947139Sbostic n2->narg.text = wordtext; 35047139Sbostic n2->narg.backquote = backquotelist; 35147139Sbostic n2->narg.next = NULL; 35247139Sbostic while (readtoken() == TNL); 35347139Sbostic if (lasttoken != TWORD || ! equal(wordtext, "in")) 35447139Sbostic synerror("expecting \"in\""); 35547139Sbostic cpp = &n1->ncase.cases; 35647981Smarc while (checkkwd = 2, readtoken() == TWORD) { 35747139Sbostic *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); 35847139Sbostic cp->type = NCLIST; 35947139Sbostic app = &cp->nclist.pattern; 36047139Sbostic for (;;) { 36147139Sbostic *app = ap = (union node *)stalloc(sizeof (struct narg)); 36247139Sbostic ap->type = NARG; 36347139Sbostic ap->narg.text = wordtext; 36447139Sbostic ap->narg.backquote = backquotelist; 36547139Sbostic if (readtoken() != TPIPE) 36647139Sbostic break; 36747139Sbostic app = &ap->narg.next; 36847139Sbostic if (readtoken() != TWORD) 36947139Sbostic synexpect(TWORD); 37047139Sbostic } 37147139Sbostic ap->narg.next = NULL; 37247139Sbostic if (lasttoken != TRP) 37347139Sbostic synexpect(TRP); 37447139Sbostic cp->nclist.body = list(0); 37547139Sbostic if ((t = readtoken()) == TESAC) 37647139Sbostic tokpushback++; 37747139Sbostic else if (t != TENDCASE) 37847139Sbostic synexpect(TENDCASE); 37947139Sbostic cpp = &cp->nclist.next; 38047139Sbostic } 38147139Sbostic *cpp = NULL; 38247139Sbostic if (lasttoken != TESAC) 38347139Sbostic synexpect(TESAC); 38447981Smarc checkkwd = 1; 38547139Sbostic break; 38647139Sbostic case TLP: 38747139Sbostic n1 = (union node *)stalloc(sizeof (struct nredir)); 38847139Sbostic n1->type = NSUBSHELL; 38947139Sbostic n1->nredir.n = list(0); 39047139Sbostic n1->nredir.redirect = NULL; 39147139Sbostic if (readtoken() != TRP) 39247139Sbostic synexpect(TRP); 39347981Smarc checkkwd = 1; 39447139Sbostic break; 39547139Sbostic case TBEGIN: 39647139Sbostic n1 = list(0); 39747139Sbostic if (readtoken() != TEND) 39847139Sbostic synexpect(TEND); 39947981Smarc checkkwd = 1; 40047139Sbostic break; 40147139Sbostic case TWORD: 40247139Sbostic case TREDIR: 40347139Sbostic tokpushback++; 40447139Sbostic return simplecmd(); 40547139Sbostic default: 40647139Sbostic synexpect(-1); 40747139Sbostic } 40847139Sbostic 40947139Sbostic /* Now check for redirection which may follow command */ 41047139Sbostic rpp = &redir; 41147139Sbostic while (readtoken() == TREDIR) { 41247139Sbostic *rpp = n2 = redirnode; 41347139Sbostic rpp = &n2->nfile.next; 41447139Sbostic parsefname(); 41547139Sbostic } 41647139Sbostic tokpushback++; 41747139Sbostic *rpp = NULL; 41847139Sbostic if (redir) { 41947139Sbostic if (n1->type != NSUBSHELL) { 42047139Sbostic n2 = (union node *)stalloc(sizeof (struct nredir)); 42147139Sbostic n2->type = NREDIR; 42247139Sbostic n2->nredir.n = n1; 42347139Sbostic n1 = n2; 42447139Sbostic } 42547139Sbostic n1->nredir.redirect = redir; 42647139Sbostic } 42747139Sbostic return n1; 42847139Sbostic } 42947139Sbostic 43047139Sbostic 43147139Sbostic STATIC union node * 43247139Sbostic simplecmd() { 43347139Sbostic union node *args, **app; 43447139Sbostic union node *redir, **rpp; 43547139Sbostic union node *n; 43647139Sbostic 43747139Sbostic args = NULL; 43847139Sbostic app = &args; 43947139Sbostic rpp = &redir; 44047139Sbostic for (;;) { 44147139Sbostic if (readtoken() == TWORD) { 44247139Sbostic n = (union node *)stalloc(sizeof (struct narg)); 44347139Sbostic n->type = NARG; 44447139Sbostic n->narg.text = wordtext; 44547139Sbostic n->narg.backquote = backquotelist; 44647139Sbostic *app = n; 44747139Sbostic app = &n->narg.next; 44847139Sbostic } else if (lasttoken == TREDIR) { 44947139Sbostic *rpp = n = redirnode; 45047139Sbostic rpp = &n->nfile.next; 45147139Sbostic parsefname(); /* read name of redirection file */ 45247139Sbostic } else if (lasttoken == TLP && app == &args->narg.next 45347139Sbostic && rpp == &redir) { 45447139Sbostic /* We have a function */ 45547139Sbostic if (readtoken() != TRP) 45647139Sbostic synexpect(TRP); 45747300Smarc #ifdef notdef 45847139Sbostic if (! goodname(n->narg.text)) 45947139Sbostic synerror("Bad function name"); 46047300Smarc #endif 46147139Sbostic n->type = NDEFUN; 46247139Sbostic n->narg.next = command(); 46347139Sbostic return n; 46447139Sbostic } else { 46547139Sbostic tokpushback++; 46647139Sbostic break; 46747139Sbostic } 46847139Sbostic } 46947139Sbostic *app = NULL; 47047139Sbostic *rpp = NULL; 47147139Sbostic n = (union node *)stalloc(sizeof (struct ncmd)); 47247139Sbostic n->type = NCMD; 47347139Sbostic n->ncmd.backgnd = 0; 47447139Sbostic n->ncmd.args = args; 47547139Sbostic n->ncmd.redirect = redir; 47647139Sbostic return n; 47747139Sbostic } 47847139Sbostic 47947139Sbostic 48047139Sbostic STATIC void 48147139Sbostic parsefname() { 48247139Sbostic union node *n = redirnode; 48347139Sbostic 48447139Sbostic if (readtoken() != TWORD) 48547139Sbostic synexpect(-1); 48647139Sbostic if (n->type == NHERE) { 48747139Sbostic struct heredoc *here = heredoc; 48847139Sbostic struct heredoc *p; 48947139Sbostic int i; 49047139Sbostic 49147139Sbostic if (quoteflag == 0) 49247139Sbostic n->type = NXHERE; 49347139Sbostic TRACE(("Here document %d\n", n->type)); 49447139Sbostic if (here->striptabs) { 49547139Sbostic while (*wordtext == '\t') 49647139Sbostic wordtext++; 49747139Sbostic } 49847139Sbostic if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) 49947139Sbostic synerror("Illegal eof marker for << redirection"); 50047139Sbostic rmescapes(wordtext); 50147139Sbostic here->eofmark = wordtext; 50247139Sbostic here->next = NULL; 50347139Sbostic if (heredoclist == NULL) 50447139Sbostic heredoclist = here; 50547139Sbostic else { 50647139Sbostic for (p = heredoclist ; p->next ; p = p->next); 50747139Sbostic p->next = here; 50847139Sbostic } 50947139Sbostic } else if (n->type == NTOFD || n->type == NFROMFD) { 51047139Sbostic if (is_digit(wordtext[0])) 51147139Sbostic n->ndup.dupfd = digit_val(wordtext[0]); 51247139Sbostic else if (wordtext[0] == '-') 51347139Sbostic n->ndup.dupfd = -1; 51447139Sbostic else 51547139Sbostic goto bad; 51647139Sbostic if (wordtext[1] != '\0') { 51747139Sbostic bad: 51847139Sbostic synerror("Bad fd number"); 51947139Sbostic } 52047139Sbostic } else { 52147139Sbostic n->nfile.fname = (union node *)stalloc(sizeof (struct narg)); 52247139Sbostic n = n->nfile.fname; 52347139Sbostic n->type = NARG; 52447139Sbostic n->narg.next = NULL; 52547139Sbostic n->narg.text = wordtext; 52647139Sbostic n->narg.backquote = backquotelist; 52747139Sbostic } 52847139Sbostic } 52947139Sbostic 53047139Sbostic 53147139Sbostic /* 53247139Sbostic * Input any here documents. 53347139Sbostic */ 53447139Sbostic 53547139Sbostic STATIC void 53647139Sbostic parseheredoc() { 53747139Sbostic struct heredoc *here; 53847139Sbostic union node *n; 53947139Sbostic 54047139Sbostic while (heredoclist) { 54147139Sbostic here = heredoclist; 54247139Sbostic heredoclist = here->next; 54347139Sbostic if (needprompt) { 54447139Sbostic putprompt(ps2val()); 54547139Sbostic needprompt = 0; 54647139Sbostic } 54747139Sbostic readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, 54847139Sbostic here->eofmark, here->striptabs); 54947139Sbostic n = (union node *)stalloc(sizeof (struct narg)); 55047139Sbostic n->narg.type = NARG; 55147139Sbostic n->narg.next = NULL; 55247139Sbostic n->narg.text = wordtext; 55347139Sbostic n->narg.backquote = backquotelist; 55447139Sbostic here->here->nhere.doc = n; 55547139Sbostic } 55647139Sbostic } 55747139Sbostic 55847981Smarc STATIC int 55947981Smarc peektoken() { 56047139Sbostic int t; 56147139Sbostic 56247981Smarc t = readtoken(); 56347139Sbostic tokpushback++; 56447981Smarc return (t); 56547139Sbostic } 56647139Sbostic 56747139Sbostic STATIC int xxreadtoken(); 56847139Sbostic 56947139Sbostic STATIC int 57047139Sbostic readtoken() { 57147139Sbostic int t; 57247981Smarc #ifdef DEBUG 57347981Smarc int alreadyseen = tokpushback; 57447981Smarc #endif 57547981Smarc 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 /* 59147981Smarc * check for keywords 59247981Smarc */ 59347981Smarc if (t == TWORD && !quoteflag) { 59447981Smarc register char **pp; 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])); 60047981Smarc break; 60147981Smarc } 60247981Smarc } 60347981Smarc } 60447139Sbostic } 60547981Smarc #ifdef DEBUG 60647981Smarc if (!alreadyseen) 60747981Smarc TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 60847981Smarc else 60947981Smarc TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); 61047981Smarc #endif 61147981Smarc return (t); 61247139Sbostic } 61347139Sbostic 61447139Sbostic 61547139Sbostic /* 61647139Sbostic * Read the next input token. 61747139Sbostic * If the token is a word, we set backquotelist to the list of cmds in 61847139Sbostic * backquotes. We set quoteflag to true if any part of the word was 61947139Sbostic * quoted. 62047139Sbostic * If the token is TREDIR, then we set redirnode to a structure containing 62147139Sbostic * the redirection. 62247139Sbostic * In all cases, the variable startlinno is set to the number of the line 62347139Sbostic * on which the token starts. 62447139Sbostic * 62547139Sbostic * [Change comment: here documents and internal procedures] 62647139Sbostic * [Readtoken shouldn't have any arguments. Perhaps we should make the 62747139Sbostic * word parsing code into a separate routine. In this case, readtoken 62847139Sbostic * doesn't need to have any internal procedures, but parseword does. 62947139Sbostic * We could also make parseoperator in essence the main routine, and 63047139Sbostic * have parseword (readtoken1?) handle both words and redirection.] 63147139Sbostic */ 63247139Sbostic 63347139Sbostic #define RETURN(token) return lasttoken = token 63447139Sbostic 63547139Sbostic STATIC int 63647139Sbostic xxreadtoken() { 63747139Sbostic register c; 63847139Sbostic 63947139Sbostic if (tokpushback) { 64047139Sbostic tokpushback = 0; 64147139Sbostic return lasttoken; 64247139Sbostic } 64347139Sbostic if (needprompt) { 64447139Sbostic putprompt(ps2val()); 64547139Sbostic needprompt = 0; 64647139Sbostic } 64747139Sbostic startlinno = plinno; 64847139Sbostic for (;;) { /* until token or start of word found */ 64947139Sbostic c = pgetc_macro(); 65047139Sbostic if (c == ' ' || c == '\t') 65147139Sbostic continue; /* quick check for white space first */ 65247139Sbostic switch (c) { 65347139Sbostic case ' ': case '\t': 65447139Sbostic continue; 65547139Sbostic case '#': 65647139Sbostic while ((c = pgetc()) != '\n' && c != PEOF); 65747139Sbostic pungetc(); 65847139Sbostic continue; 65947139Sbostic case '\\': 66047139Sbostic if (pgetc() == '\n') { 66147139Sbostic startlinno = ++plinno; 66247139Sbostic if (doprompt) 66347139Sbostic putprompt(ps2val()); 66447139Sbostic continue; 66547139Sbostic } 66647139Sbostic pungetc(); 66747139Sbostic goto breakloop; 66847139Sbostic case '\n': 66947139Sbostic plinno++; 67047139Sbostic needprompt = doprompt; 67147139Sbostic RETURN(TNL); 67247139Sbostic case PEOF: 67347139Sbostic RETURN(TEOF); 67447139Sbostic case '&': 67547139Sbostic if (pgetc() == '&') 67647139Sbostic RETURN(TAND); 67747139Sbostic pungetc(); 67847139Sbostic RETURN(TBACKGND); 67947139Sbostic case '|': 68047139Sbostic if (pgetc() == '|') 68147139Sbostic RETURN(TOR); 68247139Sbostic pungetc(); 68347139Sbostic RETURN(TPIPE); 68447139Sbostic case ';': 68547139Sbostic if (pgetc() == ';') 68647139Sbostic RETURN(TENDCASE); 68747139Sbostic pungetc(); 68847139Sbostic RETURN(TSEMI); 68947139Sbostic case '(': 69047139Sbostic RETURN(TLP); 69147139Sbostic case ')': 69247139Sbostic RETURN(TRP); 69347139Sbostic default: 69447139Sbostic goto breakloop; 69547139Sbostic } 69647139Sbostic } 69747139Sbostic breakloop: 69847139Sbostic return readtoken1(c, BASESYNTAX, (char *)NULL, 0); 69947139Sbostic #undef RETURN 70047139Sbostic } 70147139Sbostic 70247139Sbostic 70347139Sbostic 70447139Sbostic /* 70547139Sbostic * If eofmark is NULL, read a word or a redirection symbol. If eofmark 70647139Sbostic * is not NULL, read a here document. In the latter case, eofmark is the 70747139Sbostic * word which marks the end of the document and striptabs is true if 70847139Sbostic * leading tabs should be stripped from the document. The argument firstc 70947139Sbostic * is the first character of the input token or document. 71047139Sbostic * 71147139Sbostic * Because C does not have internal subroutines, I have simulated them 71247139Sbostic * using goto's to implement the subroutine linkage. The following macros 71347139Sbostic * will run code that appears at the end of readtoken1. 71447139Sbostic */ 71547139Sbostic 71647139Sbostic #define CHECKEND() {goto checkend; checkend_return:;} 71747139Sbostic #define PARSEREDIR() {goto parseredir; parseredir_return:;} 71847139Sbostic #define PARSESUB() {goto parsesub; parsesub_return:;} 71947139Sbostic #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} 72047139Sbostic #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} 721*53302Smarc #define PARSEARITH() {goto parsearith; parsearith_return:;} 72247139Sbostic 72347139Sbostic STATIC int 72447139Sbostic readtoken1(firstc, syntax, eofmark, striptabs) 72547139Sbostic int firstc; 72647139Sbostic char const *syntax; 72747139Sbostic char *eofmark; 72847139Sbostic int striptabs; 72947139Sbostic { 73047139Sbostic register c = firstc; 73147139Sbostic register char *out; 73247139Sbostic int len; 73347139Sbostic char line[EOFMARKLEN + 1]; 73447139Sbostic struct nodelist *bqlist; 73547139Sbostic int quotef; 73647139Sbostic int dblquote; 737*53302Smarc int varnest; /* levels of variables expansion */ 738*53302Smarc int arinest; /* levels of arithmetic expansion */ 739*53302Smarc int parenlevel; /* levels of parens in arithmetic */ 74047139Sbostic int oldstyle; 741*53302Smarc char const *prevsyntax; /* syntax before arithmetic */ 74247139Sbostic 74347139Sbostic startlinno = plinno; 74447139Sbostic dblquote = 0; 74547139Sbostic if (syntax == DQSYNTAX) 74647139Sbostic dblquote = 1; 74747139Sbostic quotef = 0; 74847139Sbostic bqlist = NULL; 74947139Sbostic varnest = 0; 750*53302Smarc arinest = 0; 751*53302Smarc parenlevel = 0; 752*53302Smarc 75347139Sbostic STARTSTACKSTR(out); 75447139Sbostic loop: { /* for each line, until end of word */ 75547139Sbostic #if ATTY 75647139Sbostic if (c == '\034' && doprompt 75747139Sbostic && attyset() && ! equal(termval(), "emacs")) { 75847139Sbostic attyline(); 75947139Sbostic if (syntax == BASESYNTAX) 76047139Sbostic return readtoken(); 76147139Sbostic c = pgetc(); 76247139Sbostic goto loop; 76347139Sbostic } 76447139Sbostic #endif 76547139Sbostic CHECKEND(); /* set c to PEOF if at end of here document */ 76647139Sbostic for (;;) { /* until end of line or end of word */ 76747139Sbostic CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ 76847139Sbostic switch(syntax[c]) { 76947139Sbostic case CNL: /* '\n' */ 77047139Sbostic if (syntax == BASESYNTAX) 77147139Sbostic goto endword; /* exit outer loop */ 77247139Sbostic USTPUTC(c, out); 77347139Sbostic plinno++; 77447139Sbostic if (doprompt) { 77547139Sbostic putprompt(ps2val()); 77647139Sbostic } 77747139Sbostic c = pgetc(); 77847139Sbostic goto loop; /* continue outer loop */ 77947139Sbostic case CWORD: 78047139Sbostic USTPUTC(c, out); 78147139Sbostic break; 78247139Sbostic case CCTL: 78347139Sbostic if (eofmark == NULL || dblquote) 78447139Sbostic USTPUTC(CTLESC, out); 78547139Sbostic USTPUTC(c, out); 78647139Sbostic break; 78747139Sbostic case CBACK: /* backslash */ 78847139Sbostic c = pgetc(); 78947139Sbostic if (c == PEOF) { 79047139Sbostic USTPUTC('\\', out); 79147139Sbostic pungetc(); 79247139Sbostic } else if (c == '\n') { 79347139Sbostic if (doprompt) 79447139Sbostic putprompt(ps2val()); 79547139Sbostic } else { 79647139Sbostic if (dblquote && c != '\\' && c != '`' && c != '$' 79747139Sbostic && (c != '"' || eofmark != NULL)) 79847139Sbostic USTPUTC('\\', out); 79947139Sbostic if (SQSYNTAX[c] == CCTL) 80047139Sbostic USTPUTC(CTLESC, out); 80147139Sbostic USTPUTC(c, out); 80247139Sbostic quotef++; 80347139Sbostic } 80447139Sbostic break; 80547139Sbostic case CSQUOTE: 80647139Sbostic syntax = SQSYNTAX; 80747139Sbostic break; 80847139Sbostic case CDQUOTE: 80947139Sbostic syntax = DQSYNTAX; 81047139Sbostic dblquote = 1; 81147139Sbostic break; 81247139Sbostic case CENDQUOTE: 81347139Sbostic if (eofmark) { 81447139Sbostic USTPUTC(c, out); 81547139Sbostic } else { 816*53302Smarc if (arinest) 817*53302Smarc syntax = ARISYNTAX; 818*53302Smarc else 819*53302Smarc syntax = BASESYNTAX; 82047139Sbostic quotef++; 82147139Sbostic dblquote = 0; 82247139Sbostic } 82347139Sbostic break; 82447139Sbostic case CVAR: /* '$' */ 82547139Sbostic PARSESUB(); /* parse substitution */ 82647139Sbostic break; 82747139Sbostic case CENDVAR: /* '}' */ 82847139Sbostic if (varnest > 0) { 82947139Sbostic varnest--; 83047139Sbostic USTPUTC(CTLENDVAR, out); 83147139Sbostic } else { 83247139Sbostic USTPUTC(c, out); 83347139Sbostic } 83447139Sbostic break; 835*53302Smarc case CLP: /* '(' in arithmetic */ 836*53302Smarc parenlevel++; 837*53302Smarc USTPUTC(c, out); 838*53302Smarc break; 839*53302Smarc case CRP: /* ')' in arithmetic */ 840*53302Smarc if (parenlevel > 0) { 841*53302Smarc USTPUTC(c, out); 842*53302Smarc --parenlevel; 843*53302Smarc } else { 844*53302Smarc if (pgetc() == ')') { 845*53302Smarc if (--arinest == 0) { 846*53302Smarc USTPUTC(CTLENDARI, out); 847*53302Smarc syntax = prevsyntax; 848*53302Smarc } else 849*53302Smarc USTPUTC(')', out); 850*53302Smarc } else { 851*53302Smarc /* 852*53302Smarc * unbalanced parens 853*53302Smarc * (don't 2nd guess - no error) 854*53302Smarc */ 855*53302Smarc pungetc(); 856*53302Smarc USTPUTC(')', out); 857*53302Smarc } 858*53302Smarc } 859*53302Smarc break; 86047139Sbostic case CBQUOTE: /* '`' */ 86147139Sbostic if (parsebackquote && syntax == BASESYNTAX) { 86247139Sbostic if (out == stackblock()) 86347139Sbostic return lasttoken = TENDBQUOTE; 86447139Sbostic else 86547139Sbostic goto endword; /* exit outer loop */ 86647139Sbostic } 86747139Sbostic PARSEBACKQOLD(); 86847139Sbostic break; 86947139Sbostic case CEOF: 87047139Sbostic goto endword; /* exit outer loop */ 87147139Sbostic default: 87247139Sbostic if (varnest == 0) 87347139Sbostic goto endword; /* exit outer loop */ 87447139Sbostic USTPUTC(c, out); 87547139Sbostic } 87647139Sbostic c = pgetc_macro(); 87747139Sbostic } 87847139Sbostic } 87947139Sbostic endword: 880*53302Smarc if (syntax == ARISYNTAX) 881*53302Smarc synerror("Missing '))'"); 88247139Sbostic if (syntax != BASESYNTAX && eofmark == NULL) 88347139Sbostic synerror("Unterminated quoted string"); 88447139Sbostic if (varnest != 0) { 88547139Sbostic startlinno = plinno; 88647139Sbostic synerror("Missing '}'"); 88747139Sbostic } 88847139Sbostic USTPUTC('\0', out); 88947139Sbostic len = out - stackblock(); 89047139Sbostic out = stackblock(); 89147139Sbostic if (eofmark == NULL) { 89247139Sbostic if ((c == '>' || c == '<') 89347139Sbostic && quotef == 0 89447139Sbostic && len <= 2 89547139Sbostic && (*out == '\0' || is_digit(*out))) { 89647139Sbostic PARSEREDIR(); 89747139Sbostic return lasttoken = TREDIR; 89847139Sbostic } else { 89947139Sbostic pungetc(); 90047139Sbostic } 90147139Sbostic } 90247139Sbostic quoteflag = quotef; 90347139Sbostic backquotelist = bqlist; 90447139Sbostic grabstackblock(len); 90547139Sbostic wordtext = out; 90647139Sbostic return lasttoken = TWORD; 90747139Sbostic /* end of readtoken routine */ 90847139Sbostic 90947139Sbostic 91047139Sbostic 91147139Sbostic /* 91247139Sbostic * Check to see whether we are at the end of the here document. When this 91347139Sbostic * is called, c is set to the first character of the next input line. If 91447139Sbostic * we are at the end of the here document, this routine sets the c to PEOF. 91547139Sbostic */ 91647139Sbostic 91747139Sbostic checkend: { 91847139Sbostic if (eofmark) { 91947139Sbostic if (striptabs) { 92047139Sbostic while (c == '\t') 92147139Sbostic c = pgetc(); 92247139Sbostic } 92347139Sbostic if (c == *eofmark) { 92447139Sbostic if (pfgets(line, sizeof line) != NULL) { 92547139Sbostic register char *p, *q; 92647139Sbostic 92747139Sbostic p = line; 92847139Sbostic for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); 92947139Sbostic if (*p == '\n' && *q == '\0') { 93047139Sbostic c = PEOF; 93147139Sbostic plinno++; 93247139Sbostic needprompt = doprompt; 93347139Sbostic } else { 93447139Sbostic ppushback(line, strlen(line)); 93547139Sbostic } 93647139Sbostic } 93747139Sbostic } 93847139Sbostic } 93947139Sbostic goto checkend_return; 94047139Sbostic } 94147139Sbostic 94247139Sbostic 94347139Sbostic /* 94447139Sbostic * Parse a redirection operator. The variable "out" points to a string 94547139Sbostic * specifying the fd to be redirected. The variable "c" contains the 94647139Sbostic * first character of the redirection operator. 94747139Sbostic */ 94847139Sbostic 94947139Sbostic parseredir: { 95047139Sbostic char fd = *out; 95147139Sbostic union node *np; 95247139Sbostic 95347139Sbostic np = (union node *)stalloc(sizeof (struct nfile)); 95447139Sbostic if (c == '>') { 95547139Sbostic np->nfile.fd = 1; 95647139Sbostic c = pgetc(); 95747139Sbostic if (c == '>') 95847139Sbostic np->type = NAPPEND; 95947139Sbostic else if (c == '&') 96047139Sbostic np->type = NTOFD; 96147139Sbostic else { 96247139Sbostic np->type = NTO; 96347139Sbostic pungetc(); 96447139Sbostic } 96547139Sbostic } else { /* c == '<' */ 96647139Sbostic np->nfile.fd = 0; 96747139Sbostic c = pgetc(); 96847139Sbostic if (c == '<') { 96947139Sbostic if (sizeof (struct nfile) != sizeof (struct nhere)) { 97047139Sbostic np = (union node *)stalloc(sizeof (struct nhere)); 97147139Sbostic np->nfile.fd = 0; 97247139Sbostic } 97347139Sbostic np->type = NHERE; 97447139Sbostic heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); 97547139Sbostic heredoc->here = np; 97647139Sbostic if ((c = pgetc()) == '-') { 97747139Sbostic heredoc->striptabs = 1; 97847139Sbostic } else { 97947139Sbostic heredoc->striptabs = 0; 98047139Sbostic pungetc(); 98147139Sbostic } 98247139Sbostic } else if (c == '&') 98347139Sbostic np->type = NFROMFD; 98447139Sbostic else { 98547139Sbostic np->type = NFROM; 98647139Sbostic pungetc(); 98747139Sbostic } 98847139Sbostic } 98947139Sbostic if (fd != '\0') 99047139Sbostic np->nfile.fd = digit_val(fd); 99147139Sbostic redirnode = np; 99247139Sbostic goto parseredir_return; 99347139Sbostic } 99447139Sbostic 99547139Sbostic 99647139Sbostic /* 99747139Sbostic * Parse a substitution. At this point, we have read the dollar sign 99847139Sbostic * and nothing else. 99947139Sbostic */ 100047139Sbostic 100147139Sbostic parsesub: { 100247139Sbostic int subtype; 100347139Sbostic int typeloc; 100447139Sbostic int flags; 100547139Sbostic char *p; 100647139Sbostic #ifndef GDB_HACK 100747139Sbostic static const char types[] = "}-+?="; 100847139Sbostic #endif 100947139Sbostic 101047139Sbostic c = pgetc(); 101147300Smarc if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) { 101247139Sbostic USTPUTC('$', out); 101347139Sbostic pungetc(); 1014*53302Smarc } else if (c == '(') { /* $(command) or $((arith)) */ 1015*53302Smarc if (pgetc() == '(') { 1016*53302Smarc PARSEARITH(); 1017*53302Smarc } else { 1018*53302Smarc pungetc(); 1019*53302Smarc PARSEBACKQNEW(); 1020*53302Smarc } 102147139Sbostic } else { 102247139Sbostic USTPUTC(CTLVAR, out); 102347139Sbostic typeloc = out - stackblock(); 102447139Sbostic USTPUTC(VSNORMAL, out); 102547139Sbostic subtype = VSNORMAL; 102647139Sbostic if (c == '{') { 102747139Sbostic c = pgetc(); 102847139Sbostic subtype = 0; 102947139Sbostic } 103047139Sbostic if (is_name(c)) { 103147139Sbostic do { 103247139Sbostic STPUTC(c, out); 103347139Sbostic c = pgetc(); 103447139Sbostic } while (is_in_name(c)); 103547139Sbostic } else { 103647139Sbostic if (! is_special(c)) 103747300Smarc badsub: synerror("Bad substitution"); 103847139Sbostic USTPUTC(c, out); 103947139Sbostic c = pgetc(); 104047139Sbostic } 104147139Sbostic STPUTC('=', out); 104247139Sbostic flags = 0; 104347139Sbostic if (subtype == 0) { 104447139Sbostic if (c == ':') { 104547139Sbostic flags = VSNUL; 104647139Sbostic c = pgetc(); 104747139Sbostic } 104847139Sbostic p = strchr(types, c); 104947139Sbostic if (p == NULL) 105047139Sbostic goto badsub; 105147139Sbostic subtype = p - types + VSNORMAL; 105247139Sbostic } else { 105347139Sbostic pungetc(); 105447139Sbostic } 1055*53302Smarc if (dblquote || arinest) 105647139Sbostic flags |= VSQUOTE; 105747139Sbostic *(stackblock() + typeloc) = subtype | flags; 105847139Sbostic if (subtype != VSNORMAL) 105947139Sbostic varnest++; 106047139Sbostic } 106147139Sbostic goto parsesub_return; 106247139Sbostic } 106347139Sbostic 106447139Sbostic 106547139Sbostic /* 106647139Sbostic * Called to parse command substitutions. Newstyle is set if the command 106747139Sbostic * is enclosed inside $(...); nlpp is a pointer to the head of the linked 106847139Sbostic * list of commands (passed by reference), and savelen is the number of 106947139Sbostic * characters on the top of the stack which must be preserved. 107047139Sbostic */ 107147139Sbostic 107247139Sbostic parsebackq: { 107347139Sbostic struct nodelist **nlpp; 107447139Sbostic int savepbq; 107547139Sbostic union node *n; 107647139Sbostic char *volatile str; 107747139Sbostic struct jmploc jmploc; 107847139Sbostic struct jmploc *volatile savehandler; 107947139Sbostic int savelen; 108047139Sbostic int t; 108147139Sbostic 108247139Sbostic savepbq = parsebackquote; 108347139Sbostic if (setjmp(jmploc.loc)) { 108447139Sbostic if (str) 108547139Sbostic ckfree(str); 108647139Sbostic parsebackquote = 0; 108747139Sbostic handler = savehandler; 108847139Sbostic longjmp(handler, 1); 108947139Sbostic } 109047139Sbostic INTOFF; 109147139Sbostic str = NULL; 109247139Sbostic savelen = out - stackblock(); 109347139Sbostic if (savelen > 0) { 109447139Sbostic str = ckmalloc(savelen); 109547139Sbostic bcopy(stackblock(), str, savelen); 109647139Sbostic } 109747139Sbostic savehandler = handler; 109847139Sbostic handler = &jmploc; 109947139Sbostic INTON; 110047139Sbostic nlpp = &bqlist; 110147139Sbostic while (*nlpp) 110247139Sbostic nlpp = &(*nlpp)->next; 110347139Sbostic *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); 110447139Sbostic (*nlpp)->next = NULL; 110547139Sbostic parsebackquote = oldstyle; 110647139Sbostic n = list(0); 110747139Sbostic t = oldstyle? TENDBQUOTE : TRP; 110847139Sbostic if (readtoken() != t) 110947139Sbostic synexpect(t); 111047139Sbostic (*nlpp)->n = n; 111147139Sbostic while (stackblocksize() <= savelen) 111247139Sbostic growstackblock(); 111347139Sbostic STARTSTACKSTR(out); 111447139Sbostic if (str) { 111547139Sbostic bcopy(str, out, savelen); 111647139Sbostic STADJUST(savelen, out); 111747139Sbostic INTOFF; 111847139Sbostic ckfree(str); 111947139Sbostic str = NULL; 112047139Sbostic INTON; 112147139Sbostic } 112247139Sbostic parsebackquote = savepbq; 112347139Sbostic handler = savehandler; 1124*53302Smarc if (arinest || dblquote) 1125*53302Smarc USTPUTC(CTLBACKQ | CTLQUOTE, out); 1126*53302Smarc else 1127*53302Smarc USTPUTC(CTLBACKQ, out); 112847139Sbostic if (oldstyle) 112947139Sbostic goto parsebackq_oldreturn; 113047139Sbostic else 113147139Sbostic goto parsebackq_newreturn; 113247139Sbostic } 113347139Sbostic 1134*53302Smarc /* 1135*53302Smarc * Parse an arithmetic expansion (indicate start of one and set state) 1136*53302Smarc */ 1137*53302Smarc parsearith: { 1138*53302Smarc 1139*53302Smarc if (++arinest == 1) { 1140*53302Smarc prevsyntax = syntax; 1141*53302Smarc syntax = ARISYNTAX; 1142*53302Smarc USTPUTC(CTLARI, out); 1143*53302Smarc } else { 1144*53302Smarc /* 1145*53302Smarc * we collapse embedded arithmetic expansion to 1146*53302Smarc * parenthesis, which should be equivalent 1147*53302Smarc */ 1148*53302Smarc USTPUTC('(', out); 1149*53302Smarc } 1150*53302Smarc goto parsearith_return; 1151*53302Smarc } 1152*53302Smarc 115347139Sbostic } /* end of readtoken */ 115447139Sbostic 115547139Sbostic 115647139Sbostic 115747139Sbostic #ifdef mkinit 115847139Sbostic RESET { 115947139Sbostic tokpushback = 0; 116047139Sbostic } 116147139Sbostic #endif 116247139Sbostic 116347139Sbostic 116447139Sbostic #if ATTY 116547139Sbostic /* 116647139Sbostic * Called to process a command generated by atty. We execute the line, 116747139Sbostic * and catch any errors that occur so they don't propagate outside of 116847139Sbostic * this routine. 116947139Sbostic */ 117047139Sbostic 117147139Sbostic STATIC void 117247139Sbostic attyline() { 117347139Sbostic char line[256]; 117447139Sbostic struct stackmark smark; 117547139Sbostic struct jmploc jmploc; 117647139Sbostic struct jmploc *volatile savehandler; 117747139Sbostic 117847139Sbostic if (pfgets(line, sizeof line) == NULL) 117947139Sbostic return; /* "can't happen" */ 118047139Sbostic if (setjmp(jmploc.loc)) { 118147139Sbostic if (exception == EXERROR) 118247139Sbostic out2str("\033]D\n"); 118347139Sbostic handler = savehandler; 118447139Sbostic longjmp(handler, 1); 118547139Sbostic } 118647139Sbostic savehandler = handler; 118747139Sbostic handler = &jmploc; 118847139Sbostic setstackmark(&smark); 118947139Sbostic evalstring(line); 119047139Sbostic popstackmark(&smark); 119147139Sbostic handler = savehandler; 119247139Sbostic doprompt = 1; 119347139Sbostic } 119447139Sbostic 119547139Sbostic 119647139Sbostic /* 119747139Sbostic * Output a prompt for atty. We output the prompt as part of the 119847139Sbostic * appropriate escape sequence. 119947139Sbostic */ 120047139Sbostic 120147139Sbostic STATIC void 120247139Sbostic putprompt(s) 120347139Sbostic char *s; 120447139Sbostic { 120547139Sbostic register char *p; 120647139Sbostic 120747139Sbostic if (attyset() && ! equal(termval(), "emacs")) { 120847139Sbostic if (strchr(s, '\7')) 120947139Sbostic out2c('\7'); 121047139Sbostic out2str("\033]P1;"); 121147139Sbostic for (p = s ; *p ; p++) { 121247139Sbostic if ((unsigned)(*p - ' ') <= '~' - ' ') 121347139Sbostic out2c(*p); 121447139Sbostic } 121547139Sbostic out2c('\n'); 121647139Sbostic } else { 121747139Sbostic out2str(s); 121847139Sbostic } 121947139Sbostic } 122047139Sbostic #endif 122147139Sbostic 122247139Sbostic 122347139Sbostic 122447139Sbostic /* 122547139Sbostic * Returns true if the text contains nothing to expand (no dollar signs 122647139Sbostic * or backquotes). 122747139Sbostic */ 122847139Sbostic 122947139Sbostic STATIC int 123047139Sbostic noexpand(text) 123147139Sbostic char *text; 123247139Sbostic { 123347139Sbostic register char *p; 123447139Sbostic register char c; 123547139Sbostic 123647139Sbostic p = text; 123747139Sbostic while ((c = *p++) != '\0') { 123847139Sbostic if (c == CTLESC) 123947139Sbostic p++; 124047139Sbostic else if (BASESYNTAX[c] == CCTL) 124147139Sbostic return 0; 124247139Sbostic } 124347139Sbostic return 1; 124447139Sbostic } 124547139Sbostic 124647139Sbostic 124747139Sbostic /* 124847139Sbostic * Return true if the argument is a legal variable name (a letter or 124947139Sbostic * underscore followed by zero or more letters, underscores, and digits). 125047139Sbostic */ 125147139Sbostic 125247139Sbostic int 125347139Sbostic goodname(name) 125447139Sbostic char *name; 125547139Sbostic { 125647139Sbostic register char *p; 125747139Sbostic 125847139Sbostic p = name; 125947139Sbostic if (! is_name(*p)) 126047139Sbostic return 0; 126147139Sbostic while (*++p) { 126247139Sbostic if (! is_in_name(*p)) 126347139Sbostic return 0; 126447139Sbostic } 126547139Sbostic return 1; 126647139Sbostic } 126747139Sbostic 126847139Sbostic 126947139Sbostic /* 127047139Sbostic * Called when an unexpected token is read during the parse. The argument 127147139Sbostic * is the token that is expected, or -1 if more than one type of token can 127247139Sbostic * occur at this point. 127347139Sbostic */ 127447139Sbostic 127547139Sbostic STATIC void 127647139Sbostic synexpect(token) { 127747139Sbostic char msg[64]; 127847139Sbostic 127947139Sbostic if (token >= 0) { 128047139Sbostic fmtstr(msg, 64, "%s unexpected (expecting %s)", 128147139Sbostic tokname[lasttoken], tokname[token]); 128247139Sbostic } else { 128347139Sbostic fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); 128447139Sbostic } 128547139Sbostic synerror(msg); 128647139Sbostic } 128747139Sbostic 128847139Sbostic 128947139Sbostic STATIC void 129047139Sbostic synerror(msg) 129147139Sbostic char *msg; 129247139Sbostic { 129347139Sbostic if (commandname) 129447139Sbostic outfmt(&errout, "%s: %d: ", commandname, startlinno); 129547139Sbostic outfmt(&errout, "Syntax error: %s\n", msg); 129647139Sbostic error((char *)NULL); 129747139Sbostic } 1298