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