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