source: trunk/third/tcsh/sh.parse.c @ 22036

Revision 22036, 13.4 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r22035, which included commits to RCS files with non-trunk default branches.
Line 
1/* $Header: /afs/dev.mit.edu/source/repository/third/tcsh/sh.parse.c,v 1.1.1.3 2005-06-03 14:35:04 ghudson Exp $ */
2/*
3 * sh.parse.c: Interpret a list of tokens
4 */
5/*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
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.
20 *
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
31 * SUCH DAMAGE.
32 */
33#include "sh.h"
34
35RCSID("$Id: sh.parse.c,v 1.1.1.3 2005-06-03 14:35:04 ghudson Exp $")
36
37/*
38 * C shell
39 */
40static  void             asyntax __P((struct wordent *, struct wordent *));
41static  void             asyn0   __P((struct wordent *, struct wordent *));
42static  void             asyn3   __P((struct wordent *, struct wordent *));
43static  struct wordent  *freenod __P((struct wordent *, struct wordent *));
44static  struct command  *syn0    __P((struct wordent *, struct wordent *, int));
45static  struct command  *syn1    __P((struct wordent *, struct wordent *, int));
46static  struct command  *syn1a   __P((struct wordent *, struct wordent *, int));
47static  struct command  *syn1b   __P((struct wordent *, struct wordent *, int));
48static  struct command  *syn2    __P((struct wordent *, struct wordent *, int));
49static  struct command  *syn3    __P((struct wordent *, struct wordent *, int));
50
51#define ALEFT   51              /* max of 50 alias expansions    */
52#define HLEFT   11              /* max of 10 history expansions */
53/*
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.
58 */
59static int aleft;
60extern int hleft;
61void
62alias(lexp)
63    struct wordent *lexp;
64{
65    jmp_buf_t osetexit;
66
67    aleft = ALEFT;
68    hleft = HLEFT;
69    getexit(osetexit);
70    (void) setexit();
71    if (haderr) {
72        resexit(osetexit);
73        reset();
74    }
75    if (--aleft == 0)
76        stderror(ERR_ALIASLOOP);
77    asyntax(lexp->next, lexp);
78    resexit(osetexit);
79}
80
81static void
82asyntax(p1, p2)
83    struct wordent *p1, *p2;
84{
85    while (p1 != p2)
86        if (any(";&\n", p1->word[0]))
87            p1 = p1->next;
88        else {
89            asyn0(p1, p2);
90            return;
91        }
92}
93
94static void
95asyn0(p1, p2)
96    struct wordent *p1;
97    struct wordent *p2;
98{
99    struct wordent *p;
100    int l = 0;
101
102    for (p = p1; p != p2; p = p->next)
103        switch (p->word[0]) {
104
105        case '(':
106            l++;
107            continue;
108
109        case ')':
110            l--;
111            if (l < 0)
112                stderror(ERR_TOOMANYRP);
113            continue;
114
115        case '>':
116            if (p->next != p2 && eq(p->next->word, STRand))
117                p = p->next;
118            continue;
119
120        case '&':
121        case '|':
122        case ';':
123        case '\n':
124            if (l != 0)
125                continue;
126            asyn3(p1, p);
127            asyntax(p->next, p2);
128            return;
129
130        default:
131            break;
132        }
133    if (l == 0)
134        asyn3(p1, p2);
135}
136
137static void
138asyn3(p1, p2)
139    struct wordent *p1;
140    struct wordent *p2;
141{
142    struct varent *ap;
143    struct wordent alout;
144    int redid;
145
146    if (p1 == p2)
147        return;
148    if (p1->word[0] == '(') {
149        for (p2 = p2->prev; p2->word[0] != ')'; p2 = p2->prev)
150            if (p2 == p1)
151                return;
152        if (p2 == p1->next)
153            return;
154        asyn0(p1->next, p2);
155        return;
156    }
157    ap = adrof1(p1->word, &aliases);
158    if (ap == 0)
159        return;
160    alhistp = p1->prev;
161    alhistt = p2;
162    alvec = ap->vec;
163    redid = lex(&alout);
164    alhistp = alhistt = 0;
165    alvec = 0;
166    if (seterr) {
167        freelex(&alout);
168        stderror(ERR_OLD);
169    }
170    if (p1->word[0] && eq(p1->word, alout.next->word)) {
171        Char   *cp = alout.next->word;
172
173        alout.next->word = Strspl(STRQNULL, cp);
174        xfree((ptr_t) cp);
175    }
176    p1 = freenod(p1, redid ? p2 : p1->next);
177    if (alout.next != &alout) {
178        p1->next->prev = alout.prev->prev;
179        alout.prev->prev->next = p1->next;
180        alout.next->prev = p1;
181        p1->next = alout.next;
182        xfree((ptr_t) alout.prev->word);
183        xfree((ptr_t) (alout.prev));
184    }
185    reset();                    /* throw! */
186}
187
188static struct wordent *
189freenod(p1, p2)
190    struct wordent *p1, *p2;
191{
192    struct wordent *retp = p1->prev;
193
194    while (p1 != p2) {
195        xfree((ptr_t) p1->word);
196        p1 = p1->next;
197        xfree((ptr_t) (p1->prev));
198    }
199    retp->next = p2;
200    p2->prev = retp;
201    return (retp);
202}
203
204#define P_HERE  1
205#define P_IN    2
206#define P_OUT   4
207#define P_DIAG  8
208
209/*
210 * syntax
211 *      empty
212 *      syn0
213 */
214struct command *
215syntax(p1, p2, flags)
216    struct wordent *p1, *p2;
217    int     flags;
218{
219
220    while (p1 != p2)
221        if (any(";&\n", p1->word[0]))
222            p1 = p1->next;
223        else
224            return (syn0(p1, p2, flags));
225    return (0);
226}
227
228/*
229 * syn0
230 *      syn1
231 *      syn1 & syntax
232 */
233static struct command *
234syn0(p1, p2, flags)
235    struct wordent *p1, *p2;
236    int     flags;
237{
238    struct wordent *p;
239    struct command *t, *t1;
240    int     l;
241
242    l = 0;
243    for (p = p1; p != p2; p = p->next)
244        switch (p->word[0]) {
245
246        case '(':
247            l++;
248            continue;
249
250        case ')':
251            l--;
252            if (l < 0)
253                seterror(ERR_TOOMANYRP);
254            continue;
255
256        case '|':
257            if (p->word[1] == '|')
258                continue;
259            /*FALLTHROUGH*/
260
261        case '>':
262            if (p->next != p2 && eq(p->next->word, STRand))
263                p = p->next;
264            continue;
265
266        case '&':
267            if (l != 0)
268                break;
269            if (p->word[1] == '&')
270                continue;
271            t1 = syn1(p1, p, flags);
272            if (t1->t_dtyp == NODE_LIST ||
273                t1->t_dtyp == NODE_AND ||
274                t1->t_dtyp == NODE_OR) {
275                t = (struct command *) xcalloc(1, sizeof(*t));
276                t->t_dtyp = NODE_PAREN;
277                t->t_dflg = F_AMPERSAND | F_NOINTERRUPT;
278                t->t_dspr = t1;
279                t1 = t;
280            }
281            else
282                t1->t_dflg |= F_AMPERSAND | F_NOINTERRUPT;
283            t = (struct command *) xcalloc(1, sizeof(*t));
284            t->t_dtyp = NODE_LIST;
285            t->t_dflg = 0;
286            t->t_dcar = t1;
287            t->t_dcdr = syntax(p, p2, flags);
288            return (t);
289        default:
290            break;
291        }
292    if (l == 0)
293        return (syn1(p1, p2, flags));
294    seterror(ERR_TOOMANYLP);
295    return (0);
296}
297
298/*
299 * syn1
300 *      syn1a
301 *      syn1a ; syntax
302 */
303static struct command *
304syn1(p1, p2, flags)
305    struct wordent *p1, *p2;
306    int     flags;
307{
308    struct wordent *p;
309    struct command *t;
310    int     l;
311
312    l = 0;
313    for (p = p1; p != p2; p = p->next)
314        switch (p->word[0]) {
315
316        case '(':
317            l++;
318            continue;
319
320        case ')':
321            l--;
322            continue;
323
324        case ';':
325        case '\n':
326            if (l != 0)
327                break;
328            t = (struct command *) xcalloc(1, sizeof(*t));
329            t->t_dtyp = NODE_LIST;
330            t->t_dcar = syn1a(p1, p, flags);
331            t->t_dcdr = syntax(p->next, p2, flags);
332            if (t->t_dcdr == 0)
333                t->t_dcdr = t->t_dcar, t->t_dcar = 0;
334            return (t);
335
336        default:
337            break;
338        }
339    return (syn1a(p1, p2, flags));
340}
341
342/*
343 * syn1a
344 *      syn1b
345 *      syn1b || syn1a
346 */
347static struct command *
348syn1a(p1, p2, flags)
349    struct wordent *p1, *p2;
350    int     flags;
351{
352    struct wordent *p;
353    struct command *t;
354    int l = 0;
355
356    for (p = p1; p != p2; p = p->next)
357        switch (p->word[0]) {
358
359        case '(':
360            l++;
361            continue;
362
363        case ')':
364            l--;
365            continue;
366
367        case '|':
368            if (p->word[1] != '|')
369                continue;
370            if (l == 0) {
371                t = (struct command *) xcalloc(1, sizeof(*t));
372                t->t_dtyp = NODE_OR;
373                t->t_dcar = syn1b(p1, p, flags);
374                t->t_dcdr = syn1a(p->next, p2, flags);
375                t->t_dflg = 0;
376                return (t);
377            }
378            continue;
379
380        default:
381            break;
382        }
383    return (syn1b(p1, p2, flags));
384}
385
386/*
387 * syn1b
388 *      syn2
389 *      syn2 && syn1b
390 */
391static struct command *
392syn1b(p1, p2, flags)
393    struct wordent *p1, *p2;
394    int     flags;
395{
396    struct wordent *p;
397    struct command *t;
398    int l = 0;
399
400    for (p = p1; p != p2; p = p->next)
401        switch (p->word[0]) {
402
403        case '(':
404            l++;
405            continue;
406
407        case ')':
408            l--;
409            continue;
410
411        case '&':
412            if (p->word[1] == '&' && l == 0) {
413                t = (struct command *) xcalloc(1, sizeof(*t));
414                t->t_dtyp = NODE_AND;
415                t->t_dcar = syn2(p1, p, flags);
416                t->t_dcdr = syn1b(p->next, p2, flags);
417                t->t_dflg = 0;
418                return (t);
419            }
420            continue;
421
422        default:
423            break;
424        }
425    return (syn2(p1, p2, flags));
426}
427
428/*
429 * syn2
430 *      syn3
431 *      syn3 | syn2
432 *      syn3 |& syn2
433 */
434static struct command *
435syn2(p1, p2, flags)
436    struct wordent *p1, *p2;
437    int     flags;
438{
439    struct wordent *p, *pn;
440    struct command *t;
441    int l = 0;
442    int     f;
443
444    for (p = p1; p != p2; p = p->next)
445        switch (p->word[0]) {
446
447        case '(':
448            l++;
449            continue;
450
451        case ')':
452            l--;
453            continue;
454
455        case '|':
456            if (l != 0)
457                continue;
458            t = (struct command *) xcalloc(1, sizeof(*t));
459            f = flags | P_OUT;
460            pn = p->next;
461            if (pn != p2 && pn->word[0] == '&') {
462                f |= P_DIAG;
463                t->t_dflg |= F_STDERR;
464            }
465            t->t_dtyp = NODE_PIPE;
466            t->t_dcar = syn3(p1, p, f);
467            if (pn != p2 && pn->word[0] == '&')
468                p = pn;
469            t->t_dcdr = syn2(p->next, p2, flags | P_IN);
470            return (t);
471
472        default:
473            break;
474        }
475    return (syn3(p1, p2, flags));
476}
477
478static char RELPAR[] = {'<', '>', '(', ')', '\0'};
479
480/*
481 * syn3
482 *      ( syn0 ) [ < in  ] [ > out ]
483 *      word word* [ < in ] [ > out ]
484 *      KEYWORD ( word* ) word* [ < in ] [ > out ]
485 *
486 *      KEYWORD = (@ exit foreach if set switch test while)
487 */
488static struct command *
489syn3(p1, p2, flags)
490    struct wordent *p1, *p2;
491    int     flags;
492{
493    struct wordent *p;
494    struct wordent *lp, *rp;
495    struct command *t;
496    int l;
497    Char  **av;
498    int     n, c;
499    int    specp = 0;
500
501    if (p1 != p2) {
502        p = p1;
503again:
504        switch (srchx(p->word)) {
505
506        case TC_ELSE:
507            p = p->next;
508            if (p != p2)
509                goto again;
510            break;
511
512        case TC_EXIT:
513        case TC_FOREACH:
514        case TC_IF:
515        case TC_LET:
516        case TC_SET:
517        case TC_SWITCH:
518        case TC_WHILE:
519            specp = 1;
520            break;
521        default:
522            break;
523        }
524    }
525    n = 0;
526    l = 0;
527    for (p = p1; p != p2; p = p->next)
528        switch (p->word[0]) {
529
530        case '(':
531            if (specp)
532                n++;
533            l++;
534            continue;
535
536        case ')':
537            if (specp)
538                n++;
539            l--;
540            continue;
541
542        case '>':
543        case '<':
544            if (l != 0) {
545                if (specp)
546                    n++;
547                continue;
548            }
549            if (p->next == p2)
550                continue;
551            if (any(RELPAR, p->next->word[0]))
552                continue;
553            n--;
554            continue;
555
556        default:
557            if (!specp && l != 0)
558                continue;
559            n++;
560            continue;
561        }
562    if (n < 0)
563        n = 0;
564    t = (struct command *) xcalloc(1, sizeof(*t));
565    av = (Char **) xcalloc((size_t) (n + 1), sizeof(Char **));
566    t->t_dcom = av;
567    n = 0;
568    if (p2->word[0] == ')')
569        t->t_dflg = F_NOFORK;
570    lp = 0;
571    rp = 0;
572    l = 0;
573    for (p = p1; p != p2; p = p->next) {
574        c = p->word[0];
575        switch (c) {
576
577        case '(':
578            if (l == 0) {
579                if (lp != 0 && !specp)
580                    seterror(ERR_BADPLP);
581                lp = p->next;
582            }
583            l++;
584            goto savep;
585
586        case ')':
587            l--;
588            if (l == 0)
589                rp = p;
590            goto savep;
591
592        case '>':
593            if (l != 0)
594                goto savep;
595            if (p->word[1] == '>')
596                t->t_dflg |= F_APPEND;
597            if (p->next != p2 && eq(p->next->word, STRand)) {
598                t->t_dflg |= F_STDERR, p = p->next;
599                if (flags & (P_OUT | P_DIAG)) {
600                    seterror(ERR_OUTRED);
601                    continue;
602                }
603            }
604            if (p->next != p2 && eq(p->next->word, STRbang))
605                t->t_dflg |= F_OVERWRITE, p = p->next;
606            if (p->next == p2) {
607                seterror(ERR_MISRED);
608                continue;
609            }
610            p = p->next;
611            if (any(RELPAR, p->word[0])) {
612                seterror(ERR_MISRED);
613                continue;
614            }
615            if (((flags & P_OUT) && (flags & P_DIAG) == 0) || t->t_drit)
616                seterror(ERR_OUTRED);
617            else
618                t->t_drit = Strsave(p->word);
619            continue;
620
621        case '<':
622            if (l != 0)
623                goto savep;
624            if (p->word[1] == '<')
625                t->t_dflg |= F_READ;
626            if (p->next == p2) {
627                seterror(ERR_MISRED);
628                continue;
629            }
630            p = p->next;
631            if (any(RELPAR, p->word[0])) {
632                seterror(ERR_MISRED);
633                continue;
634            }
635            if ((flags & P_HERE) && (t->t_dflg & F_READ))
636                seterror(ERR_REDPAR);
637            else if ((flags & P_IN) || t->t_dlef)
638                seterror(ERR_INRED);
639            else
640                t->t_dlef = Strsave(p->word);
641            continue;
642
643    savep:
644            if (!specp)
645                continue;
646        default:
647            if (l != 0 && !specp)
648                continue;
649            if (seterr == 0)
650                av[n] = Strsave(p->word);
651            n++;
652            continue;
653        }
654    }
655    if (lp != 0 && !specp) {
656        if (n != 0)
657            seterror(ERR_BADPLPS);
658        t->t_dtyp = NODE_PAREN;
659        t->t_dspr = syn0(lp, rp, P_HERE);
660    }
661    else {
662        if (n == 0)
663            seterror(ERR_NULLCOM);
664        t->t_dtyp = NODE_COMMAND;
665    }
666    return (t);
667}
668
669void
670freesyn(t)
671    struct command *t;
672{
673    Char **v;
674
675    if (t == 0)
676        return;
677    switch (t->t_dtyp) {
678
679    case NODE_COMMAND:
680        for (v = t->t_dcom; *v; v++)
681            xfree((ptr_t) * v);
682        xfree((ptr_t) (t->t_dcom));
683        xfree((ptr_t) t->t_dlef);
684        xfree((ptr_t) t->t_drit);
685        break;
686    case NODE_PAREN:
687        freesyn(t->t_dspr);
688        xfree((ptr_t) t->t_dlef);
689        xfree((ptr_t) t->t_drit);
690        break;
691
692    case NODE_AND:
693    case NODE_OR:
694    case NODE_PIPE:
695    case NODE_LIST:
696        freesyn(t->t_dcar), freesyn(t->t_dcdr);
697        break;
698    default:
699        break;
700    }
701    xfree((ptr_t) t);
702}
Note: See TracBrowser for help on using the repository browser.