forked from pmichaud/pmtcl
/
Grammar.pm
179 lines (138 loc) · 5.69 KB
/
Grammar.pm
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
grammar Partcl::Grammar is HLL::Grammar;
token TOP { <TOP_eval> }
## TOP_eval evaluates a script in the current lexical context
## TOP_proc evaluates a script in a new lexical context
## TOP_expr evaluates an expression in the current lexical context
## See the corresponding methods in Actions.pm for lexical context handling
token TOP_eval { <body> }
token TOP_proc { <body> }
token TOP_expr { \h* <EXPR> }
token body { <script> [ $ || <.panic: 'Confused' > ] }
token script {
[ \h* [ <.comment> | <command> | <?> ] \h* ] ** <.command_sep>
\s*
}
token comment { '#' [ \\ \n \h* | \N ]* }
token command { <word> ** [[\h+ || \\ \x0a]+] }
token command_sep { ';' | \n }
proto token word { <...> }
token word:sym<{*}> { '{*}' <word> }
token word:sym<{ }> { <braced_word> }
token word:sym<" "> { <quoted_word> }
token word:sym<bare> { <bare_atom>+ }
token braced_word { '{' <braced_atom>* '}' }
proto token braced_atom { <...> }
token braced_atom:sym<{ }> { <braced_word> }
token braced_atom:sym<backnl> { \\ \x0a \h* }
token braced_atom:sym<back{> { \\ \{ }
token braced_atom:sym<back}> { \\ \} }
token braced_atom:sym<backd> { \\ \\}
token braced_atom:sym<back> { \\ }
token braced_atom:sym<chr> { <-[ \\ { } ]>+ }
token quoted_word { '"' <quoted_atom>* '"'}
proto token quoted_atom { <...> }
token quoted_atom:sym<[ ]> { '[' ~ ']' <script> }
token quoted_atom:sym<var> { <variable> }
token quoted_atom:sym<$> { '$' }
token quoted_atom:sym<\\> { <backslash> }
token quoted_atom:sym<chr> { <-[ \[ " \\ $]>+ }
proto token bare_atom { <...> }
token bare_atom:sym<[ ]> { '[' ~ ']' <script> }
token bare_atom:sym<var> { <variable> }
token bare_atom:sym<$> { '$' }
token bare_atom:sym<\\> { <backslash> }
token bare_atom:sym<chr> { <-[ \[ \\ $ \] ; ]-space>+ }
proto token backslash { <...> }
token backslash:sym<bel> { '\a' }
token backslash:sym<bs> { '\b' }
token backslash:sym<ff> { '\f' }
token backslash:sym<lf> { '\n' }
token backslash:sym<cr> { '\r' }
token backslash:sym<ht> { '\t' }
token backslash:sym<vt> { '\v' }
token backslash:sym<chr> { \\ $<chr>=[\N] }
token backslash:sym<backnl> { \\ \x0a \h* }
token backslash:sym<backx> { \\ x $<x>=[<.xdigit>+] }
token backslash:sym<backo> { \\ $<o>=[<[0..7]> ** 1..3] }
token backslash:sym<backu> { \\ u $<u>=[<.xdigit> ** 1..4] }
token list {
\s*
[
| <EXPR=.quoted_word>
[ $<extra>=(\S+) { $/.CURSOR.badList('quotes', $<extra><sym>); }]?
| <EXPR=.braced_word>
[ $<extra>=(\S+) { $/.CURSOR.badList('braces', $<extra><sym>); }]?
| <EXPR=.list_word>
] ** [\s+]
}
method badList($types, $extra) {
pir::die('list element in ' ~ $types ~ ' followed by "' ~ $extra ~ '" instead of space');
}
token list_word { <list_atom>+ }
proto token list_atom { <...> }
token list_atom:sym<\\> { <backslash> }
token list_atom:sym<chr> { <-[ \\ ]-space>+ }
token colons { ':' ':'+ }
token identifier { <ident> ** <.colons> }
proto token variable { <...> }
# XXX The key here is wrong. It needs to do variable interpolation, and more.
token variable:sym<normal> { '$' $<global>=<.colons>? <identifier> [ '(' $<key>=(<-[)]>+) ')' ]? }
token variable:sym<escaped> { '$' '{' $<identifier>=(<-[ } ]>*) '}' }
rule integer { $<sign>=(<[+\-]>?)<int> }
proto token int { <...> }
token int:sym<dec> { $<digits>=[<[1..9]><[0..9]>* | 0] }
token int:sym<hex> { 0<[Xx]> $<digits>=(<[0..9A..Fa..f]>+) }
token int:sym<oct> { 0<[Oo]>? $<digits>=(<[0..7]>+) }
proto token index { <...> }
token index:sym<int> { <a=.integer> [ $<op>=[<[+\-]>] <b=.integer> ]? }
token index:sym<end> { 'end' }
token index:sym<end+> { 'end+' <a=.integer>}
token index:sym<end-> { 'end-' <a=.integer>}
# expression parsing
INIT {
Partcl::Grammar.O(':prec<15>, :assoc<unary>', '%unary');
Partcl::Grammar.O(':prec<14>', '%exponentiation');
Partcl::Grammar.O(':prec<13>', '%multiplicative');
Partcl::Grammar.O(':prec<12>', '%additive');
Partcl::Grammar.O(':prec<11>', '%shift');
Partcl::Grammar.O(':prec<10>', '%compare_numeric');
Partcl::Grammar.O(':prec<09>', '%equality_numeric');
Partcl::Grammar.O(':prec<08>', '%equality_string');
}
# The <.ws> rule only gets used in expressions.
token ws { \h* }
token term:sym<integer> { <integer> }
token term:sym<variable> { <variable> }
token term:sym<true> {
(:i true | tru | tr | t
| yes | ye | y
| on
)
}
token term:sym<false> {
(:i false | fals | fal | fa | f
| no | n
| off | of
)
}
token term:sym<( )> { '(' <EXPR> ')' }
token term:sym<[ ]> { '[' ~ ']' <script> }
token term:sym<" "> { '"' <quoted_atom>* '"' }
token prefix:sym<!> { <sym> <O('%unary, :pirop<not>')> }
token prefix:sym<~> { <sym> <O('%unary, :pirop<bnot>')> }
token infix:sym<**> { <sym> <O('%exponentiation, :pirop<pow>')> }
token infix:sym<*> { <sym> <O('%multiplicative, :pirop<mul>')> }
token infix:sym</> { <sym> <O('%multiplicative, :pirop<div>')> }
token infix:sym<+> { <sym> <O('%additive, :pirop<add Nnn>')> }
token infix:sym<-> { <sym> <O('%additive, :pirop<sub Nnn>')> }
token infix:sym«<<» { <sym> <O('%shift, :pirop<shl Iii>')> }
token infix:sym«>>» { <sym> <O('%shift, :pirop<shr Iii>')> }
token infix:sym«<» { <sym> <O('%compare_numeric, :pirop<islt Inn>')> }
token infix:sym«<=» { <sym> <O('%compare_numeric, :pirop<isle Inn>')> }
token infix:sym«>» { <sym> <O('%compare_numeric, :pirop<isgt Inn>')> }
token infix:sym«>=» { <sym> <O('%compare_numeric, :pirop<isge Inn>')> }
token infix:sym<==> { <sym> <O('%equality_numeric')> }
token infix:sym<!=> { <sym> <O('%equality_numeric, :pirop<isne Inn>')> }
token infix:sym<eq> { <sym> <O('%equality_string, :pirop<iseq Iss>')> }
token infix:sym<ne> { <sym> <O('%equality_string, :pirop<isne Iss>')> }
# vim: expandtab shiftwidth=4 ft=perl6: