upgrading to sun-lamp's sh(1) + patches from Nate.
[unix-history] / bin / sh / parser.c
CommitLineData
15637ed4
RG
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.
15637ed4
RG
35 */
36
37#ifndef lint
68de1ca3
AM
38/*static char sccsid[] = "from: @(#)parser.c 5.3 (Berkeley) 4/12/91";*/
39static char rcsid[] = "parser.c,v 1.8 1993/08/01 18:58:02 mycroft Exp";
15637ed4
RG
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
68struct 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
77struct heredoc *heredoclist; /* list of here documents to read */
78int parsebackquote; /* nonzero if we are inside backquotes */
79int doprompt; /* if set, prompt the user */
80int needprompt; /* true if interactive and at start of line */
81int lasttoken; /* last token read */
82MKINIT int tokpushback; /* last token pushed back */
83char *wordtext; /* text of last word returned by readtoken */
84int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */
85struct nodelist *backquotelist;
86union node *redirnode;
87struct heredoc *heredoc;
88int quoteflag; /* set if (part of) last token was quoted */
89int 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
94static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'};
95static const char types[] = "}-+?=";
96#endif
97
98
99STATIC union node *list __P((int));
100STATIC union node *andor __P((void));
101STATIC union node *pipeline __P((void));
102STATIC union node *command __P((void));
103STATIC union node *simplecmd __P((union node **, union node *));
104STATIC void parsefname __P((void));
105STATIC void parseheredoc __P((void));
106STATIC int readtoken __P((void));
107STATIC int readtoken1 __P((int, char const *, char *, int));
108STATIC void attyline __P((void));
109STATIC int noexpand __P((char *));
110STATIC void synexpect __P((int));
111STATIC void synerror __P((char *));
112
113#if ATTY
114STATIC 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
127union node *
128parsecmd(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
144STATIC union node *
145list(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 */
170tsemi: 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
205STATIC union node *
206andor() {
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
231STATIC union node *
232pipeline() {
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
259STATIC union node *
260command() {
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) {
313TRACE(("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
461STATIC union node *
462simplecmd(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
520STATIC void
521parsefname() {
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') {
557bad:
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
575STATIC void
576parseheredoc() {
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
598STATIC int
599peektoken() {
600 int t;
601
602 t = readtoken();
603 tokpushback++;
604 return (t);
605}
606
607STATIC int xxreadtoken();
608
609STATIC int
610readtoken() {
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) {
fa5ccf6c 634 register char *const *pp;
15637ed4
RG
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
675STATIC int
676xxreadtoken() {
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 }
737breakloop:
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
762STATIC int
763readtoken1(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 }
878endword:
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
914checkend: {
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
946parseredir: {
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
998parsesub: {
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))
1029badsub: 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
1064parsebackq: {
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;
fa5ccf6c 1079 longjmp(handler->loc, 1);
15637ed4
RG
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;
f611327b
C
1128 /* Start reading from old file again, and clear tokpushback since
1129 any pushed back token from the string is no longer relevant. */
1130 if (oldstyle) {
15637ed4 1131 popfile();
f611327b
C
1132 tokpushback = 0;
1133 }
15637ed4
RG
1134 while (stackblocksize() <= savelen)
1135 growstackblock();
1136 STARTSTACKSTR(out);
1137 if (str) {
1138 bcopy(str, out, savelen);
1139 STADJUST(savelen, out);
1140 INTOFF;
1141 ckfree(str);
1142 str = NULL;
1143 INTON;
1144 }
1145 parsebackquote = savepbq;
1146 handler = savehandler;
1147 USTPUTC(CTLBACKQ + dblquote, out);
1148 if (oldstyle)
1149 goto parsebackq_oldreturn;
1150 else
1151 goto parsebackq_newreturn;
1152}
1153
1154} /* end of readtoken */
1155
1156
1157
1158#ifdef mkinit
1159RESET {
1160 tokpushback = 0;
1161}
1162#endif
1163
1164
1165#if ATTY
1166/*
1167 * Called to process a command generated by atty. We execute the line,
1168 * and catch any errors that occur so they don't propagate outside of
1169 * this routine.
1170 */
1171
1172STATIC void
1173attyline() {
1174 char line[256];
1175 struct stackmark smark;
1176 struct jmploc jmploc;
1177 struct jmploc *volatile savehandler;
1178
1179 if (pfgets(line, sizeof line) == NULL)
1180 return; /* "can't happen" */
1181 if (setjmp(jmploc.loc)) {
1182 if (exception == EXERROR)
1183 out2str("\033]D\n");
1184 handler = savehandler;
68de1ca3 1185 longjmp(handler->loc, 1);
15637ed4
RG
1186 }
1187 savehandler = handler;
1188 handler = &jmploc;
1189 setstackmark(&smark);
1190 evalstring(line);
1191 popstackmark(&smark);
1192 handler = savehandler;
1193 doprompt = 1;
1194}
1195
1196
1197/*
1198 * Output a prompt for atty. We output the prompt as part of the
1199 * appropriate escape sequence.
1200 */
1201
1202STATIC void
1203putprompt(s)
1204 char *s;
1205 {
1206 register char *p;
1207
1208 if (attyset() && ! equal(termval(), "emacs")) {
1209 if (strchr(s, '\7'))
1210 out2c('\7');
1211 out2str("\033]P1;");
1212 for (p = s ; *p ; p++) {
1213 if ((unsigned)(*p - ' ') <= '~' - ' ')
1214 out2c(*p);
1215 }
1216 out2c('\n');
1217 } else {
1218 out2str(s);
1219 }
1220}
1221#endif
1222
1223
1224
1225/*
1226 * Returns true if the text contains nothing to expand (no dollar signs
1227 * or backquotes).
1228 */
1229
1230STATIC int
1231noexpand(text)
1232 char *text;
1233 {
1234 register char *p;
1235 register char c;
1236
1237 p = text;
1238 while ((c = *p++) != '\0') {
1239 if (c == CTLESC)
1240 p++;
1241 else if (BASESYNTAX[c] == CCTL)
1242 return 0;
1243 }
1244 return 1;
1245}
1246
1247
1248/*
1249 * Return true if the argument is a legal variable name (a letter or
1250 * underscore followed by zero or more letters, underscores, and digits).
1251 */
1252
1253int
1254goodname(name)
1255 char *name;
1256 {
1257 register char *p;
1258
1259 p = name;
1260 if (! is_name(*p))
1261 return 0;
1262 while (*++p) {
1263 if (! is_in_name(*p))
1264 return 0;
1265 }
1266 return 1;
1267}
1268
1269
1270/*
1271 * Called when an unexpected token is read during the parse. The argument
1272 * is the token that is expected, or -1 if more than one type of token can
1273 * occur at this point.
1274 */
1275
1276STATIC void
1277synexpect(token) {
1278 char msg[64];
1279
1280 if (token >= 0) {
1281 fmtstr(msg, 64, "%s unexpected (expecting %s)",
1282 tokname[lasttoken], tokname[token]);
1283 } else {
1284 fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]);
1285 }
1286 synerror(msg);
1287}
1288
1289
1290STATIC void
1291synerror(msg)
1292 char *msg;
1293 {
1294 if (commandname)
1295 outfmt(&errout, "%s: %d: ", commandname, startlinno);
1296 outfmt(&errout, "Syntax error: %s\n", msg);
1297 error((char *)NULL);
1298}