aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd/rc/syntax.y
blob: 2e7e1dae7b0e7afd7dc4257d53b6d95108bfb934 (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
%token Tfor Tin Twhile Tif Telse Tswitch 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 ')' 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 assign epilog redir;
%type<tree> cmd basic executable nonkeyword keyword word words wordsnl atom;
%type<tree> Tfor Tin Twhile Tif Telse Tswitch Ttwiddle Tbang Tsubshell Tfunc;
%type<tree> Tword Tredir Tpipe;

/* 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); }

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); }
| Tif paren nl ifbody     { $$ = hangchild1($2, $1, 0); }

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); }
| '(' wordsnl ')' { $$ = $2; }
| Tcount atom     { $$ = maketree1(Tcount, $2); }
| Tjoin atom      { $$ = maketree1(Tjoin, $2); }
//| '`'  block      { $$ = maketree1('`', $2); }

keyword:
    Tin|Tfor|Twhile|Tif|Telse|Tswitch|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'
%%