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