parser.c revision 1.5 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.5 1993/05/02 01:28:43 sef 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((union node **, union node *));
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 redir = 0;
269 rpp = &redir;
270 /* Check for redirection which may precede command */
271 while (readtoken() == TREDIR) {
272 *rpp = n2 = redirnode;
273 rpp = &n2->nfile.next;
274 parsefname();
275 }
276 tokpushback++;
277
278 switch (readtoken()) {
279 case TIF:
280 n1 = (union node *)stalloc(sizeof (struct nif));
281 n1->type = NIF;
282 n1->nif.test = list(0);
283 if (readtoken() != TTHEN)
284 synexpect(TTHEN);
285 n1->nif.ifpart = list(0);
286 n2 = n1;
287 while (readtoken() == TELIF) {
288 n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
289 n2 = n2->nif.elsepart;
290 n2->type = NIF;
291 n2->nif.test = list(0);
292 if (readtoken() != TTHEN)
293 synexpect(TTHEN);
294 n2->nif.ifpart = list(0);
295 }
296 if (lasttoken == TELSE)
297 n2->nif.elsepart = list(0);
298 else {
299 n2->nif.elsepart = NULL;
300 tokpushback++;
301 }
302 if (readtoken() != TFI)
303 synexpect(TFI);
304 checkkwd = 1;
305 break;
306 case TWHILE:
307 case TUNTIL: {
308 int got;
309 n1 = (union node *)stalloc(sizeof (struct nbinary));
310 n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
311 n1->nbinary.ch1 = list(0);
312 if ((got=readtoken()) != TDO) {
313 TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
314 synexpect(TDO);
315 }
316 n1->nbinary.ch2 = list(0);
317 if (readtoken() != TDONE)
318 synexpect(TDONE);
319 checkkwd = 1;
320 break;
321 }
322 case TFOR:
323 if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
324 synerror("Bad for loop variable");
325 n1 = (union node *)stalloc(sizeof (struct nfor));
326 n1->type = NFOR;
327 n1->nfor.var = wordtext;
328 if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) {
329 app = ≈
330 while (readtoken() == TWORD) {
331 n2 = (union node *)stalloc(sizeof (struct narg));
332 n2->type = NARG;
333 n2->narg.text = wordtext;
334 n2->narg.backquote = backquotelist;
335 *app = n2;
336 app = &n2->narg.next;
337 }
338 *app = NULL;
339 n1->nfor.args = ap;
340 /* A newline or semicolon is required here to end
341 the list. */
342 if (lasttoken != TNL && lasttoken != TSEMI)
343 synexpect(-1);
344 } else {
345 #ifndef GDB_HACK
346 static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE,
347 '@', '=', '\0'};
348 #endif
349 n2 = (union node *)stalloc(sizeof (struct narg));
350 n2->type = NARG;
351 n2->narg.text = (char *)argvars;
352 n2->narg.backquote = NULL;
353 n2->narg.next = NULL;
354 n1->nfor.args = n2;
355 /* A newline or semicolon is optional here. Anything
356 else gets pushed back so we can read it again. */
357 if (lasttoken != TNL && lasttoken != TSEMI)
358 tokpushback++;
359 }
360 checkkwd = 2;
361 if ((t = readtoken()) == TDO)
362 t = TDONE;
363 else if (t == TBEGIN)
364 t = TEND;
365 else
366 synexpect(-1);
367 n1->nfor.body = list(0);
368 if (readtoken() != t)
369 synexpect(t);
370 checkkwd = 1;
371 break;
372 case TCASE:
373 n1 = (union node *)stalloc(sizeof (struct ncase));
374 n1->type = NCASE;
375 if (readtoken() != TWORD)
376 synexpect(TWORD);
377 n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
378 n2->type = NARG;
379 n2->narg.text = wordtext;
380 n2->narg.backquote = backquotelist;
381 n2->narg.next = NULL;
382 while (readtoken() == TNL);
383 if (lasttoken != TWORD || ! equal(wordtext, "in"))
384 synerror("expecting \"in\"");
385 cpp = &n1->ncase.cases;
386 while (checkkwd = 2, readtoken() == TWORD) {
387 *cpp = cp = (union node *)stalloc(sizeof (struct nclist));
388 cp->type = NCLIST;
389 app = &cp->nclist.pattern;
390 for (;;) {
391 *app = ap = (union node *)stalloc(sizeof (struct narg));
392 ap->type = NARG;
393 ap->narg.text = wordtext;
394 ap->narg.backquote = backquotelist;
395 if (readtoken() != TPIPE)
396 break;
397 app = &ap->narg.next;
398 if (readtoken() != TWORD)
399 synexpect(TWORD);
400 }
401 ap->narg.next = NULL;
402 if (lasttoken != TRP)
403 synexpect(TRP);
404 cp->nclist.body = list(0);
405 if ((t = readtoken()) == TESAC)
406 tokpushback++;
407 else if (t != TENDCASE)
408 synexpect(TENDCASE);
409 cpp = &cp->nclist.next;
410 }
411 *cpp = NULL;
412 if (lasttoken != TESAC)
413 synexpect(TESAC);
414 checkkwd = 1;
415 break;
416 case TLP:
417 n1 = (union node *)stalloc(sizeof (struct nredir));
418 n1->type = NSUBSHELL;
419 n1->nredir.n = list(0);
420 n1->nredir.redirect = NULL;
421 if (readtoken() != TRP)
422 synexpect(TRP);
423 checkkwd = 1;
424 break;
425 case TBEGIN:
426 n1 = list(0);
427 if (readtoken() != TEND)
428 synexpect(TEND);
429 checkkwd = 1;
430 break;
431 /* Handle an empty command like other simple commands. */
432 case TNL:
433 case TWORD:
434 tokpushback++;
435 return simplecmd(rpp, redir);
436 default:
437 synexpect(-1);
438 }
439
440 /* Now check for redirection which may follow command */
441 while (readtoken() == TREDIR) {
442 *rpp = n2 = redirnode;
443 rpp = &n2->nfile.next;
444 parsefname();
445 }
446 tokpushback++;
447 *rpp = NULL;
448 if (redir) {
449 if (n1->type != NSUBSHELL) {
450 n2 = (union node *)stalloc(sizeof (struct nredir));
451 n2->type = NREDIR;
452 n2->nredir.n = n1;
453 n1 = n2;
454 }
455 n1->nredir.redirect = redir;
456 }
457 return n1;
458 }
459
460
461 STATIC union node *
462 simplecmd(rpp, redir)
463 union node **rpp, *redir;
464 {
465 union node *args, **app;
466 union node **orig_rpp = rpp;
467 union node *n;
468
469 /* If we don't have any redirections already, then we must reset
470 rpp to be the address of the local redir variable. */
471 if (redir == 0)
472 rpp = &redir;
473
474 args = NULL;
475 app = &args;
476 /* We save the incoming value, because we need this for shell
477 functions. There can not be a redirect or an argument between
478 the function name and the open parenthesis. */
479 orig_rpp = rpp;
480 for (;;) {
481 if (readtoken() == TWORD) {
482 n = (union node *)stalloc(sizeof (struct narg));
483 n->type = NARG;
484 n->narg.text = wordtext;
485 n->narg.backquote = backquotelist;
486 *app = n;
487 app = &n->narg.next;
488 } else if (lasttoken == TREDIR) {
489 *rpp = n = redirnode;
490 rpp = &n->nfile.next;
491 parsefname(); /* read name of redirection file */
492 } else if (lasttoken == TLP && app == &args->narg.next
493 && rpp == orig_rpp) {
494 /* We have a function */
495 if (readtoken() != TRP)
496 synexpect(TRP);
497 #ifdef notdef
498 if (! goodname(n->narg.text))
499 synerror("Bad function name");
500 #endif
501 n->type = NDEFUN;
502 n->narg.next = command();
503 return n;
504 } else {
505 tokpushback++;
506 break;
507 }
508 }
509 *app = NULL;
510 *rpp = NULL;
511 n = (union node *)stalloc(sizeof (struct ncmd));
512 n->type = NCMD;
513 n->ncmd.backgnd = 0;
514 n->ncmd.args = args;
515 n->ncmd.redirect = redir;
516 return n;
517 }
518
519
520 STATIC void
521 parsefname() {
522 union node *n = redirnode;
523
524 if (readtoken() != TWORD)
525 synexpect(-1);
526 if (n->type == NHERE) {
527 struct heredoc *here = heredoc;
528 struct heredoc *p;
529 int i;
530
531 if (quoteflag == 0)
532 n->type = NXHERE;
533 TRACE(("Here document %d\n", n->type));
534 if (here->striptabs) {
535 while (*wordtext == '\t')
536 wordtext++;
537 }
538 if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
539 synerror("Illegal eof marker for << redirection");
540 rmescapes(wordtext);
541 here->eofmark = wordtext;
542 here->next = NULL;
543 if (heredoclist == NULL)
544 heredoclist = here;
545 else {
546 for (p = heredoclist ; p->next ; p = p->next);
547 p->next = here;
548 }
549 } else if (n->type == NTOFD || n->type == NFROMFD) {
550 if (is_digit(wordtext[0]))
551 n->ndup.dupfd = digit_val(wordtext[0]);
552 else if (wordtext[0] == '-')
553 n->ndup.dupfd = -1;
554 else
555 goto bad;
556 if (wordtext[1] != '\0') {
557 bad:
558 synerror("Bad fd number");
559 }
560 } else {
561 n->nfile.fname = (union node *)stalloc(sizeof (struct narg));
562 n = n->nfile.fname;
563 n->type = NARG;
564 n->narg.next = NULL;
565 n->narg.text = wordtext;
566 n->narg.backquote = backquotelist;
567 }
568 }
569
570
571 /*
572 * Input any here documents.
573 */
574
575 STATIC void
576 parseheredoc() {
577 struct heredoc *here;
578 union node *n;
579
580 while (heredoclist) {
581 here = heredoclist;
582 heredoclist = here->next;
583 if (needprompt) {
584 putprompt(ps2val());
585 needprompt = 0;
586 }
587 readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX,
588 here->eofmark, here->striptabs);
589 n = (union node *)stalloc(sizeof (struct narg));
590 n->narg.type = NARG;
591 n->narg.next = NULL;
592 n->narg.text = wordtext;
593 n->narg.backquote = backquotelist;
594 here->here->nhere.doc = n;
595 }
596 }
597
598 STATIC int
599 peektoken() {
600 int t;
601
602 t = readtoken();
603 tokpushback++;
604 return (t);
605 }
606
607 STATIC int xxreadtoken();
608
609 STATIC int
610 readtoken() {
611 int t;
612 #ifdef DEBUG
613 int alreadyseen = tokpushback;
614 #endif
615
616 t = xxreadtoken();
617
618 if (checkkwd) {
619 /*
620 * eat newlines
621 */
622 if (checkkwd == 2) {
623 checkkwd = 0;
624 while (t == TNL) {
625 parseheredoc();
626 t = xxreadtoken();
627 }
628 } else
629 checkkwd = 0;
630 /*
631 * check for keywords
632 */
633 if (t == TWORD && !quoteflag) {
634 register char **pp;
635
636 for (pp = parsekwd; *pp; pp++) {
637 if (**pp == *wordtext && equal(*pp, wordtext)) {
638 lasttoken = t = pp - parsekwd + KWDOFFSET;
639 TRACE(("keyword %s recognized\n", tokname[t]));
640 break;
641 }
642 }
643 }
644 }
645 #ifdef DEBUG
646 if (!alreadyseen)
647 TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
648 else
649 TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : ""));
650 #endif
651 return (t);
652 }
653
654
655 /*
656 * Read the next input token.
657 * If the token is a word, we set backquotelist to the list of cmds in
658 * backquotes. We set quoteflag to true if any part of the word was
659 * quoted.
660 * If the token is TREDIR, then we set redirnode to a structure containing
661 * the redirection.
662 * In all cases, the variable startlinno is set to the number of the line
663 * on which the token starts.
664 *
665 * [Change comment: here documents and internal procedures]
666 * [Readtoken shouldn't have any arguments. Perhaps we should make the
667 * word parsing code into a separate routine. In this case, readtoken
668 * doesn't need to have any internal procedures, but parseword does.
669 * We could also make parseoperator in essence the main routine, and
670 * have parseword (readtoken1?) handle both words and redirection.]
671 */
672
673 #define RETURN(token) return lasttoken = token
674
675 STATIC int
676 xxreadtoken() {
677 register c;
678
679 if (tokpushback) {
680 tokpushback = 0;
681 return lasttoken;
682 }
683 if (needprompt) {
684 putprompt(ps2val());
685 needprompt = 0;
686 }
687 startlinno = plinno;
688 for (;;) { /* until token or start of word found */
689 c = pgetc_macro();
690 if (c == ' ' || c == '\t')
691 continue; /* quick check for white space first */
692 switch (c) {
693 case ' ': case '\t':
694 continue;
695 case '#':
696 while ((c = pgetc()) != '\n' && c != PEOF);
697 pungetc();
698 continue;
699 case '\\':
700 if (pgetc() == '\n') {
701 startlinno = ++plinno;
702 if (doprompt)
703 putprompt(ps2val());
704 continue;
705 }
706 pungetc();
707 goto breakloop;
708 case '\n':
709 plinno++;
710 needprompt = doprompt;
711 RETURN(TNL);
712 case PEOF:
713 RETURN(TEOF);
714 case '&':
715 if (pgetc() == '&')
716 RETURN(TAND);
717 pungetc();
718 RETURN(TBACKGND);
719 case '|':
720 if (pgetc() == '|')
721 RETURN(TOR);
722 pungetc();
723 RETURN(TPIPE);
724 case ';':
725 if (pgetc() == ';')
726 RETURN(TENDCASE);
727 pungetc();
728 RETURN(TSEMI);
729 case '(':
730 RETURN(TLP);
731 case ')':
732 RETURN(TRP);
733 default:
734 goto breakloop;
735 }
736 }
737 breakloop:
738 return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
739 #undef RETURN
740 }
741
742
743
744 /*
745 * If eofmark is NULL, read a word or a redirection symbol. If eofmark
746 * is not NULL, read a here document. In the latter case, eofmark is the
747 * word which marks the end of the document and striptabs is true if
748 * leading tabs should be stripped from the document. The argument firstc
749 * is the first character of the input token or document.
750 *
751 * Because C does not have internal subroutines, I have simulated them
752 * using goto's to implement the subroutine linkage. The following macros
753 * will run code that appears at the end of readtoken1.
754 */
755
756 #define CHECKEND() {goto checkend; checkend_return:;}
757 #define PARSEREDIR() {goto parseredir; parseredir_return:;}
758 #define PARSESUB() {goto parsesub; parsesub_return:;}
759 #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;}
760 #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;}
761
762 STATIC int
763 readtoken1(firstc, syntax, eofmark, striptabs)
764 int firstc;
765 char const *syntax;
766 char *eofmark;
767 int striptabs;
768 {
769 register c = firstc;
770 register char *out;
771 int len;
772 char line[EOFMARKLEN + 1];
773 struct nodelist *bqlist;
774 int quotef;
775 int dblquote;
776 int varnest;
777 int oldstyle;
778
779 startlinno = plinno;
780 dblquote = 0;
781 if (syntax == DQSYNTAX)
782 dblquote = 1;
783 quotef = 0;
784 bqlist = NULL;
785 varnest = 0;
786 STARTSTACKSTR(out);
787 loop: { /* for each line, until end of word */
788 #if ATTY
789 if (c == '\034' && doprompt
790 && attyset() && ! equal(termval(), "emacs")) {
791 attyline();
792 if (syntax == BASESYNTAX)
793 return readtoken();
794 c = pgetc();
795 goto loop;
796 }
797 #endif
798 CHECKEND(); /* set c to PEOF if at end of here document */
799 for (;;) { /* until end of line or end of word */
800 CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */
801 switch(syntax[c]) {
802 case CNL: /* '\n' */
803 if (syntax == BASESYNTAX)
804 goto endword; /* exit outer loop */
805 USTPUTC(c, out);
806 plinno++;
807 if (doprompt) {
808 putprompt(ps2val());
809 }
810 c = pgetc();
811 goto loop; /* continue outer loop */
812 case CWORD:
813 USTPUTC(c, out);
814 break;
815 case CCTL:
816 if (eofmark == NULL || dblquote)
817 USTPUTC(CTLESC, out);
818 USTPUTC(c, out);
819 break;
820 case CBACK: /* backslash */
821 c = pgetc();
822 if (c == PEOF) {
823 USTPUTC('\\', out);
824 pungetc();
825 } else if (c == '\n') {
826 if (doprompt)
827 putprompt(ps2val());
828 } else {
829 if (dblquote && c != '\\' && c != '`' && c != '$'
830 && (c != '"' || eofmark != NULL))
831 USTPUTC('\\', out);
832 if (SQSYNTAX[c] == CCTL)
833 USTPUTC(CTLESC, out);
834 USTPUTC(c, out);
835 quotef++;
836 }
837 break;
838 case CSQUOTE:
839 syntax = SQSYNTAX;
840 break;
841 case CDQUOTE:
842 syntax = DQSYNTAX;
843 dblquote = 1;
844 break;
845 case CENDQUOTE:
846 if (eofmark) {
847 USTPUTC(c, out);
848 } else {
849 syntax = BASESYNTAX;
850 quotef++;
851 dblquote = 0;
852 }
853 break;
854 case CVAR: /* '$' */
855 PARSESUB(); /* parse substitution */
856 break;
857 case CENDVAR: /* '}' */
858 if (varnest > 0) {
859 varnest--;
860 USTPUTC(CTLENDVAR, out);
861 } else {
862 USTPUTC(c, out);
863 }
864 break;
865 case CBQUOTE: /* '`' */
866 PARSEBACKQOLD();
867 break;
868 case CEOF:
869 goto endword; /* exit outer loop */
870 default:
871 if (varnest == 0)
872 goto endword; /* exit outer loop */
873 USTPUTC(c, out);
874 }
875 c = pgetc_macro();
876 }
877 }
878 endword:
879 if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL)
880 synerror("Unterminated quoted string");
881 if (varnest != 0) {
882 startlinno = plinno;
883 synerror("Missing '}'");
884 }
885 USTPUTC('\0', out);
886 len = out - stackblock();
887 out = stackblock();
888 if (eofmark == NULL) {
889 if ((c == '>' || c == '<')
890 && quotef == 0
891 && len <= 2
892 && (*out == '\0' || is_digit(*out))) {
893 PARSEREDIR();
894 return lasttoken = TREDIR;
895 } else {
896 pungetc();
897 }
898 }
899 quoteflag = quotef;
900 backquotelist = bqlist;
901 grabstackblock(len);
902 wordtext = out;
903 return lasttoken = TWORD;
904 /* end of readtoken routine */
905
906
907
908 /*
909 * Check to see whether we are at the end of the here document. When this
910 * is called, c is set to the first character of the next input line. If
911 * we are at the end of the here document, this routine sets the c to PEOF.
912 */
913
914 checkend: {
915 if (eofmark) {
916 if (striptabs) {
917 while (c == '\t')
918 c = pgetc();
919 }
920 if (c == *eofmark) {
921 if (pfgets(line, sizeof line) != NULL) {
922 register char *p, *q;
923
924 p = line;
925 for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
926 if (*p == '\n' && *q == '\0') {
927 c = PEOF;
928 plinno++;
929 needprompt = doprompt;
930 } else {
931 ppushback(line, strlen(line));
932 }
933 }
934 }
935 }
936 goto checkend_return;
937 }
938
939
940 /*
941 * Parse a redirection operator. The variable "out" points to a string
942 * specifying the fd to be redirected. The variable "c" contains the
943 * first character of the redirection operator.
944 */
945
946 parseredir: {
947 char fd = *out;
948 union node *np;
949
950 np = (union node *)stalloc(sizeof (struct nfile));
951 if (c == '>') {
952 np->nfile.fd = 1;
953 c = pgetc();
954 if (c == '>')
955 np->type = NAPPEND;
956 else if (c == '&')
957 np->type = NTOFD;
958 else {
959 np->type = NTO;
960 pungetc();
961 }
962 } else { /* c == '<' */
963 np->nfile.fd = 0;
964 c = pgetc();
965 if (c == '<') {
966 if (sizeof (struct nfile) != sizeof (struct nhere)) {
967 np = (union node *)stalloc(sizeof (struct nhere));
968 np->nfile.fd = 0;
969 }
970 np->type = NHERE;
971 heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
972 heredoc->here = np;
973 if ((c = pgetc()) == '-') {
974 heredoc->striptabs = 1;
975 } else {
976 heredoc->striptabs = 0;
977 pungetc();
978 }
979 } else if (c == '&')
980 np->type = NFROMFD;
981 else {
982 np->type = NFROM;
983 pungetc();
984 }
985 }
986 if (fd != '\0')
987 np->nfile.fd = digit_val(fd);
988 redirnode = np;
989 goto parseredir_return;
990 }
991
992
993 /*
994 * Parse a substitution. At this point, we have read the dollar sign
995 * and nothing else.
996 */
997
998 parsesub: {
999 int subtype;
1000 int typeloc;
1001 int flags;
1002 char *p;
1003 #ifndef GDB_HACK
1004 static const char types[] = "}-+?=";
1005 #endif
1006
1007 c = pgetc();
1008 if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) {
1009 USTPUTC('$', out);
1010 pungetc();
1011 } else if (c == '(') { /* $(command) */
1012 PARSEBACKQNEW();
1013 } else {
1014 USTPUTC(CTLVAR, out);
1015 typeloc = out - stackblock();
1016 USTPUTC(VSNORMAL, out);
1017 subtype = VSNORMAL;
1018 if (c == '{') {
1019 c = pgetc();
1020 subtype = 0;
1021 }
1022 if (is_name(c)) {
1023 do {
1024 STPUTC(c, out);
1025 c = pgetc();
1026 } while (is_in_name(c));
1027 } else {
1028 if (! is_special(c))
1029 badsub: synerror("Bad substitution");
1030 USTPUTC(c, out);
1031 c = pgetc();
1032 }
1033 STPUTC('=', out);
1034 flags = 0;
1035 if (subtype == 0) {
1036 if (c == ':') {
1037 flags = VSNUL;
1038 c = pgetc();
1039 }
1040 p = strchr(types, c);
1041 if (p == NULL)
1042 goto badsub;
1043 subtype = p - types + VSNORMAL;
1044 } else {
1045 pungetc();
1046 }
1047 if (dblquote)
1048 flags |= VSQUOTE;
1049 *(stackblock() + typeloc) = subtype | flags;
1050 if (subtype != VSNORMAL)
1051 varnest++;
1052 }
1053 goto parsesub_return;
1054 }
1055
1056
1057 /*
1058 * Called to parse command substitutions. Newstyle is set if the command
1059 * is enclosed inside $(...); nlpp is a pointer to the head of the linked
1060 * list of commands (passed by reference), and savelen is the number of
1061 * characters on the top of the stack which must be preserved.
1062 */
1063
1064 parsebackq: {
1065 struct nodelist **nlpp;
1066 int savepbq;
1067 union node *n;
1068 char *volatile str;
1069 struct jmploc jmploc;
1070 struct jmploc *volatile savehandler;
1071 int savelen;
1072
1073 savepbq = parsebackquote;
1074 if (setjmp(jmploc.loc)) {
1075 if (str)
1076 ckfree(str);
1077 parsebackquote = 0;
1078 handler = savehandler;
1079 longjmp(handler->loc, 1);
1080 }
1081 INTOFF;
1082 str = NULL;
1083 savelen = out - stackblock();
1084 if (savelen > 0) {
1085 str = ckmalloc(savelen);
1086 bcopy(stackblock(), str, savelen);
1087 }
1088 savehandler = handler;
1089 handler = &jmploc;
1090 INTON;
1091 if (oldstyle) {
1092 /* We must read until the closing backquote, giving special
1093 treatment to some slashes, and then push the string and
1094 reread it as input, interpreting it normally. */
1095 register char *out;
1096 register c;
1097 int savelen;
1098 char *str;
1099
1100 STARTSTACKSTR(out);
1101 while ((c = pgetc ()) != '`') {
1102 if (c == '\\') {
1103 c = pgetc ();
1104 if (c != '\\' && c != '`' && c != '$'
1105 && (!dblquote || c != '"'))
1106 STPUTC('\\', out);
1107 }
1108 STPUTC(c, out);
1109 }
1110 STPUTC('\0', out);
1111 savelen = out - stackblock();
1112 if (savelen > 0) {
1113 str = ckmalloc(savelen);
1114 bcopy(stackblock(), str, savelen);
1115 }
1116 setinputstring(str, 1);
1117 }
1118 nlpp = &bqlist;
1119 while (*nlpp)
1120 nlpp = &(*nlpp)->next;
1121 *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist));
1122 (*nlpp)->next = NULL;
1123 parsebackquote = oldstyle;
1124 n = list(0);
1125 if (!oldstyle && (readtoken() != TRP))
1126 synexpect(TRP);
1127 (*nlpp)->n = n;
1128 /* Start reading from old file again. */
1129 if (oldstyle)
1130 popfile();
1131 while (stackblocksize() <= savelen)
1132 growstackblock();
1133 STARTSTACKSTR(out);
1134 if (str) {
1135 bcopy(str, out, savelen);
1136 STADJUST(savelen, out);
1137 INTOFF;
1138 ckfree(str);
1139 str = NULL;
1140 INTON;
1141 }
1142 parsebackquote = savepbq;
1143 handler = savehandler;
1144 USTPUTC(CTLBACKQ + dblquote, out);
1145 if (oldstyle)
1146 goto parsebackq_oldreturn;
1147 else
1148 goto parsebackq_newreturn;
1149 }
1150
1151 } /* end of readtoken */
1152
1153
1154
1155 #ifdef mkinit
1156 RESET {
1157 tokpushback = 0;
1158 }
1159 #endif
1160
1161
1162 #if ATTY
1163 /*
1164 * Called to process a command generated by atty. We execute the line,
1165 * and catch any errors that occur so they don't propagate outside of
1166 * this routine.
1167 */
1168
1169 STATIC void
1170 attyline() {
1171 char line[256];
1172 struct stackmark smark;
1173 struct jmploc jmploc;
1174 struct jmploc *volatile savehandler;
1175
1176 if (pfgets(line, sizeof line) == NULL)
1177 return; /* "can't happen" */
1178 if (setjmp(jmploc.loc)) {
1179 if (exception == EXERROR)
1180 out2str("\033]D\n");
1181 handler = savehandler;
1182 longjmp(handler->loc, 1);
1183 }
1184 savehandler = handler;
1185 handler = &jmploc;
1186 setstackmark(&smark);
1187 evalstring(line);
1188 popstackmark(&smark);
1189 handler = savehandler;
1190 doprompt = 1;
1191 }
1192
1193
1194 /*
1195 * Output a prompt for atty. We output the prompt as part of the
1196 * appropriate escape sequence.
1197 */
1198
1199 STATIC void
1200 putprompt(s)
1201 char *s;
1202 {
1203 register char *p;
1204
1205 if (attyset() && ! equal(termval(), "emacs")) {
1206 if (strchr(s, '\7'))
1207 out2c('\7');
1208 out2str("\033]P1;");
1209 for (p = s ; *p ; p++) {
1210 if ((unsigned)(*p - ' ') <= '~' - ' ')
1211 out2c(*p);
1212 }
1213 out2c('\n');
1214 } else {
1215 out2str(s);
1216 }
1217 }
1218 #endif
1219
1220
1221
1222 /*
1223 * Returns true if the text contains nothing to expand (no dollar signs
1224 * or backquotes).
1225 */
1226
1227 STATIC int
1228 noexpand(text)
1229 char *text;
1230 {
1231 register char *p;
1232 register char c;
1233
1234 p = text;
1235 while ((c = *p++) != '\0') {
1236 if (c == CTLESC)
1237 p++;
1238 else if (BASESYNTAX[c] == CCTL)
1239 return 0;
1240 }
1241 return 1;
1242 }
1243
1244
1245 /*
1246 * Return true if the argument is a legal variable name (a letter or
1247 * underscore followed by zero or more letters, underscores, and digits).
1248 */
1249
1250 int
1251 goodname(name)
1252 char *name;
1253 {
1254 register char *p;
1255
1256 p = name;
1257 if (! is_name(*p))
1258 return 0;
1259 while (*++p) {
1260 if (! is_in_name(*p))
1261 return 0;
1262 }
1263 return 1;
1264 }
1265
1266
1267 /*
1268 * Called when an unexpected token is read during the parse. The argument
1269 * is the token that is expected, or -1 if more than one type of token can
1270 * occur at this point.
1271 */
1272
1273 STATIC void
1274 synexpect(token) {
1275 char msg[64];
1276
1277 if (token >= 0) {
1278 fmtstr(msg, 64, "%s unexpected (expecting %s)",
1279 tokname[lasttoken], tokname[token]);
1280 } else {
1281 fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1282 }
1283 synerror(msg);
1284 }
1285
1286
1287 STATIC void
1288 synerror(msg)
1289 char *msg;
1290 {
1291 if (commandname)
1292 outfmt(&errout, "%s: %d: ", commandname, startlinno);
1293 outfmt(&errout, "Syntax error: %s\n", msg);
1294 error((char *)NULL);
1295 }
1296