Blob


1 %term FOR IN WHILE IF NOT TWIDDLE BANG SUBSHELL SWITCH FN
2 %term WORD REDIR DUP PIPE SUB
3 %term SIMPLE ARGLIST WORDS BRACE PAREN PCMD PIPEFD /* not used in syntax */
4 /* operator priorities -- lowest first */
5 %left LOW
6 %left IF WHILE FOR SWITCH ')' NOT
7 %left ANDAND OROR
8 %left BANG SUBSHELL
9 %left PIPE
10 %left '^'
11 %right '$' COUNT '"'
12 %left SUB
13 %left '='
14 %{
15 #include "rc.h"
16 #include "fns.h"
17 %}
18 %union{
19 struct tree *tree;
20 };
21 %type<tree> line paren brace body cmdsa cmdsan assign epilog redir
22 %type<tree> cmd simple first word comword keyword words
23 %type<tree> NOT FOR IN WHILE IF TWIDDLE BANG SUBSHELL SWITCH FN
24 %type<tree> WORD REDIR DUP PIPE
25 %%
26 rc: { return 1;}
27 | line '\n' {return !compile($1);}
28 line: cmd
29 | cmdsa line {$$=tree2(';', $1, $2);}
30 body: cmd
31 | cmdsan body {$$=tree2(';', $1, $2);}
32 cmdsa: cmd ';'
33 | cmd '&' {$$=tree1('&', $1);}
34 cmdsan: cmdsa
35 | cmd '\n'
36 brace: '{' body '}' {$$=tree1(BRACE, $2);}
37 paren: '(' body ')' {$$=tree1(PCMD, $2);}
38 assign: first '=' word {$$=tree2('=', $1, $3);}
39 epilog: {$$=0;}
40 | redir epilog {$$=mung2($1, $1->child[0], $2);}
41 redir: REDIR word {$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);}
42 | DUP
43 cmd: {$$=0;}
44 | brace epilog {$$=epimung($1, $2);}
45 | IF paren {skipnl();} cmd
46 {$$=mung2($1, $2, $4);}
47 | IF NOT {skipnl();} cmd {$$=mung1($2, $4);}
48 | FOR '(' word IN words ')' {skipnl();} cmd
49 /*
50 * if ``words'' is nil, we need a tree element to distinguish between
51 * for(i in ) and for(i), the former being a loop over the empty set
52 * and the latter being the implicit argument loop. so if $5 is nil
53 * (the empty set), we represent it as "()". don't parenthesize non-nil
54 * functions, to avoid growing parentheses every time we reread the
55 * definition.
56 */
57 {$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);}
58 | FOR '(' word ')' {skipnl();} cmd
59 {$$=mung3($1, $3, (struct tree *)0, $6);}
60 | WHILE paren {skipnl();} cmd
61 {$$=mung2($1, $2, $4);}
62 | SWITCH word {skipnl();} brace
63 {$$=tree2(SWITCH, $2, $4);}
64 | simple {$$=simplemung($1);}
65 | TWIDDLE word words {$$=mung2($1, $2, $3);}
66 | cmd ANDAND cmd {$$=tree2(ANDAND, $1, $3);}
67 | cmd OROR cmd {$$=tree2(OROR, $1, $3);}
68 | cmd PIPE cmd {$$=mung2($2, $1, $3);}
69 | redir cmd %prec BANG {$$=mung2($1, $1->child[0], $2);}
70 | assign cmd %prec BANG {$$=mung3($1, $1->child[0], $1->child[1], $2);}
71 | BANG cmd {$$=mung1($1, $2);}
72 | SUBSHELL cmd {$$=mung1($1, $2);}
73 | FN words brace {$$=tree2(FN, $2, $3);}
74 | FN words {$$=tree1(FN, $2);}
75 simple: first
76 | simple word {$$=tree2(ARGLIST, $1, $2);}
77 | simple redir {$$=tree2(ARGLIST, $1, $2);}
78 first: comword
79 | first '^' word {$$=tree2('^', $1, $3);}
80 word: keyword {lastword=1; $1->type=WORD;}
81 | comword
82 | word '^' word {$$=tree2('^', $1, $3);}
83 | word '=' word %prec LOW {$$=tree2('^', tree2('^', $1, token("=", WORD)), $3);}
84 comword: '$' word {$$=tree1('$', $2);}
85 | '$' word SUB words ')' {$$=tree2(SUB, $2, $4);}
86 | '"' word {$$=tree1('"', $2);}
87 | COUNT word {$$=tree1(COUNT, $2);}
88 | WORD
89 | '`' brace {$$=tree1('`', $2);}
90 | '(' words ')' {$$=tree1(PAREN, $2);}
91 | REDIR brace {$$=mung1($1, $2); $$->type=PIPEFD;}
92 keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN
93 words: {$$=(struct tree*)0;}
94 | words word {$$=tree2(WORDS, $1, $2);}