📄 parse.y
字号:
/* 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. */#endifstatic 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -