1 /* $Header: /p/tcsh/cvsroot/tcsh/sh.parse.c,v 3.18 2006/03/02 18:46:44 christos Exp $ */
3 * sh.parse.c: Interpret a list of tokens
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 RCSID("$tcsh: sh.parse.c,v 3.18 2006/03/02 18:46:44 christos Exp $")
40 static int asyntax (struct wordent
*, struct wordent
*);
41 static int asyn0 (struct wordent
*, struct wordent
*);
42 static int asyn3 (struct wordent
*, struct wordent
*);
43 static struct wordent
*freenod (struct wordent
*, struct wordent
*);
44 static struct command
*syn0 (const struct wordent
*, const struct wordent
*, int);
45 static struct command
*syn1 (const struct wordent
*, const struct wordent
*, int);
46 static struct command
*syn1a (const struct wordent
*, const struct wordent
*, int);
47 static struct command
*syn1b (const struct wordent
*, const struct wordent
*, int);
48 static struct command
*syn2 (const struct wordent
*, const struct wordent
*, int);
49 static struct command
*syn3 (const struct wordent
*, const struct wordent
*, int);
51 #define ALEFT 51 /* max of 50 alias expansions */
52 #define HLEFT 11 /* max of 10 history expansions */
54 * Perform aliasing on the word list lexp
55 * Do a (very rudimentary) parse to separate into commands.
56 * If word 0 of a command has an alias, do it.
57 * Repeat a maximum of 50 times.
61 alias(struct wordent
*lexp
)
69 stderror(ERR_ALIASLOOP
);
70 } while (asyntax(lexp
->next
, lexp
) != 0);
74 asyntax(struct wordent
*p1
, struct wordent
*p2
)
77 if (!any(";&\n", p1
->word
[0]))
85 asyn0(struct wordent
*p1
, struct wordent
*p2
)
90 for (p
= p1
; p
!= p2
; p
= p
->next
)
100 stderror(ERR_TOOMANYRP
);
104 if (p
->next
!= p2
&& eq(p
->next
->word
, STRand
))
114 if (asyn3(p1
, p
) != 0)
116 return asyntax(p
->next
, p2
);
122 return asyn3(p1
, p2
);
127 alvec_cleanup(void *dummy
)
136 asyn3(struct wordent
*p1
, struct wordent
*p2
)
139 struct wordent alout
;
144 if (p1
->word
[0] == '(') {
145 for (p2
= p2
->prev
; p2
->word
[0] != ')'; p2
= p2
->prev
)
150 return asyn0(p1
->next
, p2
);
152 ap
= adrof1(p1
->word
, &aliases
);
158 cleanup_push(&alvec
, alvec_cleanup
);
160 cleanup_until(&alvec
);
165 if (p1
->word
[0] && eq(p1
->word
, alout
.next
->word
)) {
166 Char
*cp
= alout
.next
->word
;
168 alout
.next
->word
= Strspl(STRQNULL
, cp
);
171 p1
= freenod(p1
, redid
? p2
: p1
->next
);
172 if (alout
.next
!= &alout
) {
173 p1
->next
->prev
= alout
.prev
->prev
;
174 alout
.prev
->prev
->next
= p1
->next
;
175 alout
.next
->prev
= p1
;
176 p1
->next
= alout
.next
;
177 xfree(alout
.prev
->word
);
183 static struct wordent
*
184 freenod(struct wordent
*p1
, struct wordent
*p2
)
186 struct wordent
*retp
= p1
->prev
;
209 syntax(const struct wordent
*p1
, const struct wordent
*p2
, int flags
)
213 if (any(";&\n", p1
->word
[0]))
216 return (syn0(p1
, p2
, flags
));
225 static struct command
*
226 syn0(const struct wordent
*p1
, const struct wordent
*p2
, int flags
)
228 const struct wordent
*p
;
229 struct command
*t
, *t1
;
233 for (p
= p1
; p
!= p2
; p
= p
->next
)
234 switch (p
->word
[0]) {
243 seterror(ERR_TOOMANYRP
);
247 if (p
->word
[1] == '|')
252 if (p
->next
!= p2
&& eq(p
->next
->word
, STRand
))
259 if (p
->word
[1] == '&')
261 t1
= syn1(p1
, p
, flags
);
262 if (t1
->t_dtyp
== NODE_LIST
||
263 t1
->t_dtyp
== NODE_AND
||
264 t1
->t_dtyp
== NODE_OR
) {
265 t
= xcalloc(1, sizeof(*t
));
266 t
->t_dtyp
= NODE_PAREN
;
267 t
->t_dflg
= F_AMPERSAND
| F_NOINTERRUPT
;
272 t1
->t_dflg
|= F_AMPERSAND
| F_NOINTERRUPT
;
273 t
= xcalloc(1, sizeof(*t
));
274 t
->t_dtyp
= NODE_LIST
;
277 t
->t_dcdr
= syntax(p
, p2
, flags
);
283 return (syn1(p1
, p2
, flags
));
284 seterror(ERR_TOOMANYLP
);
293 static struct command
*
294 syn1(const struct wordent
*p1
, const struct wordent
*p2
, int flags
)
296 const struct wordent
*p
;
301 for (p
= p1
; p
!= p2
; p
= p
->next
)
302 switch (p
->word
[0]) {
316 t
= xcalloc(1, sizeof(*t
));
317 t
->t_dtyp
= NODE_LIST
;
318 t
->t_dcar
= syn1a(p1
, p
, flags
);
319 t
->t_dcdr
= syntax(p
->next
, p2
, flags
);
321 t
->t_dcdr
= t
->t_dcar
, t
->t_dcar
= 0;
327 return (syn1a(p1
, p2
, flags
));
335 static struct command
*
336 syn1a(const struct wordent
*p1
, const struct wordent
*p2
, int flags
)
338 const struct wordent
*p
;
342 for (p
= p1
; p
!= p2
; p
= p
->next
)
343 switch (p
->word
[0]) {
354 if (p
->word
[1] != '|')
357 t
= xcalloc(1, sizeof(*t
));
359 t
->t_dcar
= syn1b(p1
, p
, flags
);
360 t
->t_dcdr
= syn1a(p
->next
, p2
, flags
);
369 return (syn1b(p1
, p2
, flags
));
377 static struct command
*
378 syn1b(const struct wordent
*p1
, const struct wordent
*p2
, int flags
)
380 const struct wordent
*p
;
384 for (p
= p1
; p
!= p2
; p
= p
->next
)
385 switch (p
->word
[0]) {
396 if (p
->word
[1] == '&' && l
== 0) {
397 t
= xcalloc(1, sizeof(*t
));
398 t
->t_dtyp
= NODE_AND
;
399 t
->t_dcar
= syn2(p1
, p
, flags
);
400 t
->t_dcdr
= syn1b(p
->next
, p2
, flags
);
409 return (syn2(p1
, p2
, flags
));
418 static struct command
*
419 syn2(const struct wordent
*p1
, const struct wordent
*p2
, int flags
)
421 const struct wordent
*p
, *pn
;
426 for (p
= p1
; p
!= p2
; p
= p
->next
)
427 switch (p
->word
[0]) {
440 t
= xcalloc(1, sizeof(*t
));
443 if (pn
!= p2
&& pn
->word
[0] == '&') {
445 t
->t_dflg
|= F_STDERR
;
447 t
->t_dtyp
= NODE_PIPE
;
448 t
->t_dcar
= syn3(p1
, p
, f
);
449 if (pn
!= p2
&& pn
->word
[0] == '&')
451 t
->t_dcdr
= syn2(p
->next
, p2
, flags
| P_IN
);
457 return (syn3(p1
, p2
, flags
));
460 static const char RELPAR
[] = {'<', '>', '(', ')', '\0'};
464 * ( syn0 ) [ < in ] [ > out ]
465 * word word* [ < in ] [ > out ]
466 * KEYWORD ( word* ) word* [ < in ] [ > out ]
468 * KEYWORD = (@ exit foreach if set switch test while)
470 static struct command
*
471 syn3(const struct wordent
*p1
, const struct wordent
*p2
, int flags
)
473 const struct wordent
*p
;
474 const struct wordent
*lp
, *rp
;
484 switch (srchx(p
->word
)) {
507 for (p
= p1
; p
!= p2
; p
= p
->next
)
508 switch (p
->word
[0]) {
531 if (any(RELPAR
, p
->next
->word
[0]))
537 if (!specp
&& l
!= 0)
544 t
= xcalloc(1, sizeof(*t
));
545 av
= xcalloc(n
+ 1, sizeof(Char
**));
548 if (p2
->word
[0] == ')')
549 t
->t_dflg
= F_NOFORK
;
553 for (p
= p1
; p
!= p2
; p
= p
->next
) {
559 if (lp
!= 0 && !specp
)
560 seterror(ERR_BADPLP
);
575 if (p
->word
[1] == '>')
576 t
->t_dflg
|= F_APPEND
;
577 if (p
->next
!= p2
&& eq(p
->next
->word
, STRand
)) {
578 t
->t_dflg
|= F_STDERR
, p
= p
->next
;
579 if (flags
& (P_OUT
| P_DIAG
)) {
580 seterror(ERR_OUTRED
);
584 if (p
->next
!= p2
&& eq(p
->next
->word
, STRbang
))
585 t
->t_dflg
|= F_OVERWRITE
, p
= p
->next
;
587 seterror(ERR_MISRED
);
591 if (any(RELPAR
, p
->word
[0])) {
592 seterror(ERR_MISRED
);
595 if (((flags
& P_OUT
) && (flags
& P_DIAG
) == 0) || t
->t_drit
)
596 seterror(ERR_OUTRED
);
598 t
->t_drit
= Strsave(p
->word
);
604 if (p
->word
[1] == '<')
607 seterror(ERR_MISRED
);
611 if (any(RELPAR
, p
->word
[0])) {
612 seterror(ERR_MISRED
);
615 if ((flags
& P_HERE
) && (t
->t_dflg
& F_READ
))
616 seterror(ERR_REDPAR
);
617 else if ((flags
& P_IN
) || t
->t_dlef
)
620 t
->t_dlef
= Strsave(p
->word
);
627 if (l
!= 0 && !specp
)
630 av
[n
] = Strsave(p
->word
);
635 if (lp
!= 0 && !specp
) {
637 seterror(ERR_BADPLPS
);
638 t
->t_dtyp
= NODE_PAREN
;
639 t
->t_dspr
= syn0(lp
, rp
, P_HERE
);
643 seterror(ERR_NULLCOM
);
644 t
->t_dtyp
= NODE_COMMAND
;
650 freesyn(struct command
*t
)
659 for (v
= t
->t_dcom
; *v
; v
++)
675 freesyn(t
->t_dcar
), freesyn(t
->t_dcdr
);
684 syntax_cleanup(void *xt
)