From 2ade60747db41771498ab2b85ce6e3c3389f2c26 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Wed, 13 Oct 2021 09:08:59 -0700 Subject: feat(rc): added unix port of rc with linenoise --- sys/cmd/rc/syn.y | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 sys/cmd/rc/syn.y (limited to 'sys/cmd/rc/syn.y') diff --git a/sys/cmd/rc/syn.y b/sys/cmd/rc/syn.y new file mode 100644 index 0000000..c7de353 --- /dev/null +++ b/sys/cmd/rc/syn.y @@ -0,0 +1,91 @@ +%term FOR IN WHILE IF NOT TWIDDLE BANG SUBSHELL SWITCH FN +%term WORD REDIR DUP PIPE SUB +%term SIMPLE ARGLIST WORDS BRACE PAREN PCMD PIPEFD /* not used in syntax */ +/* operator priorities -- lowest first */ +%left IF WHILE FOR SWITCH ')' NOT +%left ANDAND OROR +%left BANG SUBSHELL +%left PIPE +%left '^' +%right '$' COUNT '"' +%left SUB +%{ +#include "rc.h" +#include "fns.h" +%} +%union{ + struct tree *tree; +}; +%type line paren brace body cmdsa cmdsan assign epilog redir +%type cmd simple first word comword keyword words +%type NOT FOR IN WHILE IF TWIDDLE BANG SUBSHELL SWITCH FN +%type WORD REDIR DUP PIPE +%% +rc: { return 1;} +| line '\n' {return !compile($1);} +line: cmd +| cmdsa line {$$=tree2(';', $1, $2);} +body: cmd +| cmdsan body {$$=tree2(';', $1, $2);} +cmdsa: cmd ';' +| cmd '&' {$$=tree1('&', $1);} +cmdsan: cmdsa +| cmd '\n' +brace: '{' body '}' {$$=tree1(BRACE, $2);} +paren: '(' body ')' {$$=tree1(PCMD, $2);} +assign: first '=' word {$$=tree2('=', $1, $3);} +epilog: {$$=0;} +| redir epilog {$$=mung2($1, $1->child[0], $2);} +redir: REDIR word {$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);} +| DUP +cmd: {$$=0;} +| brace epilog {$$=epimung($1, $2);} +| IF paren {skipnl();} cmd + {$$=mung2($1, $2, $4);} +| IF NOT {skipnl();} cmd {$$=mung1($2, $4);} +| FOR '(' word IN words ')' {skipnl();} cmd + /* + * if ``words'' is nil, we need a tree element to distinguish between + * for(i in ) and for(i), the former being a loop over the empty set + * and the latter being the implicit argument loop. so if $5 is nil + * (the empty set), we represent it as "()". don't parenthesize non-nil + * functions, to avoid growing parentheses every time we reread the + * definition. + */ + {$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);} +| FOR '(' word ')' {skipnl();} cmd + {$$=mung3($1, $3, (struct tree *)0, $6);} +| WHILE paren {skipnl();} cmd + {$$=mung2($1, $2, $4);} +| SWITCH word {skipnl();} brace + {$$=tree2(SWITCH, $2, $4);} +| simple {$$=simplemung($1);} +| TWIDDLE word words {$$=mung2($1, $2, $3);} +| cmd ANDAND cmd {$$=tree2(ANDAND, $1, $3);} +| cmd OROR cmd {$$=tree2(OROR, $1, $3);} +| cmd PIPE cmd {$$=mung2($2, $1, $3);} +| redir cmd %prec BANG {$$=mung2($1, $1->child[0], $2);} +| assign cmd %prec BANG {$$=mung3($1, $1->child[0], $1->child[1], $2);} +| BANG cmd {$$=mung1($1, $2);} +| SUBSHELL cmd {$$=mung1($1, $2);} +| FN words brace {$$=tree2(FN, $2, $3);} +| FN words {$$=tree1(FN, $2);} +simple: first +| simple word {$$=tree2(ARGLIST, $1, $2);} +| simple redir {$$=tree2(ARGLIST, $1, $2);} +first: comword +| first '^' word {$$=tree2('^', $1, $3);} +word: keyword {lastword=1; $1->type=WORD;} +| comword +| word '^' word {$$=tree2('^', $1, $3);} +comword: '$' word {$$=tree1('$', $2);} +| '$' word SUB words ')' {$$=tree2(SUB, $2, $4);} +| '"' word {$$=tree1('"', $2);} +| COUNT word {$$=tree1(COUNT, $2);} +| WORD +| '`' brace {$$=tree1('`', $2);} +| '(' words ')' {$$=tree1(PAREN, $2);} +| REDIR brace {$$=mung1($1, $2); $$->type=PIPEFD;} +keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN +words: {$$=(struct tree*)0;} +| words word {$$=tree2(WORDS, $1, $2);} -- cgit v1.2.1