1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
/* parse.y -- grammar for es ($Revision: 1.2 $) */
%{
/* Some yaccs insist on including stdlib.h */
#define _STDLIB_H
#include "es.h"
#include "input.h"
#include "syntax.h"
%}
%token WORD QWORD
%token LOCAL LET FOR CLOSURE FN
%token ANDAND BACKBACK EXTRACT CALL COUNT DUP FLAT OROR PRIM REDIR SUB
%token NL ENDFILE ERROR
%left LOCAL LET FOR CLOSURE ')'
%left ANDAND OROR NL
%left '!'
%left PIPE
%right '$'
%left SUB
%union {
Tree *tree;
char *str;
NodeKind kind;
}
%type <str> WORD QWORD keyword
%type <tree> REDIR PIPE DUP
body cmd cmdsa cmdsan comword first fn line word param assign
binding bindings params nlwords words simple redir sword
%type <kind> binder
%start es
%%
es : line end { parsetree = $1; YYACCEPT; }
| error end { yyerrok; parsetree = NULL; YYABORT; }
end : NL { if (!readheredocs(FALSE)) YYABORT; }
| ENDFILE { if (!readheredocs(TRUE)) YYABORT; }
line : cmd { $$ = $1; }
| cmdsa line { $$ = mkseq("%seq", $1, $2); }
body : cmd { $$ = $1; }
| cmdsan body { $$ = mkseq("%seq", $1, $2); }
cmdsa : cmd ';' { $$ = $1; }
| cmd '&' { $$ = prefix("%background", mk(nList, thunkify($1), NULL)); }
cmdsan : cmdsa { $$ = $1; }
| cmd NL { $$ = $1; if (!readheredocs(FALSE)) YYABORT; }
cmd : %prec LET { $$ = NULL; }
| simple { $$ = redirect($1); if ($$ == &errornode) YYABORT; }
| redir cmd %prec '!' { $$ = redirect(mk(nRedir, $1, $2)); if ($$ == &errornode) YYABORT; }
| first assign { $$ = mk(nAssign, $1, $2); }
| fn { $$ = $1; }
| binder nl '(' bindings ')' nl cmd { $$ = mk($1, $4, $7); }
| cmd ANDAND nl cmd { $$ = mkseq("%and", $1, $4); }
| cmd OROR nl cmd { $$ = mkseq("%or", $1, $4); }
| cmd PIPE nl cmd { $$ = mkpipe($1, $2->u[0].i, $2->u[1].i, $4); }
| '!' caret cmd { $$ = prefix("%not", mk(nList, thunkify($3), NULL)); }
| '~' word words { $$ = mk(nMatch, $2, $3); }
| EXTRACT word words { $$ = mk(nExtract, $2, $3); }
simple : first { $$ = treecons2($1, NULL); }
| simple word { $$ = treeconsend2($1, $2); }
| simple redir { $$ = redirappend($1, $2); }
redir : DUP { $$ = $1; }
| REDIR word { $$ = mkredir($1, $2); }
bindings: binding { $$ = treecons2($1, NULL); }
| bindings ';' binding { $$ = treeconsend2($1, $3); }
| bindings NL binding { $$ = treeconsend2($1, $3); }
binding : { $$ = NULL; }
| fn { $$ = $1; }
| word assign { $$ = mk(nAssign, $1, $2); }
assign : caret '=' caret words { $$ = $4; }
fn : FN word params '{' body '}' { $$ = fnassign($2, mklambda($3, $5)); }
| FN word { $$ = fnassign($2, NULL); }
first : comword { $$ = $1; }
| first '^' sword { $$ = mk(nConcat, $1, $3); }
sword : comword { $$ = $1; }
| keyword { $$ = mk(nWord, $1); }
word : sword { $$ = $1; }
| word '^' sword { $$ = mk(nConcat, $1, $3); }
comword : param { $$ = $1; }
| '(' nlwords ')' { $$ = $2; }
| '{' body '}' { $$ = thunkify($2); }
| '@' params '{' body '}' { $$ = mklambda($2, $4); }
| '$' sword { $$ = mk(nVar, $2); }
| '$' sword SUB words ')' { $$ = mk(nVarsub, $2, $4); }
| CALL sword { $$ = mk(nCall, $2); }
| COUNT sword { $$ = mk(nCall, prefix("%count", treecons(mk(nVar, $2), NULL))); }
| FLAT sword { $$ = flatten(mk(nVar, $2), " "); }
| PRIM WORD { $$ = mk(nPrim, $2); }
| '`' sword { $$ = backquote(mk(nVar, mk(nWord, "ifs")), $2); }
| BACKBACK word sword { $$ = backquote($2, $3); }
param : WORD { $$ = mk(nWord, $1); }
| QWORD { $$ = mk(nQword, $1); }
params : { $$ = NULL; }
| params param { $$ = treeconsend($1, $2); }
words : { $$ = NULL; }
| words word { $$ = treeconsend($1, $2); }
nlwords : { $$ = NULL; }
| nlwords word { $$ = treeconsend($1, $2); }
| nlwords NL { $$ = $1; }
nl :
| nl NL
caret :
| '^'
binder : LOCAL { $$ = nLocal; }
| LET { $$ = nLet; }
| FOR { $$ = nFor; }
| CLOSURE { $$ = nClosure; }
keyword : '!' { $$ = "!"; }
| '~' { $$ = "~"; }
| EXTRACT { $$ = "~~"; }
| LOCAL { $$ = "local"; }
| LET { $$ = "let"; }
| FOR { $$ = "for"; }
| FN { $$ = "fn"; }
| CLOSURE { $$ = "%closure"; }
|