antlr3 1.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/ANTLR-LICENSE.txt +26 -0
- data/History.txt +66 -0
- data/README.txt +139 -0
- data/bin/antlr4ruby +33 -0
- data/java/RubyTarget.java +524 -0
- data/java/antlr-full-3.2.1.jar +0 -0
- data/lib/antlr3.rb +176 -0
- data/lib/antlr3/constants.rb +88 -0
- data/lib/antlr3/debug.rb +701 -0
- data/lib/antlr3/debug/event-hub.rb +210 -0
- data/lib/antlr3/debug/record-event-listener.rb +25 -0
- data/lib/antlr3/debug/rule-tracer.rb +55 -0
- data/lib/antlr3/debug/socket.rb +360 -0
- data/lib/antlr3/debug/trace-event-listener.rb +92 -0
- data/lib/antlr3/dfa.rb +247 -0
- data/lib/antlr3/dot.rb +174 -0
- data/lib/antlr3/error.rb +657 -0
- data/lib/antlr3/main.rb +561 -0
- data/lib/antlr3/modes/ast-builder.rb +41 -0
- data/lib/antlr3/modes/filter.rb +56 -0
- data/lib/antlr3/profile.rb +322 -0
- data/lib/antlr3/recognizers.rb +1280 -0
- data/lib/antlr3/streams.rb +985 -0
- data/lib/antlr3/streams/interactive.rb +91 -0
- data/lib/antlr3/streams/rewrite.rb +412 -0
- data/lib/antlr3/test/call-stack.rb +57 -0
- data/lib/antlr3/test/config.rb +23 -0
- data/lib/antlr3/test/core-extensions.rb +269 -0
- data/lib/antlr3/test/diff.rb +165 -0
- data/lib/antlr3/test/functional.rb +207 -0
- data/lib/antlr3/test/grammar.rb +371 -0
- data/lib/antlr3/token.rb +592 -0
- data/lib/antlr3/tree.rb +1415 -0
- data/lib/antlr3/tree/debug.rb +163 -0
- data/lib/antlr3/tree/visitor.rb +84 -0
- data/lib/antlr3/tree/wizard.rb +481 -0
- data/lib/antlr3/util.rb +149 -0
- data/lib/antlr3/version.rb +27 -0
- data/samples/ANTLRv3Grammar.g +621 -0
- data/samples/Cpp.g +749 -0
- data/templates/AST.stg +335 -0
- data/templates/ASTDbg.stg +40 -0
- data/templates/ASTParser.stg +153 -0
- data/templates/ASTTreeParser.stg +272 -0
- data/templates/Dbg.stg +192 -0
- data/templates/Ruby.stg +1514 -0
- data/test/functional/ast-output/auto-ast.rb +797 -0
- data/test/functional/ast-output/construction.rb +555 -0
- data/test/functional/ast-output/hetero-nodes.rb +753 -0
- data/test/functional/ast-output/rewrites.rb +1327 -0
- data/test/functional/ast-output/tree-rewrite.rb +1662 -0
- data/test/functional/debugging/debug-mode.rb +689 -0
- data/test/functional/debugging/profile-mode.rb +165 -0
- data/test/functional/debugging/rule-tracing.rb +74 -0
- data/test/functional/delegation/import.rb +379 -0
- data/test/functional/lexer/basic.rb +559 -0
- data/test/functional/lexer/filter-mode.rb +245 -0
- data/test/functional/lexer/nuances.rb +47 -0
- data/test/functional/lexer/properties.rb +104 -0
- data/test/functional/lexer/syn-pred.rb +32 -0
- data/test/functional/lexer/xml.rb +206 -0
- data/test/functional/main/main-scripts.rb +245 -0
- data/test/functional/parser/actions.rb +224 -0
- data/test/functional/parser/backtracking.rb +244 -0
- data/test/functional/parser/basic.rb +282 -0
- data/test/functional/parser/calc.rb +98 -0
- data/test/functional/parser/ll-star.rb +143 -0
- data/test/functional/parser/nuances.rb +165 -0
- data/test/functional/parser/predicates.rb +103 -0
- data/test/functional/parser/properties.rb +242 -0
- data/test/functional/parser/rule-methods.rb +132 -0
- data/test/functional/parser/scopes.rb +274 -0
- data/test/functional/token-rewrite/basic.rb +318 -0
- data/test/functional/token-rewrite/via-parser.rb +100 -0
- data/test/functional/tree-parser/basic.rb +750 -0
- data/test/unit/sample-input/file-stream-1 +2 -0
- data/test/unit/sample-input/teststreams.input2 +2 -0
- data/test/unit/test-dfa.rb +52 -0
- data/test/unit/test-exceptions.rb +44 -0
- data/test/unit/test-recognizers.rb +55 -0
- data/test/unit/test-scheme.rb +62 -0
- data/test/unit/test-streams.rb +459 -0
- data/test/unit/test-tree-wizard.rb +535 -0
- data/test/unit/test-trees.rb +854 -0
- metadata +205 -0
data/lib/antlr3/util.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
module ANTLR3
|
5
|
+
module Util
|
6
|
+
|
7
|
+
module_function
|
8
|
+
|
9
|
+
def snake_case(str)
|
10
|
+
str = str.to_s.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
11
|
+
str.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
12
|
+
str.tr!("-", "_")
|
13
|
+
str.downcase!
|
14
|
+
str
|
15
|
+
end
|
16
|
+
|
17
|
+
def tidy(here_doc, flow = false)
|
18
|
+
here_doc.gsub!(/^ *\| ?/, '')
|
19
|
+
if flow
|
20
|
+
here_doc.strip!
|
21
|
+
here_doc.gsub!(/\s+/, ' ')
|
22
|
+
end
|
23
|
+
return here_doc
|
24
|
+
end
|
25
|
+
|
26
|
+
def silence_warnings
|
27
|
+
verbosity, $VERBOSE = $VERBOSE, nil
|
28
|
+
return yield
|
29
|
+
ensure
|
30
|
+
$VERBOSE = verbosity
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
module ClassMacros
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def shared_attribute( name, *additional_members )
|
40
|
+
attr_reader name
|
41
|
+
|
42
|
+
additional_writers = additional_members.inject('') do |src, attr|
|
43
|
+
src << "@#{attr} = value if @#{attr}\n"
|
44
|
+
end
|
45
|
+
|
46
|
+
file, line, = caller[1].split(':', 3)
|
47
|
+
class_eval(<<-END, file, line.to_i)
|
48
|
+
def #{name}= value
|
49
|
+
@#{name} = value
|
50
|
+
|
51
|
+
each_delegate do |del|
|
52
|
+
del.#{name} = value
|
53
|
+
end
|
54
|
+
|
55
|
+
#{additional_writers}
|
56
|
+
end
|
57
|
+
END
|
58
|
+
end
|
59
|
+
|
60
|
+
def abstract( name, message = nil )
|
61
|
+
message ||= "abstract method -- #{self.class}::#{name} has not been implemented"
|
62
|
+
file, line, = caller[1].split(':', 3)
|
63
|
+
class_eval(<<-END, file, line.to_i)
|
64
|
+
def #{name}( * )
|
65
|
+
raise TypeError, #{message.to_s.inspect}
|
66
|
+
end
|
67
|
+
END
|
68
|
+
end
|
69
|
+
|
70
|
+
def alias_accessor( alias_name, attr_name )
|
71
|
+
alias_method( alias_name, attr_name )
|
72
|
+
alias_method( :"#{alias_name}=", :"#{attr_name}=" )
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
class Integer
|
80
|
+
|
81
|
+
# Returns the lower of self or x.
|
82
|
+
#
|
83
|
+
# 4.at_least(5) #=> 5
|
84
|
+
# 6.at_least(5) #=> 6
|
85
|
+
#
|
86
|
+
# CREDIT Florian Gross
|
87
|
+
|
88
|
+
def at_least(x)
|
89
|
+
(self >= x) ? self : x
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns the greater of self or x.
|
93
|
+
#
|
94
|
+
# 4.at_most(5) #=> 4
|
95
|
+
# 6.at_most(5) #=> 5
|
96
|
+
#
|
97
|
+
# CREDIT Florian Gross
|
98
|
+
|
99
|
+
def at_most(x)
|
100
|
+
(self <= x) ? self : x
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns self if above the given lower bound, or
|
104
|
+
# within the given lower and upper bounds,
|
105
|
+
# otherwise returns the the bound of which the
|
106
|
+
# value falls outside.
|
107
|
+
#
|
108
|
+
# 4.bound(3) #=> 4
|
109
|
+
# 4.bound(5) #=> 5
|
110
|
+
# 4.bound(2,7) #=> 4
|
111
|
+
# 9.bound(2,7) #=> 7
|
112
|
+
# 1.bound(2,7) #=> 2
|
113
|
+
#
|
114
|
+
# CREDIT Trans
|
115
|
+
|
116
|
+
def bound(lower, upper=nil)
|
117
|
+
return lower if self < lower
|
118
|
+
return self unless upper
|
119
|
+
return upper if self > upper
|
120
|
+
return self
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
class Range
|
127
|
+
def covers?(range)
|
128
|
+
range.first >= first or return false
|
129
|
+
if exclude_end?
|
130
|
+
range.exclude_end? ? last >= range.last : last > range.last
|
131
|
+
else
|
132
|
+
range.exclude_end? ? last.succ >= range.last : last >= range.last
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def covered_by?(range)
|
137
|
+
range.covers?(self)
|
138
|
+
end
|
139
|
+
|
140
|
+
def overlaps?(range)
|
141
|
+
range.include?(first) or include?(range.first)
|
142
|
+
end
|
143
|
+
|
144
|
+
def disjoint?(range)
|
145
|
+
not overlaps?(range)
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
module ANTLR3
|
5
|
+
|
6
|
+
#
|
7
|
+
# The version of the ANTLR tool used while designing and
|
8
|
+
# testing the current version of this library
|
9
|
+
#
|
10
|
+
ANTLR_MAJOR_VERSION = 3
|
11
|
+
ANTLR_MINOR_VERSION = 2
|
12
|
+
ANTLR_PATCH_VERSION = 1
|
13
|
+
ANTLR_VERSION = [ANTLR_MAJOR_VERSION, ANTLR_MINOR_VERSION, ANTLR_PATCH_VERSION].freeze
|
14
|
+
ANTLR_VERSION_STRING = ANTLR_VERSION.join('.')
|
15
|
+
ANTLR_VERSION_STRING.chomp!( '.0' ) # versioning drops minor version at 0
|
16
|
+
ANTLR_VERSION_STRING.freeze
|
17
|
+
|
18
|
+
#
|
19
|
+
# The version data for the current state the library itself
|
20
|
+
#
|
21
|
+
MAJOR_VERSION = 1
|
22
|
+
MINOR_VERSION = 2
|
23
|
+
PATCH_VERSION = 3
|
24
|
+
VERSION = [MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION]
|
25
|
+
VERSION_STRING = VERSION.join('.').freeze
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,621 @@
|
|
1
|
+
/*
|
2
|
+
[The "BSD licence"]
|
3
|
+
Copyright (c) 2005-2007 Terence Parr
|
4
|
+
All rights reserved.
|
5
|
+
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
7
|
+
modification, are permitted provided that the following conditions
|
8
|
+
are met:
|
9
|
+
1. Redistributions of source code must retain the above copyright
|
10
|
+
notice, this list of conditions and the following disclaimer.
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright
|
12
|
+
notice, this list of conditions and the following disclaimer in the
|
13
|
+
documentation and/or other materials provided with the distribution.
|
14
|
+
3. The name of the author may not be used to endorse or promote products
|
15
|
+
derived from this software without specific prior written permission.
|
16
|
+
|
17
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
18
|
+
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
19
|
+
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
20
|
+
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
21
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
22
|
+
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
23
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
24
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
25
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
26
|
+
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
*/
|
28
|
+
|
29
|
+
/** ANTLR v3 grammar written in ANTLR v3 with AST construction */
|
30
|
+
grammar ANTLRv3Grammar;
|
31
|
+
|
32
|
+
options {
|
33
|
+
ASTLabelType = CommonTree;
|
34
|
+
language = Ruby;
|
35
|
+
output = AST;
|
36
|
+
}
|
37
|
+
|
38
|
+
tokens {
|
39
|
+
DOC_COMMENT;
|
40
|
+
PARSER;
|
41
|
+
LEXER;
|
42
|
+
RULE;
|
43
|
+
BLOCK;
|
44
|
+
OPTIONAL;
|
45
|
+
CLOSURE;
|
46
|
+
POSITIVE_CLOSURE;
|
47
|
+
SYNPRED;
|
48
|
+
RANGE;
|
49
|
+
CHAR_RANGE;
|
50
|
+
EPSILON;
|
51
|
+
ALT;
|
52
|
+
EOR;
|
53
|
+
EOB;
|
54
|
+
EOA; // end of alt
|
55
|
+
ID;
|
56
|
+
ARG;
|
57
|
+
ARGLIST;
|
58
|
+
RET='returns';
|
59
|
+
LEXER_GRAMMAR;
|
60
|
+
PARSER_GRAMMAR;
|
61
|
+
TREE_GRAMMAR;
|
62
|
+
COMBINED_GRAMMAR;
|
63
|
+
LABEL; // $x used in rewrite rules
|
64
|
+
TEMPLATE;
|
65
|
+
SCOPE='scope';
|
66
|
+
SEMPRED;
|
67
|
+
GATED_SEMPRED; // {p}? =>
|
68
|
+
SYN_SEMPRED; // (...) => it's a manually-specified synpred converted to sempred
|
69
|
+
BACKTRACK_SEMPRED; // auto backtracking mode syn pred converted to sempred
|
70
|
+
FRAGMENT='fragment';
|
71
|
+
TREE_BEGIN='^(';
|
72
|
+
ROOT='^';
|
73
|
+
BANG='!';
|
74
|
+
RANGE='..';
|
75
|
+
REWRITE='->';
|
76
|
+
AT='@';
|
77
|
+
LABEL_ASSIGN='=';
|
78
|
+
LIST_LABEL_ASSIGN='+=';
|
79
|
+
}
|
80
|
+
|
81
|
+
/* action -> @parser::header
|
82
|
+
{
|
83
|
+
package org.antlr.grammar.v3;
|
84
|
+
} */
|
85
|
+
/* action -> @lexer::header
|
86
|
+
{
|
87
|
+
package org.antlr.grammar.v3;
|
88
|
+
} */
|
89
|
+
|
90
|
+
@members {
|
91
|
+
attr_reader :grammar_type
|
92
|
+
}
|
93
|
+
|
94
|
+
grammar_def
|
95
|
+
: DOC_COMMENT?
|
96
|
+
( 'lexer' { @grammar_type = LEXER_GRAMMAR } // pure lexer
|
97
|
+
| 'parser' { @grammar_type = PARSER_GRAMMAR } // pure parser
|
98
|
+
| 'tree' { @grammar_type = TREE_GRAMMAR } // a tree parser
|
99
|
+
| { @grammar_type = COMBINED_GRAMMAR } // merged parser/lexer
|
100
|
+
)
|
101
|
+
g='grammar' id ';' options_spec? tokens_spec? attr_scope* action*
|
102
|
+
rule+
|
103
|
+
EOF
|
104
|
+
-> ^( {@adaptor.create!(@grammar_type, $g) }
|
105
|
+
id DOC_COMMENT? options_spec? tokens_spec? attr_scope* action* rule+
|
106
|
+
)
|
107
|
+
;
|
108
|
+
|
109
|
+
tokens_spec
|
110
|
+
: TOKENS token_spec+ '}' -> ^(TOKENS token_spec+)
|
111
|
+
;
|
112
|
+
|
113
|
+
token_spec
|
114
|
+
: TOKEN_REF
|
115
|
+
( '=' (lit=STRING_LITERAL|lit=CHAR_LITERAL) -> ^('=' TOKEN_REF $lit)
|
116
|
+
| -> TOKEN_REF
|
117
|
+
)
|
118
|
+
';'
|
119
|
+
;
|
120
|
+
|
121
|
+
attr_scope
|
122
|
+
: 'scope' id ACTION -> ^('scope' id ACTION)
|
123
|
+
;
|
124
|
+
|
125
|
+
/** Match stuff like @parser::members {int i;} */
|
126
|
+
action
|
127
|
+
: '@' (action_scope_name '::')? id ACTION -> ^('@' action_scope_name? id ACTION)
|
128
|
+
;
|
129
|
+
|
130
|
+
/** Sometimes the scope names will collide with keywords; allow them as
|
131
|
+
* ids for action scopes.
|
132
|
+
*/
|
133
|
+
action_scope_name
|
134
|
+
: id
|
135
|
+
| l='lexer' -> ID[$l]
|
136
|
+
| p='parser' -> ID[$p]
|
137
|
+
;
|
138
|
+
|
139
|
+
options_spec
|
140
|
+
: OPTIONS (option ';')+ '}' -> ^(OPTIONS option+)
|
141
|
+
;
|
142
|
+
|
143
|
+
option
|
144
|
+
: id '=' option_value -> ^('=' id option_value)
|
145
|
+
;
|
146
|
+
|
147
|
+
option_value
|
148
|
+
: qid
|
149
|
+
| STRING_LITERAL
|
150
|
+
| CHAR_LITERAL
|
151
|
+
| INT
|
152
|
+
| s='*' -> STRING_LITERAL[$s] // used for k=*
|
153
|
+
;
|
154
|
+
|
155
|
+
rule
|
156
|
+
scope {
|
157
|
+
name;
|
158
|
+
}
|
159
|
+
: DOC_COMMENT?
|
160
|
+
( modifier=('protected'|'public'|'private'|'fragment') )?
|
161
|
+
id { $rule::name = $id.text }
|
162
|
+
'!'?
|
163
|
+
( arg=ARG_ACTION )?
|
164
|
+
( 'returns' rt=ARG_ACTION )?
|
165
|
+
throws_spec? options_spec? rule_scope_spec? rule_action*
|
166
|
+
':' alt_list ';'
|
167
|
+
exception_group?
|
168
|
+
-> ^( RULE id {$modifier ? @adaptor.create!($modifier) : nil} ^(ARG[$arg] $arg)? ^('returns' $rt)?
|
169
|
+
throws_spec? options_spec? rule_scope_spec? rule_action*
|
170
|
+
alt_list
|
171
|
+
exception_group?
|
172
|
+
EOR["EOR"]
|
173
|
+
)
|
174
|
+
;
|
175
|
+
|
176
|
+
/** Match stuff like @init {int i;} */
|
177
|
+
rule_action
|
178
|
+
: '@' id ACTION -> ^('@' id ACTION)
|
179
|
+
;
|
180
|
+
|
181
|
+
throws_spec
|
182
|
+
: 'throws' id ( ',' id )* -> ^('throws' id+)
|
183
|
+
;
|
184
|
+
|
185
|
+
rule_scope_spec
|
186
|
+
: 'scope' ACTION -> ^('scope' ACTION)
|
187
|
+
| 'scope' id (',' id)* ';' -> ^('scope' id+)
|
188
|
+
| 'scope' ACTION
|
189
|
+
'scope' id (',' id)* ';'
|
190
|
+
-> ^('scope' ACTION id+ )
|
191
|
+
;
|
192
|
+
|
193
|
+
block
|
194
|
+
: lp='('
|
195
|
+
( (opts=options_spec)? ':' )?
|
196
|
+
altpair ( '|' altpair )*
|
197
|
+
rp=')'
|
198
|
+
-> ^( BLOCK[$lp,"BLOCK"] options_spec? altpair+ EOB[$rp,"EOB"] )
|
199
|
+
;
|
200
|
+
|
201
|
+
altpair : alternative rewrite ;
|
202
|
+
|
203
|
+
alt_list
|
204
|
+
@init {
|
205
|
+
block_root = @adaptor.create!(BLOCK, @input.look(-1), "BLOCK");
|
206
|
+
}
|
207
|
+
: altpair ( '|' altpair )* -> ^( {block_root} altpair+ EOB["eob"] )
|
208
|
+
;
|
209
|
+
|
210
|
+
alternative
|
211
|
+
@init {
|
212
|
+
first_token = @input.look(1)
|
213
|
+
prev_token = @input.look(-1)
|
214
|
+
}
|
215
|
+
: element+ -> ^(ALT[first_token,"ALT"] element+ EOA["EOA"])
|
216
|
+
| -> ^(ALT[prev_token,"ALT"] EPSILON[prev_token,"EPSILON"] EOA["EOA"])
|
217
|
+
;
|
218
|
+
|
219
|
+
exception_group
|
220
|
+
: ( exception_handler )+ ( finally_clause )?
|
221
|
+
| finally_clause
|
222
|
+
;
|
223
|
+
|
224
|
+
exception_handler
|
225
|
+
: 'catch' ARG_ACTION ACTION -> ^('catch' ARG_ACTION ACTION)
|
226
|
+
;
|
227
|
+
|
228
|
+
finally_clause
|
229
|
+
: 'finally' ACTION -> ^('finally' ACTION)
|
230
|
+
;
|
231
|
+
|
232
|
+
element
|
233
|
+
: id (labelOp='='|labelOp='+=') atom
|
234
|
+
( ebnf_suffix -> ^( ebnf_suffix ^(BLOCK["BLOCK"] ^(ALT["ALT"] ^($labelOp id atom) EOA["EOA"]) EOB["EOB"]))
|
235
|
+
| -> ^($labelOp id atom)
|
236
|
+
)
|
237
|
+
| id (labelOp='='|labelOp='+=') block
|
238
|
+
( ebnf_suffix -> ^( ebnf_suffix ^(BLOCK["BLOCK"] ^(ALT["ALT"] ^($labelOp id block) EOA["EOA"]) EOB["EOB"]))
|
239
|
+
| -> ^($labelOp id block)
|
240
|
+
)
|
241
|
+
| atom
|
242
|
+
( ebnf_suffix -> ^( ebnf_suffix ^(BLOCK["BLOCK"] ^(ALT["ALT"] atom EOA["EOA"]) EOB["EOB"]) )
|
243
|
+
| -> atom
|
244
|
+
)
|
245
|
+
| ebnf
|
246
|
+
| ACTION
|
247
|
+
| SEMPRED ( g='=>' -> GATED_SEMPRED[$g] | -> SEMPRED )
|
248
|
+
| tree_spec
|
249
|
+
( ebnf_suffix -> ^( ebnf_suffix ^(BLOCK["BLOCK"] ^(ALT["ALT"] tree_spec EOA["EOA"]) EOB["EOB"]) )
|
250
|
+
| -> tree_spec
|
251
|
+
)
|
252
|
+
;
|
253
|
+
|
254
|
+
atom: terminal
|
255
|
+
| range
|
256
|
+
( (op='^'|op='!') -> ^($op range)
|
257
|
+
| -> range
|
258
|
+
)
|
259
|
+
| not_set
|
260
|
+
( (op='^'|op='!') -> ^($op not_set)
|
261
|
+
| -> not_set
|
262
|
+
)
|
263
|
+
| RULE_REF ARG_ACTION?
|
264
|
+
( (op='^'|op='!') -> ^($op RULE_REF ARG_ACTION?)
|
265
|
+
| -> ^(RULE_REF ARG_ACTION?)
|
266
|
+
)
|
267
|
+
;
|
268
|
+
|
269
|
+
not_set
|
270
|
+
: '~'
|
271
|
+
( not_terminal element_options? -> ^('~' not_terminal element_options?)
|
272
|
+
| block element_options? -> ^('~' block element_options?)
|
273
|
+
)
|
274
|
+
;
|
275
|
+
|
276
|
+
not_terminal
|
277
|
+
: CHAR_LITERAL
|
278
|
+
| TOKEN_REF
|
279
|
+
| STRING_LITERAL
|
280
|
+
;
|
281
|
+
|
282
|
+
element_options
|
283
|
+
: '<' qid '>' -> ^(OPTIONS qid)
|
284
|
+
| '<' option (';' option)* '>' -> ^(OPTIONS option+)
|
285
|
+
;
|
286
|
+
|
287
|
+
element_option
|
288
|
+
: id '=' option_value -> ^('=' id option_value)
|
289
|
+
;
|
290
|
+
|
291
|
+
tree_spec
|
292
|
+
: '^(' element ( element )+ ')' -> ^(TREE_BEGIN element+)
|
293
|
+
;
|
294
|
+
|
295
|
+
range!
|
296
|
+
: c1=CHAR_LITERAL RANGE c2=CHAR_LITERAL element_options?
|
297
|
+
-> ^(CHAR_RANGE[$c1,".."] $c1 $c2 element_options?)
|
298
|
+
;
|
299
|
+
|
300
|
+
terminal
|
301
|
+
: ( CHAR_LITERAL element_options? -> ^(CHAR_LITERAL element_options?)
|
302
|
+
// Args are only valid for lexer rules
|
303
|
+
| TOKEN_REF ARG_ACTION? element_options? -> ^(TOKEN_REF ARG_ACTION? element_options?)
|
304
|
+
| STRING_LITERAL element_options? -> ^(STRING_LITERAL element_options?)
|
305
|
+
| '.' element_options? -> ^('.' element_options?)
|
306
|
+
)
|
307
|
+
( '^' -> ^('^' $terminal)
|
308
|
+
| '!' -> ^('!' $terminal)
|
309
|
+
)?
|
310
|
+
;
|
311
|
+
|
312
|
+
/** Matches ENBF blocks (and token sets via block rule) */
|
313
|
+
ebnf
|
314
|
+
@init { first_token = @input.look(1) }
|
315
|
+
@after {
|
316
|
+
$ebnf.tree.token.line = first_token.line
|
317
|
+
$ebnf.tree.token.column = first_token.column
|
318
|
+
}
|
319
|
+
: block
|
320
|
+
( op='?' -> ^(OPTIONAL[$op] block)
|
321
|
+
| op='*' -> ^(CLOSURE[$op] block)
|
322
|
+
| op='+' -> ^(POSITIVE_CLOSURE[$op] block)
|
323
|
+
| '=>' // syntactic predicate
|
324
|
+
-> {
|
325
|
+
@grammar_type == COMBINED_GRAMMAR && $rule::name[0].between?(?A, ?Z)
|
326
|
+
}?
|
327
|
+
// if lexer rule in combined, leave as pred for lexer
|
328
|
+
^(SYNPRED["=>"] block)
|
329
|
+
// in real antlr tool, text for SYN_SEMPRED is predname
|
330
|
+
-> SYN_SEMPRED
|
331
|
+
| -> block
|
332
|
+
)
|
333
|
+
;
|
334
|
+
|
335
|
+
ebnf_suffix
|
336
|
+
@init {
|
337
|
+
op = @input.look(1)
|
338
|
+
}
|
339
|
+
: '?' -> OPTIONAL[op]
|
340
|
+
| '*' -> CLOSURE[op]
|
341
|
+
| '+' -> POSITIVE_CLOSURE[op]
|
342
|
+
;
|
343
|
+
|
344
|
+
|
345
|
+
|
346
|
+
// R E W R I T E S Y N T A X
|
347
|
+
|
348
|
+
rewrite
|
349
|
+
@init {
|
350
|
+
first_token = @input.look(1)
|
351
|
+
}
|
352
|
+
: (rew+='->' preds+=SEMPRED predicated+=rewrite_alternative)*
|
353
|
+
rew2='->' last=rewrite_alternative
|
354
|
+
-> ^($rew $preds $predicated)* ^($rew2 $last)
|
355
|
+
|
|
356
|
+
;
|
357
|
+
|
358
|
+
rewrite_alternative
|
359
|
+
options {backtrack=true;}
|
360
|
+
: rewrite_template
|
361
|
+
| rewrite_tree_alternative
|
362
|
+
| /* empty rewrite */ -> ^(ALT["ALT"] EPSILON["EPSILON"] EOA["EOA"])
|
363
|
+
;
|
364
|
+
|
365
|
+
rewrite_tree_block
|
366
|
+
: lp='(' rewrite_tree_alternative ')'
|
367
|
+
-> ^(BLOCK[$lp,"BLOCK"] rewrite_tree_alternative EOB[$lp,"EOB"])
|
368
|
+
;
|
369
|
+
|
370
|
+
rewrite_tree_alternative
|
371
|
+
: rewrite_tree_element+ -> ^(ALT["ALT"] rewrite_tree_element+ EOA["EOA"])
|
372
|
+
;
|
373
|
+
|
374
|
+
rewrite_tree_element
|
375
|
+
: rewrite_tree_atom
|
376
|
+
| rewrite_tree_atom ebnf_suffix
|
377
|
+
-> ^( ebnf_suffix ^(BLOCK["BLOCK"] ^(ALT["ALT"] rewrite_tree_atom EOA["EOA"]) EOB["EOB"]))
|
378
|
+
| rewrite_tree
|
379
|
+
( ebnf_suffix
|
380
|
+
-> ^(ebnf_suffix ^(BLOCK["BLOCK"] ^(ALT["ALT"] rewrite_tree EOA["EOA"]) EOB["EOB"]))
|
381
|
+
| -> rewrite_tree
|
382
|
+
)
|
383
|
+
| rewrite_tree_ebnf
|
384
|
+
;
|
385
|
+
|
386
|
+
rewrite_tree_atom
|
387
|
+
: CHAR_LITERAL
|
388
|
+
| TOKEN_REF ARG_ACTION? -> ^(TOKEN_REF ARG_ACTION?) // for imaginary nodes
|
389
|
+
| RULE_REF
|
390
|
+
| STRING_LITERAL
|
391
|
+
| d='$' id -> LABEL[$d,$id.text] // reference to a label in a rewrite rule
|
392
|
+
| ACTION
|
393
|
+
;
|
394
|
+
|
395
|
+
rewrite_tree_ebnf
|
396
|
+
@init {
|
397
|
+
first_token = @input.look(1)
|
398
|
+
}
|
399
|
+
@after {
|
400
|
+
$rewrite_tree_ebnf.tree.token.line = first_token.line
|
401
|
+
$rewrite_tree_ebnf.tree.token.column = first_token.column
|
402
|
+
}
|
403
|
+
: rewrite_tree_block ebnf_suffix -> ^(ebnf_suffix rewrite_tree_block)
|
404
|
+
;
|
405
|
+
|
406
|
+
rewrite_tree
|
407
|
+
: '^(' rewrite_tree_atom rewrite_tree_element* ')'
|
408
|
+
-> ^(TREE_BEGIN rewrite_tree_atom rewrite_tree_element* )
|
409
|
+
;
|
410
|
+
|
411
|
+
/** Build a tree for a template rewrite:
|
412
|
+
^(TEMPLATE (ID|ACTION) ^(ARGLIST ^(ARG ID ACTION) ...) )
|
413
|
+
where ARGLIST is always there even if no args exist.
|
414
|
+
ID can be "template" keyword. If first child is ACTION then it's
|
415
|
+
an indirect template ref
|
416
|
+
|
417
|
+
-> foo(a={...}, b={...})
|
418
|
+
-> ({string-e})(a={...}, b={...}) // e evaluates to template name
|
419
|
+
-> {%{$ID.text}} // create literal template from string (done in ActionTranslator)
|
420
|
+
-> {st-expr} // st-expr evaluates to ST
|
421
|
+
*/
|
422
|
+
rewrite_template
|
423
|
+
: // -> template(a={...},...) "..." inline template
|
424
|
+
id lp='(' rewrite_template_args ')'
|
425
|
+
( str=DOUBLE_QUOTE_STRING_LITERAL | str=DOUBLE_ANGLE_STRING_LITERAL )
|
426
|
+
-> ^(TEMPLATE[$lp,"TEMPLATE"] id rewrite_template_args $str)
|
427
|
+
|
428
|
+
| // -> foo(a={...}, ...)
|
429
|
+
rewrite_template_ref
|
430
|
+
|
431
|
+
| // -> ({expr})(a={...}, ...)
|
432
|
+
rewrite_indirect_template_head
|
433
|
+
|
434
|
+
| // -> {...}
|
435
|
+
ACTION
|
436
|
+
;
|
437
|
+
|
438
|
+
/** -> foo(a={...}, ...) */
|
439
|
+
rewrite_template_ref
|
440
|
+
: id lp='(' rewrite_template_args ')'
|
441
|
+
-> ^(TEMPLATE[$lp,"TEMPLATE"] id rewrite_template_args)
|
442
|
+
;
|
443
|
+
|
444
|
+
/** -> ({expr})(a={...}, ...) */
|
445
|
+
rewrite_indirect_template_head
|
446
|
+
: lp='(' ACTION ')' '(' rewrite_template_args ')'
|
447
|
+
-> ^(TEMPLATE[$lp,"TEMPLATE"] ACTION rewrite_template_args)
|
448
|
+
;
|
449
|
+
|
450
|
+
rewrite_template_args
|
451
|
+
: rewrite_template_arg (',' rewrite_template_arg)*
|
452
|
+
-> ^(ARGLIST rewrite_template_arg+)
|
453
|
+
| -> ARGLIST
|
454
|
+
;
|
455
|
+
|
456
|
+
rewrite_template_arg
|
457
|
+
: id '=' ACTION -> ^(ARG[$id.start] id ACTION)
|
458
|
+
;
|
459
|
+
|
460
|
+
qid : id ('.' id)* ;
|
461
|
+
|
462
|
+
id :
|
463
|
+
TOKEN_REF -> ID[$TOKEN_REF]
|
464
|
+
| RULE_REF -> ID[$RULE_REF]
|
465
|
+
;
|
466
|
+
|
467
|
+
// L E X I C A L R U L E S
|
468
|
+
|
469
|
+
SL_COMMENT
|
470
|
+
: '//'
|
471
|
+
( ' $ANTLR ' SRC // src directive
|
472
|
+
| ~('\r'|'\n')*
|
473
|
+
)
|
474
|
+
'\r'? '\n' {$channel=HIDDEN;}
|
475
|
+
;
|
476
|
+
|
477
|
+
ML_COMMENT
|
478
|
+
: '/*' {if @input.peek(1) == ?* then $type = DOC_COMMENT else $channel = HIDDEN end } .* '*/'
|
479
|
+
;
|
480
|
+
|
481
|
+
CHAR_LITERAL
|
482
|
+
: '\'' LITERAL_CHAR '\''
|
483
|
+
;
|
484
|
+
|
485
|
+
STRING_LITERAL
|
486
|
+
: '\'' LITERAL_CHAR LITERAL_CHAR* '\''
|
487
|
+
;
|
488
|
+
|
489
|
+
fragment
|
490
|
+
LITERAL_CHAR
|
491
|
+
: ESC
|
492
|
+
| ~('\''|'\\')
|
493
|
+
;
|
494
|
+
|
495
|
+
DOUBLE_QUOTE_STRING_LITERAL
|
496
|
+
: '"' (ESC | ~('\\'|'"'))* '"'
|
497
|
+
;
|
498
|
+
|
499
|
+
DOUBLE_ANGLE_STRING_LITERAL
|
500
|
+
: '<<' .* '>>'
|
501
|
+
;
|
502
|
+
|
503
|
+
fragment
|
504
|
+
ESC : '\\'
|
505
|
+
( 'n'
|
506
|
+
| 'r'
|
507
|
+
| 't'
|
508
|
+
| 'b'
|
509
|
+
| 'f'
|
510
|
+
| '"'
|
511
|
+
| '\''
|
512
|
+
| '\\'
|
513
|
+
| '>'
|
514
|
+
| 'u' XDIGIT XDIGIT XDIGIT XDIGIT
|
515
|
+
| . // unknown, leave as it is
|
516
|
+
)
|
517
|
+
;
|
518
|
+
|
519
|
+
fragment
|
520
|
+
XDIGIT :
|
521
|
+
'0' .. '9'
|
522
|
+
| 'a' .. 'f'
|
523
|
+
| 'A' .. 'F'
|
524
|
+
;
|
525
|
+
|
526
|
+
INT : '0'..'9'+
|
527
|
+
;
|
528
|
+
|
529
|
+
ARG_ACTION
|
530
|
+
: NESTED_ARG_ACTION
|
531
|
+
;
|
532
|
+
|
533
|
+
fragment
|
534
|
+
NESTED_ARG_ACTION :
|
535
|
+
'['
|
536
|
+
( options {greedy=false; k=1;}
|
537
|
+
: NESTED_ARG_ACTION
|
538
|
+
| ACTION_STRING_LITERAL
|
539
|
+
| ACTION_CHAR_LITERAL
|
540
|
+
| .
|
541
|
+
)*
|
542
|
+
']'
|
543
|
+
//{setText(getText().substring(1, getText().length()-1));}
|
544
|
+
;
|
545
|
+
|
546
|
+
ACTION
|
547
|
+
: NESTED_ACTION ( '?' { $type = SEMPRED } )?
|
548
|
+
;
|
549
|
+
|
550
|
+
fragment
|
551
|
+
NESTED_ACTION :
|
552
|
+
'{'
|
553
|
+
( options {greedy=false; k=2;}
|
554
|
+
: NESTED_ACTION
|
555
|
+
| SL_COMMENT
|
556
|
+
| ML_COMMENT
|
557
|
+
| ACTION_STRING_LITERAL
|
558
|
+
| ACTION_CHAR_LITERAL
|
559
|
+
| ~ '\\'
|
560
|
+
| '\\' .
|
561
|
+
)*
|
562
|
+
'}'
|
563
|
+
;
|
564
|
+
|
565
|
+
fragment
|
566
|
+
ACTION_CHAR_LITERAL
|
567
|
+
: '\'' ( ~('\\'|'\'') | '\\' . )* '\''
|
568
|
+
;
|
569
|
+
|
570
|
+
fragment
|
571
|
+
ACTION_STRING_LITERAL
|
572
|
+
: '"' ( ~('\\'|'"') | '\\' . )* '"'
|
573
|
+
;
|
574
|
+
|
575
|
+
fragment
|
576
|
+
ACTION_ESC
|
577
|
+
: '\\' .
|
578
|
+
;
|
579
|
+
|
580
|
+
TOKEN_REF
|
581
|
+
: 'A'..'Z' ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
|
582
|
+
;
|
583
|
+
|
584
|
+
RULE_REF
|
585
|
+
: 'a'..'z' ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
|
586
|
+
;
|
587
|
+
|
588
|
+
/** Match the start of an options section. Don't allow normal
|
589
|
+
* action processing on the {...} as it's not a action.
|
590
|
+
*/
|
591
|
+
OPTIONS
|
592
|
+
: 'options' WS_LOOP '{'
|
593
|
+
;
|
594
|
+
|
595
|
+
TOKENS
|
596
|
+
: 'tokens' WS_LOOP '{'
|
597
|
+
;
|
598
|
+
|
599
|
+
/** Reset the file and line information; useful when the grammar
|
600
|
+
* has been generated so that errors are shown relative to the
|
601
|
+
* original file like the old C preprocessor used to do.
|
602
|
+
*/
|
603
|
+
fragment
|
604
|
+
SRC : 'src' ' ' file=ACTION_STRING_LITERAL ' ' line=INT
|
605
|
+
;
|
606
|
+
|
607
|
+
WS : ( ' '
|
608
|
+
| '\t'
|
609
|
+
| '\r'? '\n'
|
610
|
+
)+
|
611
|
+
{$channel=HIDDEN}
|
612
|
+
;
|
613
|
+
|
614
|
+
fragment
|
615
|
+
WS_LOOP
|
616
|
+
: ( WS
|
617
|
+
| SL_COMMENT
|
618
|
+
| ML_COMMENT
|
619
|
+
)*
|
620
|
+
;
|
621
|
+
|