| %term FOR IN WHILE IF NOT TWIDDLE BANG SUBSHELL SWITCH FN |
| %term WORD REDIR DUP PIPE SUB |
| %term SIMPLE ARGLIST WORDS BRACE PAREN PCMD PIPEFD /* not used in syntax */ |
| /* operator priorities -- lowest first */ |
| %left IF WHILE FOR SWITCH ')' NOT |
| %left ANDAND OROR |
| %left BANG SUBSHELL |
| %left PIPE |
| %left '^' |
| %right '$' COUNT '"' |
| %left SUB |
| %{ |
| #include "rc.h" |
| #include "fns.h" |
| %} |
| %union{ |
| struct tree *tree; |
| }; |
| %type<tree> line paren brace body cmdsa cmdsan assign epilog redir |
| %type<tree> cmd simple first word comword keyword words |
| %type<tree> NOT FOR IN WHILE IF TWIDDLE BANG SUBSHELL SWITCH FN |
| %type<tree> WORD REDIR DUP PIPE |
| %% |
| rc: { return 1;} |
| | line '\n' {return !compile($1);} |
| line: cmd |
| | cmdsa line {$$=tree2(';', $1, $2);} |
| body: cmd |
| | cmdsan body {$$=tree2(';', $1, $2);} |
| cmdsa: cmd ';' |
| | cmd '&' {$$=tree1('&', $1);} |
| cmdsan: cmdsa |
| | cmd '\n' |
| brace: '{' body '}' {$$=tree1(BRACE, $2);} |
| paren: '(' body ')' {$$=tree1(PCMD, $2);} |
| assign: first '=' word {$$=tree2('=', $1, $3);} |
| epilog: {$$=0;} |
| | redir epilog {$$=mung2($1, $1->child[0], $2);} |
| redir: REDIR word {$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);} |
| | DUP |
| cmd: {$$=0;} |
| | brace epilog {$$=epimung($1, $2);} |
| | IF paren {skipnl();} cmd |
| {$$=mung2($1, $2, $4);} |
| | IF NOT {skipnl();} cmd {$$=mung1($2, $4);} |
| | FOR '(' word IN words ')' {skipnl();} cmd |
| /* |
| * if ``words'' is nil, we need a tree element to distinguish between |
| * for(i in ) and for(i), the former being a loop over the empty set |
| * and the latter being the implicit argument loop. so if $5 is nil |
| * (the empty set), we represent it as "()". don't parenthesize non-nil |
| * functions, to avoid growing parentheses every time we reread the |
| * definition. |
| */ |
| {$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);} |
| | FOR '(' word ')' {skipnl();} cmd |
| {$$=mung3($1, $3, (struct tree *)0, $6);} |
| | WHILE paren {skipnl();} cmd |
| {$$=mung2($1, $2, $4);} |
| | SWITCH word {skipnl();} brace |
| {$$=tree2(SWITCH, $2, $4);} |
| | simple {$$=simplemung($1);} |
| | TWIDDLE word words {$$=mung2($1, $2, $3);} |
| | cmd ANDAND cmd {$$=tree2(ANDAND, $1, $3);} |
| | cmd OROR cmd {$$=tree2(OROR, $1, $3);} |
| | cmd PIPE cmd {$$=mung2($2, $1, $3);} |
| | redir cmd %prec BANG {$$=mung2($1, $1->child[0], $2);} |
| | assign cmd %prec BANG {$$=mung3($1, $1->child[0], $1->child[1], $2);} |
| | BANG cmd {$$=mung1($1, $2);} |
| | SUBSHELL cmd {$$=mung1($1, $2);} |
| | FN words brace {$$=tree2(FN, $2, $3);} |
| | FN words {$$=tree1(FN, $2);} |
| simple: first |
| | simple word {$$=tree2(ARGLIST, $1, $2);} |
| | simple redir {$$=tree2(ARGLIST, $1, $2);} |
| first: comword |
| | first '^' word {$$=tree2('^', $1, $3);} |
| word: keyword {lastword=1; $1->type=WORD;} |
| | comword |
| | word '^' word {$$=tree2('^', $1, $3);} |
| comword: '$' word {$$=tree1('$', $2);} |
| | '$' word SUB words ')' {$$=tree2(SUB, $2, $4);} |
| | '"' word {$$=tree1('"', $2);} |
| | COUNT word {$$=tree1(COUNT, $2);} |
| | WORD |
| | '`' brace {$$=tree1('`', $2);} |
| | '(' words ')' {$$=tree1(PAREN, $2);} |
| | REDIR brace {$$=mung1($1, $2); $$->type=PIPEFD;} |
| keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN |
| words: {$$=(struct tree*)0;} |
| | words word {$$=tree2(WORDS, $1, $2);} |