aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/rc/syntax.y
blob: 0bdc77681f0f366cc738b247646f0edc9d7ddaf2 (plain)
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
145
146
147
%token Tfor Tin Twhile Tif Telse Tswitch Tcase Tcasebody Ttwiddle Tbang Tsubshell Tfunc
%token Tredir Tdup Tpipe Tindex
%token Tbasic Targs Tword Twords Tparen Tblock

%define parse.error verbose

%{
    #include "rc.h"

    int  yylex(void);
    void yyerror(const char *);
%}

/* operator precendence: lowest first */
%left Tif Tfor Tswitch Tcase ')' Twhile Telse
%left Tandand Toror '\n'
%left Tbang Tsubshell
%left Tpipe;
%left '^';
%right '$' Tcount Tjoin
%left Tindex

/* semantic types */
%union{
    struct Tree *tree;
}
%type<tree> line cmds cmdsln body paren block ifbody casebody case assign epilog redir;
%type<tree> cmd basic executable nonkeyword keyword word words wordsnl atom;
%type<tree> Tfor Tin Twhile Tif Telse Tswitch Tcase Ttwiddle Tbang Tsubshell Tfunc;
%type<tree> Tword Tredir Tpipe Tdup;

/* grammar */

%start rc

%%
rc:
/*empty*/   { return 0; }
| line '\n' { return compile($1); }

line:
  cmd
| cmds line { $$ = maketree2(';', $1, $2); }

body:
  cmd
| cmdsln body { $$ = maketree2(';', $1, $2); }

paren:
  '(' body ')' { $$ = maketree1(Tparen, $2); }

block:
  '{' body '}' { $$ = maketree1(Tblock, $2); }

cmds:
  cmd ';'
| cmd '&' { $$ = maketree1('&', $1); }

cmdsln:
  cmds
| cmd '\n'

ifbody:
  cmd   %prec Telse  { $$ = maketree2(Tif, nil, $1); }
| block Telse nl cmd { $$ = maketree3(Tif, nil, $1, $2); }

case:
  Tcase words ';'    { $$ = hangchild1($1, $2, 0); }
| Tcase words '\n'   { $$ = hangchild1($1, $2, 0); }

casebody:
  cmd                { $$ = maketree2(Tcasebody, $1, nil); }
| case casebody      { $$ = maketree2(Tcasebody, $1, $2); }
| cmdsln casebody    { $$ = maketree2(Tcasebody, $1, $2); }

assign:
    executable '=' word { $$ = maketree2('=', $1, $3); }

redir:
  Tdup
| Tredir word              { $$ = hangchild1($1, $2, 0); }

epilog:
/* empty */     { $$ = nil; }
| redir epilog  { $$ = hangchild1($1, $2, 1); }

cmd:
/* empty */  %prec Twhile                  { $$ = nil; }
| basic                                    { $$ = maketree1(Tbasic, $1); }
| block epilog                             { $$ = hangepilog($1, $2); }
| cmd Tpipe nl cmd                         { $$ = hangchild2($2, $1, 0, $4, 1); }
| cmd Tandand nl cmd                       { $$ = maketree2(Tandand, $1, $4); }
| cmd Toror nl cmd                         { $$ = maketree2(Toror, $1, $4); }
| redir  cmd %prec Tbang                   { $$ = hangchild1($1, $2, 1); }
| assign cmd %prec Tbang                   { $$ = hangchild1($1, $2, 2); }
| Tbang cmd                                { $$ = maketree1(Tbang, $2); }
| Tsubshell cmd                            { $$ = maketree1(Tsubshell, $2); }
| Tfor '(' word ')' nl cmd                 { $$ = hangchild3($1, $3, nil, $6); }
| Tfor '(' word Tin words ')' nl cmd       { $$ = hangchild3($1, $3, $5, $8); }
| Twhile paren nl cmd                      { $$ = hangchild2($1, $2, 0, $4, 1); }
| Tif paren nl ifbody                      { $$ = hangchild1($2, $1, 0); }
| Tswitch '(' word ')' nl '{' casebody '}' { $$ = hangchild2($1, $3, 0, $7, 1); }

basic:
  executable
| basic word    { $$ = maketree2(Targs, $1, $2); }
| basic redir   { $$ = maketree2(Targs, $1, $2); }

atom:
  nonkeyword
| keyword             { $$ = maketree1(Tword, $1); }

word:
  atom
| word '^' atom       { $$ = maketree2('^', $1, $3); }

executable:
  nonkeyword
| executable '^' atom { $$ = maketree2('^', $1, $3); }

nonkeyword:
  Tword
| '$' atom                  { $$ = maketree1('$', $2); }
| '$' atom Tindex words ')' { $$ = maketree2(Tindex, $2, $4); }
| '(' wordsnl ')'           { $$ = $2; }
| Tcount atom               { $$ = maketree1(Tcount, $2); }
| Tjoin atom                { $$ = maketree1(Tjoin, $2); }
| '`'  block                { $$ = maketree1('`', $2); }
//| Tredir block    { $$ = hangchild1($1, $2, 0); $$->type = Tpipefd; }

keyword:
    Tfor|Tin|Twhile|Tif|Telse|Tswitch|Tcase|Tbang|Tsubshell|Tfunc

words:
/* empty */  { $$ = nil; }
| words word { $$ = maketree2(Twords, $1, $2); }

wordsnl:
/* empty */    { $$ = nil; }
| wordsnl '\n' /* empty */
| wordsnl word {$$ = (!$1) ? ((!$2) ? nil : $2) : ((!$2) ? $1 : maketree2(Twords, $1, $2)); }

nl:
/*empty*/
| nl '\n'

%%