home *** CD-ROM | disk | FTP | other *** search
- /* parse.y */
-
- /*
- * Adapted from rc grammar, v10 manuals, volume 2.
- */
-
- %{
- #include "rc.h"
- #ifndef lint
- #define lint /* hush up gcc -Wall, leave out the dumb sccsid's. */
- #endif
- static Node *star, *nolist;
- Node *parsetree; /* not using yylval because bison declares it as an auto */
- %}
-
- %token ANDAND BACKBACK BANG CASE COUNT DUP ELSE END FLAT FN FOR IF IN
- %token OROR PIPE REDIR SREDIR SUB SUBSHELL SWITCH TWIDDLE WHILE WORD HUH
-
- %left WHILE ')' ELSE
- %left ANDAND OROR '\n'
- %left BANG SUBSHELL
- %left PIPE
- %right '$'
- %left SUB
- /*
- */
-
- %union {
- struct Node *node;
- struct Redir redir;
- struct Pipe pipe;
- struct Dup dup;
- struct Word word;
- char *keyword;
- }
-
- %type <redir> REDIR SREDIR
- %type <pipe> PIPE
- %type <dup> DUP
- %type <word> WORD
- %type <keyword> keyword
- %type <node> assign body brace case cbody cmd cmdsa cmdsan comword epilog
- first line nlwords paren redir sword simple iftail word words
-
- %start rc
-
- %%
-
- rc : line end { parsetree = $1; YYACCEPT; }
- | error end { yyerrok; parsetree = NULL; YYABORT; }
-
- /* an rc line may end in end-of-file as well as newline, e.g., rc -c 'ls' */
- end : END /* EOF */ { if (!heredoc(1)) YYABORT; } /* flag error if there is a heredoc in the queue */
- | '\n' { if (!heredoc(0)) YYABORT; } /* get heredoc on \n */
-
- /* a cmdsa is a command followed by ampersand or newline (used in "line" and "body") */
- cmdsa : cmd ';'
- | cmd '&' { $$ = ($1 != NULL ? mk(nNowait,$1) : $1); }
-
- /* a line is a single command, or a command terminated by ; or & followed by a line (recursive) */
- line : cmd
- | cmdsa line { $$ = ($1 != NULL ? mk(nBody,$1,$2) : $2); }
-
- /* a body is like a line, only commands may also be terminated by newline */
- body : cmd
- | cmdsan body { $$ = ($1 == NULL ? $2 : $2 == NULL ? $1 : mk(nBody,$1,$2)); }
-
- cmdsan : cmdsa
- | cmd '\n' { $$ = $1; if (!heredoc(0)) YYABORT; } /* get h.d. on \n */
-
- brace : '{' body '}' { $$ = $2; }
-
- paren : '(' body ')' { $$ = $2; }
-
- assign : first '=' word { $$ = mk(nAssign,$1,$3); }
-
- epilog : { $$ = NULL; }
- | redir epilog { $$ = mk(nEpilog,$1,$2); }
-
- /* a redirection is a dup (e.g., >[1=2]) or a file redirection. (e.g., > /dev/null) */
- redir : DUP { $$ = mk(nDup,$1.type,$1.left,$1.right); }
- | REDIR word { $$ = mk(nRedir,$1.type,$1.fd,$2);
- if ($1.type == rHeredoc && !qdoc($2, $$)) YYABORT; /* queue heredocs up */
- }
- | SREDIR word { $$ = mk(nRedir,$1.type,$1.fd,$2);
- if ($1.type == rHeredoc && !qdoc($2, $$)) YYABORT; /* queue heredocs up */
- }
-
- case : CASE words ';' { $$ = mk(nCase, $2); }
- | CASE words '\n' { $$ = mk(nCase, $2); }
-
- cbody : cmd { $$ = mk(nCbody, $1, NULL); }
- | case cbody { $$ = mk(nCbody, $1, $2); }
- | cmdsan cbody { $$ = mk(nCbody, $1, $2); }
-
- iftail : cmd %prec ELSE
- | brace ELSE optnl cmd { $$ = mk(nElse,$1,$4); }
-
- cmd : /* empty */ %prec WHILE { $$ = NULL; }
- | simple
- | brace epilog { $$ = mk(nBrace,$1,$2); }
- | IF paren optnl iftail { $$ = mk(nIf,$2,$4); }
- | FOR '(' word IN words ')' optnl cmd { $$ = mk(nForin,$3,$5,$8); }
- | FOR '(' word ')' optnl cmd { $$ = mk(nForin,$3,star,$6); }
- | WHILE paren optnl cmd { $$ = mk(nWhile,$2,$4); }
- | SWITCH '(' word ')' optnl '{' cbody '}' { $$ = mk(nSwitch,$3,$7); }
- | TWIDDLE optcaret word words { $$ = mk(nMatch,$3,$4); }
- | cmd ANDAND optnl cmd { $$ = mk(nAndalso,$1,$4); }
- | cmd OROR optnl cmd { $$ = mk(nOrelse,$1,$4); }
- | cmd PIPE optnl cmd { $$ = mk(nPipe,$2.left,$2.right,$1,$4); }
- | redir cmd %prec BANG { $$ = ($2 != NULL ? mk(nPre,$1,$2) : $1); }
- | assign cmd %prec BANG { $$ = ($2 != NULL ? mk(nPre,$1,$2) : $1); }
- | BANG optcaret cmd { $$ = mk(nBang,$3); }
- | SUBSHELL optcaret cmd { $$ = mk(nSubshell,$3); }
- | FN words brace { $$ = mk(nNewfn,$2,$3); }
- | FN words { $$ = mk(nRmfn,$2); }
-
- optcaret : /* empty */
- | '^'
-
- simple : first
- | simple word { $$ = ($2 != NULL ? mk(nArgs,$1,$2) : $1); }
- | simple redir { $$ = mk(nArgs,$1,$2); }
-
- first : comword
- | first '^' sword { $$ = mk(nConcat,$1,$3); }
-
- sword : comword
- | keyword { $$ = mk(nWord,$1, NULL); }
-
- word : sword
- | word '^' sword { $$ = mk(nConcat,$1,$3); }
-
- comword : '$' sword { $$ = mk(nVar,$2); }
- | '$' sword SUB words ')' { $$ = mk(nVarsub,$2,$4); }
- | COUNT sword { $$ = mk(nCount,$2); }
- | FLAT sword { $$ = mk(nFlat, $2); }
- | '`' sword { $$ = mk(nBackq,nolist,$2); }
- | '`' brace { $$ = mk(nBackq,nolist,$2); }
- | BACKBACK word brace { $$ = mk(nBackq,$2,$3); }
- | BACKBACK word sword { $$ = mk(nBackq,$2,$3); }
- | '(' nlwords ')' { $$ = $2; }
- | REDIR brace { $$ = mk(nNmpipe,$1.type,$1.fd,$2); }
- | WORD { $$ = ($1.w[0] == '\'') ? mk(nQword, $1.w+1, NULL) : mk(nWord,$1.w, $1.m); }
-
- keyword : FOR { $$ = "for"; }
- | IN { $$ = "in"; }
- | WHILE { $$ = "while"; }
- | IF { $$ = "if"; }
- | SWITCH { $$ = "switch"; }
- | FN { $$ = "fn"; }
- | ELSE { $$ = "else"; }
- | CASE { $$ = "case"; }
- | TWIDDLE { $$ = "~"; }
- | BANG { $$ = "!"; }
- | SUBSHELL { $$ = "@"; }
-
- words : { $$ = NULL; }
- | words word { $$ = ($1 != NULL ? ($2 != NULL ? mk(nLappend,$1,$2) : $1) : $2); }
-
- nlwords : { $$ = NULL; }
- | nlwords '\n'
- | nlwords word { $$ = ($1 != NULL ? ($2 != NULL ? mk(nLappend,$1,$2) : $1) : $2); }
-
- optnl : /* empty */
- | optnl '\n'
-
- %%
-
- void initparse() {
- star = treecpy(mk(nVar,mk(nWord,"*",NULL)), ealloc);
- nolist = treecpy(mk(nVar,mk(nWord,"ifs",NULL)), ealloc);
- }
-
-