aliases and editing (and -v, sort of)
[unix-history] / usr / src / bin / sh / parser.c
CommitLineData
d787dbb5
KB
1/*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * %sccs.include.redist.c%
9 */
10
11#ifndef lint
df4e2023 12static char sccsid[] = "@(#)parser.c 5.5 (Berkeley) %G%";
d787dbb5
KB
13#endif /* not lint */
14
15#include "shell.h"
16#include "parser.h"
17#include "nodes.h"
18#include "expand.h" /* defines rmescapes() */
19#include "redir.h" /* defines copyfd() */
20#include "syntax.h"
21#include "options.h"
22#include "input.h"
23#include "output.h"
24#include "var.h"
25#include "error.h"
26#include "memalloc.h"
27#include "mystring.h"
28
29
30/*
31 * Shell command parser.
32 */
33
34#define EOFMARKLEN 79
35
36/* values returned by readtoken */
37#include "token.def"
38
39
40
41struct heredoc {
42 struct heredoc *next; /* next here document in list */
43 union node *here; /* redirection node */
44 char *eofmark; /* string indicating end of input */
45 int striptabs; /* if set, strip leading tabs */
46};
47
48
49
50struct heredoc *heredoclist; /* list of here documents to read */
51int parsebackquote; /* nonzero if we are inside backquotes */
52int doprompt; /* if set, prompt the user */
53int needprompt; /* true if interactive and at start of line */
54int lasttoken; /* last token read */
55MKINIT int tokpushback; /* last token pushed back */
56char *wordtext; /* text of last word returned by readtoken */
21679e1e 57int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
d787dbb5
KB
58struct nodelist *backquotelist;
59union node *redirnode;
60struct heredoc *heredoc;
61int quoteflag; /* set if (part of) last token was quoted */
62int startlinno; /* line # where last token started */
63
64
65#define GDB_HACK 1 /* avoid local declarations which gdb can't handle */
66#ifdef GDB_HACK
67static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'};
68static const char types[] = "}-+?=";
69#endif
70
71
21679e1e
MT
72STATIC union node *list __P((int));
73STATIC union node *andor __P((void));
74STATIC union node *pipeline __P((void));
75STATIC union node *command __P((void));
76STATIC union node *simplecmd __P((void));
77STATIC void parsefname __P((void));
78STATIC void parseheredoc __P((void));
79STATIC int readtoken __P((void));
80STATIC int readtoken1 __P((int, char const *, char *, int));
81STATIC void attyline __P((void));
82STATIC int noexpand __P((char *));
83STATIC void synexpect __P((int));
84STATIC void synerror __P((char *));
d787dbb5
KB
85
86#if ATTY
21679e1e 87STATIC void putprompt __P((char *));
d787dbb5
KB
88#else /* not ATTY */
89#define putprompt(s) out2str(s)
90#endif
91
92
93
94
95/*
96 * Read and parse a command. Returns NEOF on end of file. (NULL is a
97 * valid parse tree indicating a blank line.)
98 */
99
100union node *
101parsecmd(interact) {
102 int t;
103
104 doprompt = interact;
105 if (doprompt)
106 putprompt(ps1val());
107 needprompt = 0;
108 if ((t = readtoken()) == TEOF)
109 return NEOF;
110 if (t == TNL)
111 return NULL;
112 tokpushback++;
113 return list(1);
114}
115
116
117STATIC union node *
118list(nlflag) {
119 union node *n1, *n2, *n3;
120
21679e1e
MT
121 checkkwd = 2;
122 if (nlflag == 0 && tokendlist[peektoken()])
d787dbb5
KB
123 return NULL;
124 n1 = andor();
125 for (;;) {
126 switch (readtoken()) {
127 case TBACKGND:
128 if (n1->type == NCMD || n1->type == NPIPE) {
129 n1->ncmd.backgnd = 1;
130 } else if (n1->type == NREDIR) {
131 n1->type = NBACKGND;
132 } else {
133 n3 = (union node *)stalloc(sizeof (struct nredir));
134 n3->type = NBACKGND;
135 n3->nredir.n = n1;
136 n3->nredir.redirect = NULL;
137 n1 = n3;
138 }
139 goto tsemi;
140 case TNL:
141 tokpushback++;
142 /* fall through */
143tsemi: case TSEMI:
144 if (readtoken() == TNL) {
145 parseheredoc();
146 if (nlflag)
147 return n1;
148 } else {
149 tokpushback++;
150 }
21679e1e
MT
151 checkkwd = 2;
152 if (tokendlist[peektoken()])
d787dbb5
KB
153 return n1;
154 n2 = andor();
155 n3 = (union node *)stalloc(sizeof (struct nbinary));
156 n3->type = NSEMI;
157 n3->nbinary.ch1 = n1;
158 n3->nbinary.ch2 = n2;
159 n1 = n3;
160 break;
161 case TEOF:
162 if (heredoclist)
163 parseheredoc();
164 else
165 pungetc(); /* push back EOF on input */
166 return n1;
167 default:
168 if (nlflag)
169 synexpect(-1);
170 tokpushback++;
171 return n1;
172 }
173 }
174}
175
176
177
178STATIC union node *
179andor() {
180 union node *n1, *n2, *n3;
181 int t;
182
183 n1 = pipeline();
184 for (;;) {
185 if ((t = readtoken()) == TAND) {
186 t = NAND;
187 } else if (t == TOR) {
188 t = NOR;
189 } else {
190 tokpushback++;
191 return n1;
192 }
193 n2 = pipeline();
194 n3 = (union node *)stalloc(sizeof (struct nbinary));
195 n3->type = t;
196 n3->nbinary.ch1 = n1;
197 n3->nbinary.ch2 = n2;
198 n1 = n3;
199 }
200}
201
202
203
204STATIC union node *
205pipeline() {
1545e6b2 206 union node *n1, *pipenode, *notnode;
d787dbb5 207 struct nodelist *lp, *prev;
1545e6b2 208 int negate = 0;
d787dbb5 209
1545e6b2
MT
210 TRACE(("pipeline: entered\n"));
211 while (readtoken() == TNOT) {
212 TRACE(("pipeline: TNOT recognized\n"));
213 negate = !negate;
214 }
215 tokpushback++;
d787dbb5
KB
216 n1 = command();
217 if (readtoken() == TPIPE) {
218 pipenode = (union node *)stalloc(sizeof (struct npipe));
219 pipenode->type = NPIPE;
220 pipenode->npipe.backgnd = 0;
221 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
222 pipenode->npipe.cmdlist = lp;
223 lp->n = n1;
224 do {
225 prev = lp;
226 lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
227 lp->n = command();
228 prev->next = lp;
229 } while (readtoken() == TPIPE);
230 lp->next = NULL;
231 n1 = pipenode;
232 }
233 tokpushback++;
1545e6b2
MT
234 if (negate) {
235 notnode = (union node *)stalloc(sizeof (struct nnot));
236 notnode->type = NNOT;
237 notnode->nnot.com = n1;
238 n1 = notnode;
239 }
d787dbb5
KB
240 return n1;
241}
242
243
244
245STATIC union node *
246command() {
247 union node *n1, *n2;
248 union node *ap, **app;
249 union node *cp, **cpp;
250 union node *redir, **rpp;
251 int t;
252
21679e1e 253 checkkwd = 2;
d787dbb5
KB
254 switch (readtoken()) {
255 case TIF:
256 n1 = (union node *)stalloc(sizeof (struct nif));
257 n1->type = NIF;
258 n1->nif.test = list(0);
259 if (readtoken() != TTHEN)
260 synexpect(TTHEN);
261 n1->nif.ifpart = list(0);
262 n2 = n1;
263 while (readtoken() == TELIF) {
264 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
265 n2 = n2->nif.elsepart;
266 n2->type = NIF;
267 n2->nif.test = list(0);
268 if (readtoken() != TTHEN)
269 synexpect(TTHEN);
270 n2->nif.ifpart = list(0);
271 }
272 if (lasttoken == TELSE)
273 n2->nif.elsepart = list(0);
274 else {
275 n2->nif.elsepart = NULL;
276 tokpushback++;
277 }
278 if (readtoken() != TFI)
279 synexpect(TFI);
21679e1e 280 checkkwd = 1;
d787dbb5
KB
281 break;
282 case TWHILE:
21679e1e
MT
283 case TUNTIL: {
284 int got;
d787dbb5
KB
285 n1 = (union node *)stalloc(sizeof (struct nbinary));
286 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
287 n1->nbinary.ch1 = list(0);
21679e1e
MT
288 if ((got=readtoken()) != TDO) {
289TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
d787dbb5 290 synexpect(TDO);
21679e1e 291 }
d787dbb5
KB
292 n1->nbinary.ch2 = list(0);
293 if (readtoken() != TDONE)
294 synexpect(TDONE);
21679e1e 295 checkkwd = 1;
d787dbb5 296 break;
21679e1e 297 }
d787dbb5
KB
298 case TFOR:
299 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
300 synerror("Bad for loop variable");
301 n1 = (union node *)stalloc(sizeof (struct nfor));
302 n1->type = NFOR;
303 n1->nfor.var = wordtext;
304 if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
305 app = ≈
306 while (readtoken() == TWORD) {
307 n2 = (union node *)stalloc(sizeof (struct narg));
308 n2->type = NARG;
309 n2->narg.text = wordtext;
310 n2->narg.backquote = backquotelist;
311 *app = n2;
312 app = &n2->narg.next;
313 }
314 *app = NULL;
315 n1->nfor.args = ap;
316 } else {
317#ifndef GDB_HACK
318 static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
319 '@', '=', '\0'};
320#endif
321 n2 = (union node *)stalloc(sizeof (struct narg));
322 n2->type = NARG;
323 n2->narg.text = (char *)argvars;
324 n2->narg.backquote = NULL;
325 n2->narg.next = NULL;
326 n1->nfor.args = n2;
327 }
328 if (lasttoken != TNL && lasttoken != TSEMI)
329 synexpect(-1);
21679e1e 330 checkkwd = 2;
d787dbb5
KB
331 if ((t = readtoken()) == TDO)
332 t = TDONE;
333 else if (t == TBEGIN)
334 t = TEND;
335 else
336 synexpect(-1);
337 n1->nfor.body = list(0);
338 if (readtoken() != t)
339 synexpect(t);
21679e1e 340 checkkwd = 1;
d787dbb5
KB
341 break;
342 case TCASE:
343 n1 = (union node *)stalloc(sizeof (struct ncase));
344 n1->type = NCASE;
345 if (readtoken() != TWORD)
346 synexpect(TWORD);
347 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
348 n2->type = NARG;
349 n2->narg.text = wordtext;
350 n2->narg.backquote = backquotelist;
351 n2->narg.next = NULL;
352 while (readtoken() == TNL);
353 if (lasttoken != TWORD || ! equal(wordtext, "in"))
354 synerror("expecting \"in\"");
355 cpp = &n1->ncase.cases;
21679e1e 356 while (checkkwd = 2, readtoken() == TWORD) {
d787dbb5
KB
357 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
358 cp->type = NCLIST;
359 app = &cp->nclist.pattern;
360 for (;;) {
361 *app = ap = (union node *)stalloc(sizeof (struct narg));
362 ap->type = NARG;
363 ap->narg.text = wordtext;
364 ap->narg.backquote = backquotelist;
365 if (readtoken() != TPIPE)
366 break;
367 app = &ap->narg.next;
368 if (readtoken() != TWORD)
369 synexpect(TWORD);
370 }
371 ap->narg.next = NULL;
372 if (lasttoken != TRP)
373 synexpect(TRP);
374 cp->nclist.body = list(0);
375 if ((t = readtoken()) == TESAC)
376 tokpushback++;
377 else if (t != TENDCASE)
378 synexpect(TENDCASE);
379 cpp = &cp->nclist.next;
380 }
381 *cpp = NULL;
382 if (lasttoken != TESAC)
383 synexpect(TESAC);
21679e1e 384 checkkwd = 1;
d787dbb5
KB
385 break;
386 case TLP:
387 n1 = (union node *)stalloc(sizeof (struct nredir));
388 n1->type = NSUBSHELL;
389 n1->nredir.n = list(0);
390 n1->nredir.redirect = NULL;
391 if (readtoken() != TRP)
392 synexpect(TRP);
21679e1e 393 checkkwd = 1;
d787dbb5
KB
394 break;
395 case TBEGIN:
396 n1 = list(0);
397 if (readtoken() != TEND)
398 synexpect(TEND);
21679e1e 399 checkkwd = 1;
d787dbb5
KB
400 break;
401 case TWORD:
402 case TREDIR:
403 tokpushback++;
404 return simplecmd();
405 default:
406 synexpect(-1);
407 }
408
409 /* Now check for redirection which may follow command */
410 rpp = &redir;
411 while (readtoken() == TREDIR) {
412 *rpp = n2 = redirnode;
413 rpp = &n2->nfile.next;
414 parsefname();
415 }
416 tokpushback++;
417 *rpp = NULL;
418 if (redir) {
419 if (n1->type != NSUBSHELL) {
420 n2 = (union node *)stalloc(sizeof (struct nredir));
421 n2->type = NREDIR;
422 n2->nredir.n = n1;
423 n1 = n2;
424 }
425 n1->nredir.redirect = redir;
426 }
427 return n1;
428}
429
430
431STATIC union node *
432simplecmd() {
433 union node *args, **app;
434 union node *redir, **rpp;
435 union node *n;
436
437 args = NULL;
438 app = &args;
439 rpp = &redir;
440 for (;;) {
441 if (readtoken() == TWORD) {
442 n = (union node *)stalloc(sizeof (struct narg));
443 n->type = NARG;
444 n->narg.text = wordtext;
445 n->narg.backquote = backquotelist;
446 *app = n;
447 app = &n->narg.next;
448 } else if (lasttoken == TREDIR) {
449 *rpp = n = redirnode;
450 rpp = &n->nfile.next;
451 parsefname(); /* read name of redirection file */
452 } else if (lasttoken == TLP && app == &args->narg.next
453 && rpp == &redir) {
454 /* We have a function */
455 if (readtoken() != TRP)
456 synexpect(TRP);
ddba57cd 457#ifdef notdef
d787dbb5
KB
458 if (! goodname(n->narg.text))
459 synerror("Bad function name");
ddba57cd 460#endif
d787dbb5
KB
461 n->type = NDEFUN;
462 n->narg.next = command();
463 return n;
464 } else {
465 tokpushback++;
466 break;
467 }
468 }
469 *app = NULL;
470 *rpp = NULL;
471 n = (union node *)stalloc(sizeof (struct ncmd));
472 n->type = NCMD;
473 n->ncmd.backgnd = 0;
474 n->ncmd.args = args;
475 n->ncmd.redirect = redir;
476 return n;
477}
478
479
480STATIC void
481parsefname() {
482 union node *n = redirnode;
483
484 if (readtoken() != TWORD)
485 synexpect(-1);
486 if (n->type == NHERE) {
487 struct heredoc *here = heredoc;
488 struct heredoc *p;
489 int i;
490
491 if (quoteflag == 0)
492 n->type = NXHERE;
493 TRACE(("Here document %d\n", n->type));
494 if (here->striptabs) {
495 while (*wordtext == '\t')
496 wordtext++;
497 }
498 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
499 synerror("Illegal eof marker for << redirection");
500 rmescapes(wordtext);
501 here->eofmark = wordtext;
502 here->next = NULL;
503 if (heredoclist == NULL)
504 heredoclist = here;
505 else {
506 for (p = heredoclist ; p->next ; p = p->next);
507 p->next = here;
508 }
509 } else if (n->type == NTOFD || n->type == NFROMFD) {
510 if (is_digit(wordtext[0]))
511 n->ndup.dupfd = digit_val(wordtext[0]);
512 else if (wordtext[0] == '-')
513 n->ndup.dupfd = -1;
514 else
515 goto bad;
516 if (wordtext[1] != '\0') {
517bad:
518 synerror("Bad fd number");
519 }
520 } else {
521 n->nfile.fname = (union node *)stalloc(sizeof (struct narg));
522 n = n->nfile.fname;
523 n->type = NARG;
524 n->narg.next = NULL;
525 n->narg.text = wordtext;
526 n->narg.backquote = backquotelist;
527 }
528}
529
530
531/*
532 * Input any here documents.
533 */
534
535STATIC void
536parseheredoc() {
537 struct heredoc *here;
538 union node *n;
539
540 while (heredoclist) {
541 here = heredoclist;
542 heredoclist = here->next;
543 if (needprompt) {
544 putprompt(ps2val());
545 needprompt = 0;
546 }
547 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
548 here->eofmark, here->striptabs);
549 n = (union node *)stalloc(sizeof (struct narg));
550 n->narg.type = NARG;
551 n->narg.next = NULL;
552 n->narg.text = wordtext;
553 n->narg.backquote = backquotelist;
554 here->here->nhere.doc = n;
555 }
556}
557
21679e1e
MT
558STATIC int
559peektoken() {
d787dbb5
KB
560 int t;
561
21679e1e 562 t = readtoken();
d787dbb5 563 tokpushback++;
21679e1e 564 return (t);
d787dbb5
KB
565}
566
d787dbb5
KB
567STATIC int xxreadtoken();
568
569STATIC int
570readtoken() {
571 int t;
21679e1e
MT
572#ifdef DEBUG
573 int alreadyseen = tokpushback;
574#endif
575
576 t = xxreadtoken();
577
578 if (checkkwd) {
579 /*
580 * eat newlines
581 */
582 if (checkkwd == 2) {
583 checkkwd = 0;
584 while (t == TNL) {
585 parseheredoc();
586 t = xxreadtoken();
587 }
588 } else
589 checkkwd = 0;
590 /*
591 * check for keywords
592 */
593 if (t == TWORD && !quoteflag) {
594 register char **pp;
595
596 for (pp = parsekwd; *pp; pp++) {
597 if (**pp == *wordtext && equal(*pp, wordtext)) {
598 lasttoken = t = pp - parsekwd + KWDOFFSET;
599 TRACE(("keyword %s recognized\n", tokname[t]));
600 break;
601 }
602 }
603 }
d787dbb5 604 }
21679e1e
MT
605#ifdef DEBUG
606 if (!alreadyseen)
607 TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
608 else
609 TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
610#endif
611 return (t);
d787dbb5
KB
612}
613
614
615/*
616 * Read the next input token.
617 * If the token is a word, we set backquotelist to the list of cmds in
618 * backquotes. We set quoteflag to true if any part of the word was
619 * quoted.
620 * If the token is TREDIR, then we set redirnode to a structure containing
621 * the redirection.
622 * In all cases, the variable startlinno is set to the number of the line
623 * on which the token starts.
624 *
625 * [Change comment: here documents and internal procedures]
626 * [Readtoken shouldn't have any arguments. Perhaps we should make the
627 * word parsing code into a separate routine. In this case, readtoken
628 * doesn't need to have any internal procedures, but parseword does.
629 * We could also make parseoperator in essence the main routine, and
630 * have parseword (readtoken1?) handle both words and redirection.]
631 */
632
633#define RETURN(token) return lasttoken = token
634
635STATIC int
636xxreadtoken() {
637 register c;
638
639 if (tokpushback) {
640 tokpushback = 0;
641 return lasttoken;
642 }
643 if (needprompt) {
644 putprompt(ps2val());
645 needprompt = 0;
646 }
647 startlinno = plinno;
648 for (;;) { /* until token or start of word found */
649 c = pgetc_macro();
650 if (c == ' ' || c == '\t')
651 continue; /* quick check for white space first */
652 switch (c) {
653 case ' ': case '\t':
654 continue;
655 case '#':
656 while ((c = pgetc()) != '\n' && c != PEOF);
657 pungetc();
658 continue;
659 case '\\':
660 if (pgetc() == '\n') {
661 startlinno = ++plinno;
662 if (doprompt)
663 putprompt(ps2val());
664 continue;
665 }
666 pungetc();
667 goto breakloop;
668 case '\n':
669 plinno++;
670 needprompt = doprompt;
671 RETURN(TNL);
672 case PEOF:
673 RETURN(TEOF);
674 case '&':
675 if (pgetc() == '&')
676 RETURN(TAND);
677 pungetc();
678 RETURN(TBACKGND);
679 case '|':
680 if (pgetc() == '|')
681 RETURN(TOR);
682 pungetc();
683 RETURN(TPIPE);
684 case ';':
685 if (pgetc() == ';')
686 RETURN(TENDCASE);
687 pungetc();
688 RETURN(TSEMI);
689 case '(':
690 RETURN(TLP);
691 case ')':
692 RETURN(TRP);
693 default:
694 goto breakloop;
695 }
696 }
697breakloop:
698 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
699#undef RETURN
700}
701
702
703
704/*
705 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
706 * is not NULL, read a here document. In the latter case, eofmark is the
707 * word which marks the end of the document and striptabs is true if
708 * leading tabs should be stripped from the document. The argument firstc
709 * is the first character of the input token or document.
710 *
711 * Because C does not have internal subroutines, I have simulated them
712 * using goto's to implement the subroutine linkage. The following macros
713 * will run code that appears at the end of readtoken1.
714 */
715
716#define CHECKEND() {goto checkend; checkend_return:;}
717#define PARSEREDIR() {goto parseredir; parseredir_return:;}
718#define PARSESUB() {goto parsesub; parsesub_return:;}
719#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
720#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
df4e2023 721#define PARSEARITH() {goto parsearith; parsearith_return:;}
d787dbb5
KB
722
723STATIC int
724readtoken1(firstc, syntax, eofmark, striptabs)
725 int firstc;
726 char const *syntax;
727 char *eofmark;
728 int striptabs;
729 {
730 register c = firstc;
731 register char *out;
732 int len;
733 char line[EOFMARKLEN + 1];
734 struct nodelist *bqlist;
735 int quotef;
736 int dblquote;
df4e2023
MT
737 int varnest; /* levels of variables expansion */
738 int arinest; /* levels of arithmetic expansion */
739 int parenlevel; /* levels of parens in arithmetic */
d787dbb5 740 int oldstyle;
df4e2023 741 char const *prevsyntax; /* syntax before arithmetic */
d787dbb5
KB
742
743 startlinno = plinno;
744 dblquote = 0;
745 if (syntax == DQSYNTAX)
746 dblquote = 1;
747 quotef = 0;
748 bqlist = NULL;
749 varnest = 0;
df4e2023
MT
750 arinest = 0;
751 parenlevel = 0;
752
d787dbb5
KB
753 STARTSTACKSTR(out);
754 loop: { /* for each line, until end of word */
755#if ATTY
756 if (c == '\034' && doprompt
757 && attyset() && ! equal(termval(), "emacs")) {
758 attyline();
759 if (syntax == BASESYNTAX)
760 return readtoken();
761 c = pgetc();
762 goto loop;
763 }
764#endif
765 CHECKEND(); /* set c to PEOF if at end of here document */
766 for (;;) { /* until end of line or end of word */
767 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
768 switch(syntax[c]) {
769 case CNL: /* '\n' */
770 if (syntax == BASESYNTAX)
771 goto endword; /* exit outer loop */
772 USTPUTC(c, out);
773 plinno++;
774 if (doprompt) {
775 putprompt(ps2val());
776 }
777 c = pgetc();
778 goto loop; /* continue outer loop */
779 case CWORD:
780 USTPUTC(c, out);
781 break;
782 case CCTL:
783 if (eofmark == NULL || dblquote)
784 USTPUTC(CTLESC, out);
785 USTPUTC(c, out);
786 break;
787 case CBACK: /* backslash */
788 c = pgetc();
789 if (c == PEOF) {
790 USTPUTC('\\', out);
791 pungetc();
792 } else if (c == '\n') {
793 if (doprompt)
794 putprompt(ps2val());
795 } else {
796 if (dblquote && c != '\\' && c != '`' && c != '$'
797 && (c != '"' || eofmark != NULL))
798 USTPUTC('\\', out);
799 if (SQSYNTAX[c] == CCTL)
800 USTPUTC(CTLESC, out);
801 USTPUTC(c, out);
802 quotef++;
803 }
804 break;
805 case CSQUOTE:
806 syntax = SQSYNTAX;
807 break;
808 case CDQUOTE:
809 syntax = DQSYNTAX;
810 dblquote = 1;
811 break;
812 case CENDQUOTE:
813 if (eofmark) {
814 USTPUTC(c, out);
815 } else {
df4e2023
MT
816 if (arinest)
817 syntax = ARISYNTAX;
818 else
819 syntax = BASESYNTAX;
d787dbb5
KB
820 quotef++;
821 dblquote = 0;
822 }
823 break;
824 case CVAR: /* '$' */
825 PARSESUB(); /* parse substitution */
826 break;
827 case CENDVAR: /* '}' */
828 if (varnest > 0) {
829 varnest--;
830 USTPUTC(CTLENDVAR, out);
831 } else {
832 USTPUTC(c, out);
833 }
834 break;
df4e2023
MT
835 case CLP: /* '(' in arithmetic */
836 parenlevel++;
837 USTPUTC(c, out);
838 break;
839 case CRP: /* ')' in arithmetic */
840 if (parenlevel > 0) {
841 USTPUTC(c, out);
842 --parenlevel;
843 } else {
844 if (pgetc() == ')') {
845 if (--arinest == 0) {
846 USTPUTC(CTLENDARI, out);
847 syntax = prevsyntax;
848 } else
849 USTPUTC(')', out);
850 } else {
851 /*
852 * unbalanced parens
853 * (don't 2nd guess - no error)
854 */
855 pungetc();
856 USTPUTC(')', out);
857 }
858 }
859 break;
d787dbb5
KB
860 case CBQUOTE: /* '`' */
861 if (parsebackquote && syntax == BASESYNTAX) {
862 if (out == stackblock())
863 return lasttoken = TENDBQUOTE;
864 else
865 goto endword; /* exit outer loop */
866 }
867 PARSEBACKQOLD();
868 break;
869 case CEOF:
870 goto endword; /* exit outer loop */
871 default:
872 if (varnest == 0)
873 goto endword; /* exit outer loop */
874 USTPUTC(c, out);
875 }
876 c = pgetc_macro();
877 }
878 }
879endword:
df4e2023
MT
880 if (syntax == ARISYNTAX)
881 synerror("Missing '))'");
d787dbb5
KB
882 if (syntax != BASESYNTAX && eofmark == NULL)
883 synerror("Unterminated quoted string");
884 if (varnest != 0) {
885 startlinno = plinno;
886 synerror("Missing '}'");
887 }
888 USTPUTC('\0', out);
889 len = out - stackblock();
890 out = stackblock();
891 if (eofmark == NULL) {
892 if ((c == '>' || c == '<')
893 && quotef == 0
894 && len <= 2
895 && (*out == '\0' || is_digit(*out))) {
896 PARSEREDIR();
897 return lasttoken = TREDIR;
898 } else {
899 pungetc();
900 }
901 }
902 quoteflag = quotef;
903 backquotelist = bqlist;
904 grabstackblock(len);
905 wordtext = out;
906 return lasttoken = TWORD;
907/* end of readtoken routine */
908
909
910
911/*
912 * Check to see whether we are at the end of the here document. When this
913 * is called, c is set to the first character of the next input line. If
914 * we are at the end of the here document, this routine sets the c to PEOF.
915 */
916
917checkend: {
918 if (eofmark) {
919 if (striptabs) {
920 while (c == '\t')
921 c = pgetc();
922 }
923 if (c == *eofmark) {
924 if (pfgets(line, sizeof line) != NULL) {
925 register char *p, *q;
926
927 p = line;
928 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
929 if (*p == '\n' && *q == '\0') {
930 c = PEOF;
931 plinno++;
932 needprompt = doprompt;
933 } else {
934 ppushback(line, strlen(line));
935 }
936 }
937 }
938 }
939 goto checkend_return;
940}
941
942
943/*
944 * Parse a redirection operator. The variable "out" points to a string
945 * specifying the fd to be redirected. The variable "c" contains the
946 * first character of the redirection operator.
947 */
948
949parseredir: {
950 char fd = *out;
951 union node *np;
952
953 np = (union node *)stalloc(sizeof (struct nfile));
954 if (c == '>') {
955 np->nfile.fd = 1;
956 c = pgetc();
957 if (c == '>')
958 np->type = NAPPEND;
959 else if (c == '&')
960 np->type = NTOFD;
961 else {
962 np->type = NTO;
963 pungetc();
964 }
965 } else { /* c == '<' */
966 np->nfile.fd = 0;
967 c = pgetc();
968 if (c == '<') {
969 if (sizeof (struct nfile) != sizeof (struct nhere)) {
970 np = (union node *)stalloc(sizeof (struct nhere));
971 np->nfile.fd = 0;
972 }
973 np->type = NHERE;
974 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
975 heredoc->here = np;
976 if ((c = pgetc()) == '-') {
977 heredoc->striptabs = 1;
978 } else {
979 heredoc->striptabs = 0;
980 pungetc();
981 }
982 } else if (c == '&')
983 np->type = NFROMFD;
984 else {
985 np->type = NFROM;
986 pungetc();
987 }
988 }
989 if (fd != '\0')
990 np->nfile.fd = digit_val(fd);
991 redirnode = np;
992 goto parseredir_return;
993}
994
995
996/*
997 * Parse a substitution. At this point, we have read the dollar sign
998 * and nothing else.
999 */
1000
1001parsesub: {
1002 int subtype;
1003 int typeloc;
1004 int flags;
1005 char *p;
1006#ifndef GDB_HACK
1007 static const char types[] = "}-+?=";
1008#endif
1009
1010 c = pgetc();
ddba57cd 1011 if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
d787dbb5
KB
1012 USTPUTC('$', out);
1013 pungetc();
df4e2023
MT
1014 } else if (c == '(') { /* $(command) or $((arith)) */
1015 if (pgetc() == '(') {
1016 PARSEARITH();
1017 } else {
1018 pungetc();
1019 PARSEBACKQNEW();
1020 }
d787dbb5
KB
1021 } else {
1022 USTPUTC(CTLVAR, out);
1023 typeloc = out - stackblock();
1024 USTPUTC(VSNORMAL, out);
1025 subtype = VSNORMAL;
1026 if (c == '{') {
1027 c = pgetc();
1028 subtype = 0;
1029 }
1030 if (is_name(c)) {
1031 do {
1032 STPUTC(c, out);
1033 c = pgetc();
1034 } while (is_in_name(c));
1035 } else {
1036 if (! is_special(c))
ddba57cd 1037badsub: synerror("Bad substitution");
d787dbb5
KB
1038 USTPUTC(c, out);
1039 c = pgetc();
1040 }
1041 STPUTC('=', out);
1042 flags = 0;
1043 if (subtype == 0) {
1044 if (c == ':') {
1045 flags = VSNUL;
1046 c = pgetc();
1047 }
1048 p = strchr(types, c);
1049 if (p == NULL)
1050 goto badsub;
1051 subtype = p - types + VSNORMAL;
1052 } else {
1053 pungetc();
1054 }
df4e2023 1055 if (dblquote || arinest)
d787dbb5
KB
1056 flags |= VSQUOTE;
1057 *(stackblock() + typeloc) = subtype | flags;
1058 if (subtype != VSNORMAL)
1059 varnest++;
1060 }
1061 goto parsesub_return;
1062}
1063
1064
1065/*
1066 * Called to parse command substitutions. Newstyle is set if the command
1067 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
1068 * list of commands (passed by reference), and savelen is the number of
1069 * characters on the top of the stack which must be preserved.
1070 */
1071
1072parsebackq: {
1073 struct nodelist **nlpp;
1074 int savepbq;
1075 union node *n;
1076 char *volatile str;
1077 struct jmploc jmploc;
1078 struct jmploc *volatile savehandler;
1079 int savelen;
1080 int t;
1081
1082 savepbq = parsebackquote;
1083 if (setjmp(jmploc.loc)) {
1084 if (str)
1085 ckfree(str);
1086 parsebackquote = 0;
1087 handler = savehandler;
1088 longjmp(handler, 1);
1089 }
1090 INTOFF;
1091 str = NULL;
1092 savelen = out - stackblock();
1093 if (savelen > 0) {
1094 str = ckmalloc(savelen);
1095 bcopy(stackblock(), str, savelen);
1096 }
1097 savehandler = handler;
1098 handler = &jmploc;
1099 INTON;
1100 nlpp = &bqlist;
1101 while (*nlpp)
1102 nlpp = &(*nlpp)->next;
1103 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1104 (*nlpp)->next = NULL;
1105 parsebackquote = oldstyle;
1106 n = list(0);
1107 t = oldstyle? TENDBQUOTE : TRP;
1108 if (readtoken() != t)
1109 synexpect(t);
1110 (*nlpp)->n = n;
1111 while (stackblocksize() <= savelen)
1112 growstackblock();
1113 STARTSTACKSTR(out);
1114 if (str) {
1115 bcopy(str, out, savelen);
1116 STADJUST(savelen, out);
1117 INTOFF;
1118 ckfree(str);
1119 str = NULL;
1120 INTON;
1121 }
1122 parsebackquote = savepbq;
1123 handler = savehandler;
df4e2023
MT
1124 if (arinest || dblquote)
1125 USTPUTC(CTLBACKQ | CTLQUOTE, out);
1126 else
1127 USTPUTC(CTLBACKQ, out);
d787dbb5
KB
1128 if (oldstyle)
1129 goto parsebackq_oldreturn;
1130 else
1131 goto parsebackq_newreturn;
1132}
1133
df4e2023
MT
1134/*
1135 * Parse an arithmetic expansion (indicate start of one and set state)
1136 */
1137parsearith: {
1138
1139 if (++arinest == 1) {
1140 prevsyntax = syntax;
1141 syntax = ARISYNTAX;
1142 USTPUTC(CTLARI, out);
1143 } else {
1144 /*
1145 * we collapse embedded arithmetic expansion to
1146 * parenthesis, which should be equivalent
1147 */
1148 USTPUTC('(', out);
1149 }
1150 goto parsearith_return;
1151}
1152
d787dbb5
KB
1153} /* end of readtoken */
1154
1155
1156
1157#ifdef mkinit
1158RESET {
1159 tokpushback = 0;
1160}
1161#endif
1162
1163
1164#if ATTY
1165/*
1166 * Called to process a command generated by atty. We execute the line,
1167 * and catch any errors that occur so they don't propagate outside of
1168 * this routine.
1169 */
1170
1171STATIC void
1172attyline() {
1173 char line[256];
1174 struct stackmark smark;
1175 struct jmploc jmploc;
1176 struct jmploc *volatile savehandler;
1177
1178 if (pfgets(line, sizeof line) == NULL)
1179 return; /* "can't happen" */
1180 if (setjmp(jmploc.loc)) {
1181 if (exception == EXERROR)
1182 out2str("\033]D\n");
1183 handler = savehandler;
1184 longjmp(handler, 1);
1185 }
1186 savehandler = handler;
1187 handler = &jmploc;
1188 setstackmark(&smark);
1189 evalstring(line);
1190 popstackmark(&smark);
1191 handler = savehandler;
1192 doprompt = 1;
1193}
1194
1195
1196/*
1197 * Output a prompt for atty. We output the prompt as part of the
1198 * appropriate escape sequence.
1199 */
1200
1201STATIC void
1202putprompt(s)
1203 char *s;
1204 {
1205 register char *p;
1206
1207 if (attyset() && ! equal(termval(), "emacs")) {
1208 if (strchr(s, '\7'))
1209 out2c('\7');
1210 out2str("\033]P1;");
1211 for (p = s ; *p ; p++) {
1212 if ((unsigned)(*p - ' ') <= '~' - ' ')
1213 out2c(*p);
1214 }
1215 out2c('\n');
1216 } else {
1217 out2str(s);
1218 }
1219}
1220#endif
1221
1222
1223
1224/*
1225 * Returns true if the text contains nothing to expand (no dollar signs
1226 * or backquotes).
1227 */
1228
1229STATIC int
1230noexpand(text)
1231 char *text;
1232 {
1233 register char *p;
1234 register char c;
1235
1236 p = text;
1237 while ((c = *p++) != '\0') {
1238 if (c == CTLESC)
1239 p++;
1240 else if (BASESYNTAX[c] == CCTL)
1241 return 0;
1242 }
1243 return 1;
1244}
1245
1246
1247/*
1248 * Return true if the argument is a legal variable name (a letter or
1249 * underscore followed by zero or more letters, underscores, and digits).
1250 */
1251
1252int
1253goodname(name)
1254 char *name;
1255 {
1256 register char *p;
1257
1258 p = name;
1259 if (! is_name(*p))
1260 return 0;
1261 while (*++p) {
1262 if (! is_in_name(*p))
1263 return 0;
1264 }
1265 return 1;
1266}
1267
1268
1269/*
1270 * Called when an unexpected token is read during the parse. The argument
1271 * is the token that is expected, or -1 if more than one type of token can
1272 * occur at this point.
1273 */
1274
1275STATIC void
1276synexpect(token) {
1277 char msg[64];
1278
1279 if (token >= 0) {
1280 fmtstr(msg, 64, "%s unexpected (expecting %s)",
1281 tokname[lasttoken], tokname[token]);
1282 } else {
1283 fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1284 }
1285 synerror(msg);
1286}
1287
1288
1289STATIC void
1290synerror(msg)
1291 char *msg;
1292 {
1293 if (commandname)
1294 outfmt(&errout, "%s: %d: ", commandname, startlinno);
1295 outfmt(&errout, "Syntax error: %s\n", msg);
1296 error((char *)NULL);
1297}