%token Tword Tif Telse Tbang %token Targs %token Tbasic Tparen Tblock %define parse.error verbose %{ #include "rc.h" int yylex(void); void yyerror(const char *); %} /* operator precendence: lowest first */ %right Telse %left Twhile %left '\n' %left Tbang %right '$' /* semantic types */ %union{ struct Tree *tree; } %type line cmds cmdsln body paren block ifbody assign; %type cmd basic executable nonkeyword keyword word atom arg args; %type Tbang; %type Tword Tif Telse; /* grammar */ %start rc %% rc: /*empty*/ { return 0; } | line '\n' { return compile($1); } line: cmd | cmds line { $$ = maketree2(';', $1, $2); } body: cmd | cmdsln body { $$ = maketree2(';', $1, $2); } paren: '(' body ')' { $$ = maketree1(Tparen, $2); } block: '{' body '}' { $$ = maketree1(Tblock, $2); } cmds: cmd ';' | cmd '&' { $$ = maketree1('&', $1); } cmdsln: cmds | cmd '\n' ifbody: cmd %prec Telse { $$ = maketree2(Tif, nil, $1); } | block Telse nl cmd { $$ = maketree3(Tif, nil, $1, $2); } assign: executable '=' word { $$ = maketree2('=', $1, $3); } cmd: /* empty */ %prec Twhile { $$ = nil; } | basic { $$ = maketree1(Tbasic, $1); } | block | assign cmd %prec Tbang { $$ = hangchild1($1, $2, 2); } | Tif paren nl ifbody { $$ = hangchild1($2, $1, 0); } basic: executable | basic word { $$ = maketree2(Targs, $1, $2); } arg: word args: arg | args arg { $$ = maketree2(Targs, $1, $2); } atom: nonkeyword | keyword { $$ = maketree1(Tword, $1); } word: atom | word '^' atom { $$ = maketree2('^', $1, $3); } executable: nonkeyword | executable '^' atom { $$ = maketree2('^', $1, $3); } nonkeyword: Tword | '$' atom { $$ = maketree1('$', $2); } keyword: Tif|Telse nl: /*empty*/ | nl '\n' %%