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