13e12c5d1SDavid du Colombier %term FOR IN WHILE IF NOT TWIDDLE BANG SUBSHELL SWITCH FN 23e12c5d1SDavid du Colombier %term WORD REDIR DUP PIPE SUB 33e12c5d1SDavid du Colombier %term SIMPLE ARGLIST WORDS BRACE PAREN PCMD PIPEFD /* not used in syntax */ 43e12c5d1SDavid du Colombier /* operator priorities -- lowest first */ 53e12c5d1SDavid du Colombier %left IF WHILE FOR SWITCH ')' NOT 63e12c5d1SDavid du Colombier %left ANDAND OROR 73e12c5d1SDavid du Colombier %left BANG SUBSHELL 83e12c5d1SDavid du Colombier %left PIPE 93e12c5d1SDavid du Colombier %left '^' 103e12c5d1SDavid du Colombier %right '$' COUNT '"' 113e12c5d1SDavid du Colombier %left SUB 123e12c5d1SDavid du Colombier %{ 133e12c5d1SDavid du Colombier #include "rc.h" 143e12c5d1SDavid du Colombier #include "fns.h" 153e12c5d1SDavid du Colombier %} 163e12c5d1SDavid du Colombier %union{ 173e12c5d1SDavid du Colombier struct tree *tree; 183e12c5d1SDavid du Colombier }; 193e12c5d1SDavid du Colombier %type<tree> line paren brace body cmdsa cmdsan assign epilog redir 203e12c5d1SDavid du Colombier %type<tree> cmd simple first word comword keyword words 213e12c5d1SDavid du Colombier %type<tree> NOT FOR IN WHILE IF TWIDDLE BANG SUBSHELL SWITCH FN 223e12c5d1SDavid du Colombier %type<tree> WORD REDIR DUP PIPE 233e12c5d1SDavid du Colombier %% 243e12c5d1SDavid du Colombier rc: { return 1;} 253e12c5d1SDavid du Colombier | line '\n' {return !compile($1);} 263e12c5d1SDavid du Colombier line: cmd 273e12c5d1SDavid du Colombier | cmdsa line {$$=tree2(';', $1, $2);} 283e12c5d1SDavid du Colombier body: cmd 293e12c5d1SDavid du Colombier | cmdsan body {$$=tree2(';', $1, $2);} 303e12c5d1SDavid du Colombier cmdsa: cmd ';' 313e12c5d1SDavid du Colombier | cmd '&' {$$=tree1('&', $1);} 323e12c5d1SDavid du Colombier cmdsan: cmdsa 333e12c5d1SDavid du Colombier | cmd '\n' 343e12c5d1SDavid du Colombier brace: '{' body '}' {$$=tree1(BRACE, $2);} 353e12c5d1SDavid du Colombier paren: '(' body ')' {$$=tree1(PCMD, $2);} 363e12c5d1SDavid du Colombier assign: first '=' word {$$=tree2('=', $1, $3);} 373e12c5d1SDavid du Colombier epilog: {$$=0;} 383e12c5d1SDavid du Colombier | redir epilog {$$=mung2($1, $1->child[0], $2);} 393e12c5d1SDavid du Colombier redir: REDIR word {$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);} 403e12c5d1SDavid du Colombier | DUP 413e12c5d1SDavid du Colombier cmd: {$$=0;} 423e12c5d1SDavid du Colombier | brace epilog {$$=epimung($1, $2);} 433e12c5d1SDavid du Colombier | IF paren {skipnl();} cmd 443e12c5d1SDavid du Colombier {$$=mung2($1, $2, $4);} 453e12c5d1SDavid du Colombier | IF NOT {skipnl();} cmd {$$=mung1($2, $4);} 463e12c5d1SDavid du Colombier | FOR '(' word IN words ')' {skipnl();} cmd 477dd7cddfSDavid du Colombier /* 487dd7cddfSDavid du Colombier * if ``words'' is nil, we need a tree element to distinguish between 497dd7cddfSDavid du Colombier * for(i in ) and for(i), the former being a loop over the empty set 507dd7cddfSDavid du Colombier * and the latter being the implicit argument loop. so if $5 is nil 517dd7cddfSDavid du Colombier * (the empty set), we represent it as "()". don't parenthesize non-nil 527dd7cddfSDavid du Colombier * functions, to avoid growing parentheses every time we reread the 537dd7cddfSDavid du Colombier * definition. 547dd7cddfSDavid du Colombier */ 557dd7cddfSDavid du Colombier {$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);} 563e12c5d1SDavid du Colombier | FOR '(' word ')' {skipnl();} cmd 573e12c5d1SDavid du Colombier {$$=mung3($1, $3, (struct tree *)0, $6);} 583e12c5d1SDavid du Colombier | WHILE paren {skipnl();} cmd 593e12c5d1SDavid du Colombier {$$=mung2($1, $2, $4);} 603e12c5d1SDavid du Colombier | SWITCH word {skipnl();} brace 613e12c5d1SDavid du Colombier {$$=tree2(SWITCH, $2, $4);} 623e12c5d1SDavid du Colombier | simple {$$=simplemung($1);} 633e12c5d1SDavid du Colombier | TWIDDLE word words {$$=mung2($1, $2, $3);} 643e12c5d1SDavid du Colombier | cmd ANDAND cmd {$$=tree2(ANDAND, $1, $3);} 653e12c5d1SDavid du Colombier | cmd OROR cmd {$$=tree2(OROR, $1, $3);} 663e12c5d1SDavid du Colombier | cmd PIPE cmd {$$=mung2($2, $1, $3);} 673e12c5d1SDavid du Colombier | redir cmd %prec BANG {$$=mung2($1, $1->child[0], $2);} 683e12c5d1SDavid du Colombier | assign cmd %prec BANG {$$=mung3($1, $1->child[0], $1->child[1], $2);} 693e12c5d1SDavid du Colombier | BANG cmd {$$=mung1($1, $2);} 703e12c5d1SDavid du Colombier | SUBSHELL cmd {$$=mung1($1, $2);} 713e12c5d1SDavid du Colombier | FN words brace {$$=tree2(FN, $2, $3);} 723e12c5d1SDavid du Colombier | FN words {$$=tree1(FN, $2);} 733e12c5d1SDavid du Colombier simple: first 743e12c5d1SDavid du Colombier | simple word {$$=tree2(ARGLIST, $1, $2);} 753e12c5d1SDavid du Colombier | simple redir {$$=tree2(ARGLIST, $1, $2);} 763e12c5d1SDavid du Colombier first: comword 773e12c5d1SDavid du Colombier | first '^' word {$$=tree2('^', $1, $3);} 787dd7cddfSDavid du Colombier word: keyword {lastword=1; $1->type=WORD;} 793e12c5d1SDavid du Colombier | comword 803e12c5d1SDavid du Colombier | word '^' word {$$=tree2('^', $1, $3);} 813e12c5d1SDavid du Colombier comword: '$' word {$$=tree1('$', $2);} 823e12c5d1SDavid du Colombier | '$' word SUB words ')' {$$=tree2(SUB, $2, $4);} 833e12c5d1SDavid du Colombier | '"' word {$$=tree1('"', $2);} 843e12c5d1SDavid du Colombier | COUNT word {$$=tree1(COUNT, $2);} 853e12c5d1SDavid du Colombier | WORD 86*dbee7877SDavid du Colombier | '`' brace {$$=tree2('`', (struct tree*)0, $2);} 87*dbee7877SDavid du Colombier | '`' word brace {$$=tree2('`', $2, $3);} 883e12c5d1SDavid du Colombier | '(' words ')' {$$=tree1(PAREN, $2);} 893e12c5d1SDavid du Colombier | REDIR brace {$$=mung1($1, $2); $$->type=PIPEFD;} 903e12c5d1SDavid du Colombier keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN 917dd7cddfSDavid du Colombier words: {$$=(struct tree*)0;} 923e12c5d1SDavid du Colombier | words word {$$=tree2(WORDS, $1, $2);} 93