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