rc

[fork] interactive rc shell
Log | Files | Refs | README | LICENSE

commit cf69a6080c9194f1d928b8372c2aa8f6f80a233d
parent 444505dafacdf3a69bf5237a684bbed0e603b7f9
Author: tgoodwin <tgoodwin>
Date:   Fri, 10 Jul 1998 13:36:49 +0000

Initial revision

Diffstat:
Aparse.y | 174+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 174 insertions(+), 0 deletions(-)

diff --git a/parse.y b/parse.y @@ -0,0 +1,174 @@ +/* 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); +} +