antlr3 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/main.rb
ADDED
@@ -0,0 +1,561 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
=begin LICENSE
|
5
|
+
|
6
|
+
[The "BSD licence"]
|
7
|
+
Copyright (c) 2009 Kyle Yetter
|
8
|
+
All rights reserved.
|
9
|
+
|
10
|
+
Redistribution and use in source and binary forms, with or without
|
11
|
+
modification, are permitted provided that the following conditions
|
12
|
+
are met:
|
13
|
+
|
14
|
+
1. Redistributions of source code must retain the above copyright
|
15
|
+
notice, this list of conditions and the following disclaimer.
|
16
|
+
2. Redistributions in binary form must reproduce the above copyright
|
17
|
+
notice, this list of conditions and the following disclaimer in the
|
18
|
+
documentation and/or other materials provided with the distribution.
|
19
|
+
3. The name of the author may not be used to endorse or promote products
|
20
|
+
derived from this software without specific prior written permission.
|
21
|
+
|
22
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
23
|
+
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
24
|
+
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
25
|
+
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
26
|
+
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
27
|
+
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
28
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
29
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
30
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
31
|
+
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
32
|
+
|
33
|
+
=end
|
34
|
+
|
35
|
+
require 'optparse'
|
36
|
+
require 'antlr3'
|
37
|
+
|
38
|
+
module ANTLR3
|
39
|
+
|
40
|
+
=begin rdoc ANTLR3::Main
|
41
|
+
|
42
|
+
Namespace module for the quick script Main classes.
|
43
|
+
|
44
|
+
=end
|
45
|
+
|
46
|
+
module Main
|
47
|
+
|
48
|
+
|
49
|
+
=begin rdoc ANTLR3::Main::Options
|
50
|
+
|
51
|
+
Defines command-line options and attribute mappings shared by all types of
|
52
|
+
Main classes.
|
53
|
+
|
54
|
+
=end
|
55
|
+
|
56
|
+
module Options
|
57
|
+
# the input encoding type; defaults to +nil+ (currently, not used)
|
58
|
+
attr_accessor :encoding
|
59
|
+
# the input stream used by the Main script; defaults to <tt>$stdin</tt>
|
60
|
+
attr_accessor :input
|
61
|
+
# a boolean flag indicating whether or not to run the Main
|
62
|
+
# script in interactive mode; defaults to +false+
|
63
|
+
attr_accessor :interactive
|
64
|
+
attr_accessor :no_output
|
65
|
+
attr_accessor :profile
|
66
|
+
attr_accessor :debug_socket
|
67
|
+
attr_accessor :ruby_prof
|
68
|
+
|
69
|
+
def initialize(options = {})
|
70
|
+
@no_output = options.fetch(:no_output, false)
|
71
|
+
@profile = options.fetch(:profile, false)
|
72
|
+
@debug_socket = options.fetch(:debug_socket, false)
|
73
|
+
@ruby_prof = options.fetch(:ruby_prof, false)
|
74
|
+
@encoding = options.fetch(:encoding, nil)
|
75
|
+
@interactive = options.fetch(:interactive, false)
|
76
|
+
@input = options.fetch(:input, $stdin)
|
77
|
+
end
|
78
|
+
|
79
|
+
# constructs an OptionParser and parses the argument list provided by +argv+
|
80
|
+
def parse_options(argv = ARGV)
|
81
|
+
oparser = OptionParser.new do |o|
|
82
|
+
o.on('-i', '--input "text to process"', doc(<<-END)) { |val| @input = val }
|
83
|
+
| a string to use as direct input to the recognizer
|
84
|
+
END
|
85
|
+
|
86
|
+
o.on( '-I', '--interactive', doc( <<-END ) ) { @interactive = true }
|
87
|
+
| run an interactive session with the recognizer
|
88
|
+
END
|
89
|
+
|
90
|
+
o.on( '--profile', doc( <<-END.chomp! ) ) { @profile = true }
|
91
|
+
| profile code execution using the standard profiler library
|
92
|
+
END
|
93
|
+
|
94
|
+
#o.on('--ruby-prof', doc(<<-END1), doc(<<-END2)) { @ruby_prof = true }
|
95
|
+
#| profile code execution using the faster ruby-prof
|
96
|
+
#END1
|
97
|
+
#| (requires rubygems with the ruby-prof gem)
|
98
|
+
#END2
|
99
|
+
end
|
100
|
+
|
101
|
+
setup_options( oparser )
|
102
|
+
return oparser.parse(argv)
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
def setup_options(oparser)
|
107
|
+
# overridable hook to modify / append options
|
108
|
+
end
|
109
|
+
|
110
|
+
def doc( description_string )
|
111
|
+
description_string.chomp!
|
112
|
+
description_string.gsub!(/^ *\| ?/,'')
|
113
|
+
description_string.gsub!(/\s+/,' ')
|
114
|
+
return description_string
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
|
121
|
+
=begin rdoc ANTLR3::Main::Main
|
122
|
+
|
123
|
+
The base-class for the three primary Main script-runner classes.
|
124
|
+
It defines the skeletal structure shared by all main
|
125
|
+
scripts, but isn't particularly useful on its own.
|
126
|
+
|
127
|
+
=end
|
128
|
+
|
129
|
+
class Main
|
130
|
+
include Options
|
131
|
+
attr_accessor :output, :error
|
132
|
+
|
133
|
+
def initialize(options = {})
|
134
|
+
@input = options.fetch( :input, $stdin )
|
135
|
+
@output = options.fetch( :output, $stdout )
|
136
|
+
@error = options.fetch( :error, $stderr )
|
137
|
+
@name = options.fetch( :name, File.basename($0, '.rb') )
|
138
|
+
super
|
139
|
+
block_given? and yield(self)
|
140
|
+
end
|
141
|
+
|
142
|
+
# runs the script
|
143
|
+
def execute(argv = ARGV)
|
144
|
+
args = parse_options(argv)
|
145
|
+
setup
|
146
|
+
|
147
|
+
@interactive and return execute_interactive
|
148
|
+
|
149
|
+
in_stream =
|
150
|
+
case
|
151
|
+
when @input.is_a?(::String) then StringStream.new(@input)
|
152
|
+
when args.length == 1 && args.first != '-'
|
153
|
+
ANTLR3::FileStream.new(args[0])
|
154
|
+
else ANTLR3::FileStream.new(@input)
|
155
|
+
end
|
156
|
+
case
|
157
|
+
when @ruby_prof
|
158
|
+
load_ruby_prof
|
159
|
+
profile = RubyProf.profile do
|
160
|
+
recognize(in_stream)
|
161
|
+
end
|
162
|
+
printer = RubyProf::FlatPrinter.new(profile)
|
163
|
+
printer.print(@output)
|
164
|
+
when @profile
|
165
|
+
require 'profiler'
|
166
|
+
Profiler__.start_profile
|
167
|
+
recognize(in_stream)
|
168
|
+
Profiler__.print_profile
|
169
|
+
else
|
170
|
+
recognize(in_stream)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
def execute_interactive
|
176
|
+
@output.puts( Util.tidy(<<-END) )
|
177
|
+
| ===================================================================
|
178
|
+
| Ruby ANTLR Console for #{$0}
|
179
|
+
| ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
|
180
|
+
| * Enter source code lines
|
181
|
+
| * Enter EOF to finish up and exit
|
182
|
+
| (control+D on Mac/Linux/Unix or control+Z on Windows)
|
183
|
+
| ===================================================================
|
184
|
+
|
|
185
|
+
END
|
186
|
+
|
187
|
+
read_method =
|
188
|
+
begin
|
189
|
+
require 'readline'
|
190
|
+
line_number = 0
|
191
|
+
lambda do
|
192
|
+
begin
|
193
|
+
line = Readline.readline("#@name:#{line_number += 1}> ") or
|
194
|
+
@output.print("\n") # ensures result output is on a new line after EOF is entered
|
195
|
+
rescue Interrupt, EOFError
|
196
|
+
retry
|
197
|
+
end
|
198
|
+
line << "\n" if line
|
199
|
+
end
|
200
|
+
|
201
|
+
rescue LoadError
|
202
|
+
lambda do
|
203
|
+
begin
|
204
|
+
printf("%s:%i> ", @name, @input.lineno)
|
205
|
+
flush
|
206
|
+
line = @input.gets or @output.print("\n") # ensures result output is on a new line after EOF is entered
|
207
|
+
rescue Interrupt, EOFError
|
208
|
+
retry
|
209
|
+
end
|
210
|
+
line
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
stream = InteractiveStringStream.new(:name => @name, &read_method)
|
215
|
+
recognize(stream)
|
216
|
+
end
|
217
|
+
|
218
|
+
#def load_ruby_prof
|
219
|
+
# require 'ruby-prof'
|
220
|
+
#rescue LoadError
|
221
|
+
# attempt('rubygems', doc(<<-END)) { require 'rubygems' }
|
222
|
+
# | * failed to load the rubygems library:
|
223
|
+
# | - ensure rubygems is in installed
|
224
|
+
# | - make sure it is in this script's load path
|
225
|
+
# END
|
226
|
+
# attempt('ruby-prof', doc(<<-END)) { gem 'ruby-prof' }
|
227
|
+
# | * could not active the ruby-prof gem via ``gem "ruby-prof"''
|
228
|
+
# | - ensure the ruby-prof gem is installed
|
229
|
+
# | - it can be installed using the shell command
|
230
|
+
# | ``sudo gem install ruby-prof''
|
231
|
+
# END
|
232
|
+
# attempt('ruby-prof', doc(<<-END)) { require 'ruby-prof' }
|
233
|
+
# | * activated the ruby-prof gem, but subsequently failed to
|
234
|
+
# | load the ruby-prof library
|
235
|
+
# | - check for problems with the gem
|
236
|
+
# | - try restoring it to its initial install condition
|
237
|
+
# | using the shell command
|
238
|
+
# | ``sudo gem pristine ruby-prof''
|
239
|
+
# END
|
240
|
+
#end
|
241
|
+
|
242
|
+
#def load_prof
|
243
|
+
# attempt('profiler', doc(<<-END), 1) { require 'profiler' }
|
244
|
+
# | * failed to load the profiler library from the
|
245
|
+
# | ruby standard library
|
246
|
+
# | - ensure it is installed
|
247
|
+
# | - check that it is in this script's load path
|
248
|
+
# END
|
249
|
+
#end
|
250
|
+
|
251
|
+
def attempt(lib, message = nil, exit_status = nil)
|
252
|
+
yield
|
253
|
+
rescue LoadError => error
|
254
|
+
message or raise
|
255
|
+
@error.puts(message)
|
256
|
+
report_error(error)
|
257
|
+
report_load_path
|
258
|
+
exit(exit_status) if exit_status
|
259
|
+
rescue => error
|
260
|
+
@error.puts("received an error while attempting to load %p" % lib)
|
261
|
+
report_error(error)
|
262
|
+
exit(exit_status) if exit_status
|
263
|
+
end
|
264
|
+
|
265
|
+
def report_error(error)
|
266
|
+
puts!("~ error details:")
|
267
|
+
puts!(' [ %s ]' % error.class.name)
|
268
|
+
message = error.to_s.gsub(/\n/, "\n ")
|
269
|
+
puts!(' -> ' << message)
|
270
|
+
for call in error.backtrace
|
271
|
+
puts!(' ' << call)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
def report_load_path
|
276
|
+
puts!("~ content of $LOAD_PATH: ")
|
277
|
+
for dir in $LOAD_PATH
|
278
|
+
puts!(" - #{dir}")
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def setup
|
283
|
+
end
|
284
|
+
|
285
|
+
def fetch_class(name)
|
286
|
+
name.nil? || name.empty? and return(nil)
|
287
|
+
unless constant_exists?(name)
|
288
|
+
try_to_load(name)
|
289
|
+
constant_exists?(name) or return(nil)
|
290
|
+
end
|
291
|
+
|
292
|
+
name.split(/::/).inject(Object) do |mod, name|
|
293
|
+
# ::SomeModule splits to ['', 'SomeModule'] - so ignore empty strings
|
294
|
+
name.empty? and next(mod)
|
295
|
+
mod.const_get(name)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def constant_exists?(name)
|
300
|
+
eval("defined?(#{name})") == 'constant'
|
301
|
+
end
|
302
|
+
|
303
|
+
def try_to_load(name)
|
304
|
+
if name =~ /(\w+)::(Lexer|Parser|TreeParser)$/
|
305
|
+
retry_ok = true
|
306
|
+
script = name.gsub(/::/, '')
|
307
|
+
begin
|
308
|
+
return(require(script))
|
309
|
+
rescue LoadError
|
310
|
+
if retry_ok
|
311
|
+
script, retry_ok = $1, false
|
312
|
+
retry
|
313
|
+
else
|
314
|
+
return(nil)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
%w(puts print printf flush).each do |method|
|
321
|
+
class_eval(<<-END, __FILE__, __LINE__)
|
322
|
+
private
|
323
|
+
def #{method}(*args)
|
324
|
+
@output.#{method}(*args) unless @no_output
|
325
|
+
end
|
326
|
+
def #{method}!(*args)
|
327
|
+
@error.#{method}(*args) unless @no_output
|
328
|
+
end
|
329
|
+
END
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
|
334
|
+
=begin rdoc ANTLR3::Main::LexerMain
|
335
|
+
|
336
|
+
A class which implements a handy test script which is executed whenever an ANTLR
|
337
|
+
generated lexer file is run directly from the command line.
|
338
|
+
|
339
|
+
=end
|
340
|
+
class LexerMain < Main
|
341
|
+
def initialize(lexer_class, options = {})
|
342
|
+
super(options)
|
343
|
+
@lexer_class = lexer_class
|
344
|
+
end
|
345
|
+
|
346
|
+
def recognize(in_stream)
|
347
|
+
lexer = @lexer_class.new(in_stream)
|
348
|
+
|
349
|
+
loop do
|
350
|
+
begin
|
351
|
+
token = lexer.next_token
|
352
|
+
if token.nil? || token.type == ANTLR3::EOF then break
|
353
|
+
else display_token(token)
|
354
|
+
end
|
355
|
+
rescue ANTLR3::RecognitionError => error
|
356
|
+
report_error(error)
|
357
|
+
break
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
def display_token(token)
|
363
|
+
case token.channel
|
364
|
+
when ANTLR3::DEFAULT_CHANNEL
|
365
|
+
prefix = '-->'
|
366
|
+
suffix = ''
|
367
|
+
when ANTLR3::HIDDEN_CHANNEL
|
368
|
+
prefix = '// '
|
369
|
+
suffix = ' (hidden) '
|
370
|
+
else
|
371
|
+
prefix = '~~>'
|
372
|
+
suffix = ' (channel %p) ' % token.channel
|
373
|
+
end
|
374
|
+
|
375
|
+
printf("%s %-15s %-15p @ line %-3i col %-3i%s\n",
|
376
|
+
prefix, token.name, token.text,
|
377
|
+
token.line, token.column, suffix)
|
378
|
+
end
|
379
|
+
|
380
|
+
end
|
381
|
+
|
382
|
+
|
383
|
+
=begin rdoc ANTLR3::Main::ParserMain
|
384
|
+
|
385
|
+
A class which implements a handy test script which is executed whenever an ANTLR
|
386
|
+
generated parser file is run directly from the command line.
|
387
|
+
|
388
|
+
=end
|
389
|
+
class ParserMain < Main
|
390
|
+
def initialize(parser_class, options = {})
|
391
|
+
super(options)
|
392
|
+
@lexer_class_name = options[:lexer_class_name]
|
393
|
+
@lexer_class = options[:lexer_class]
|
394
|
+
@parser_class = parser_class
|
395
|
+
@parser_rule = options[:parser_rule]
|
396
|
+
if @debug = (@parser_class.debug? rescue false)
|
397
|
+
@port = options.fetch(:port, ANTLR3::Debug::DEFAULT_PORT)
|
398
|
+
@log = options.fetch(:log, @error)
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
def setup_options(opt)
|
403
|
+
super
|
404
|
+
opt.on('--lexer-name CLASS_NAME', "name of the lexer class to use") { |val|
|
405
|
+
@lexer_class_name = val
|
406
|
+
@lexer_class = nil
|
407
|
+
}
|
408
|
+
opt.on('--lexer-file PATH_TO_LIBRARY', "path to library defining the lexer class") { |val|
|
409
|
+
begin
|
410
|
+
test(?f, val) ? load(val) : require(val)
|
411
|
+
rescue LoadError
|
412
|
+
warn("unable to load the library specified by --lexer-file: #{$!}")
|
413
|
+
end
|
414
|
+
}
|
415
|
+
opt.on('--rule NAME', "name of the parser rule to execute") { |val| @parser_rule = val }
|
416
|
+
if @debug
|
417
|
+
opt.on('--port NUMBER', Integer, "port number to use for the debug socket") do |number|
|
418
|
+
@port = number
|
419
|
+
end
|
420
|
+
opt.on('--log PATH', "path of file to use to record socket activity",
|
421
|
+
"(stderr by default)" ) do |path|
|
422
|
+
@log = open(path, 'w')
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
def setup
|
428
|
+
unless @lexer_class ||= fetch_class(@lexer_class_name)
|
429
|
+
if @lexer_class_name
|
430
|
+
fail("unable to locate the lexer class ``#@lexer_class_name''")
|
431
|
+
else
|
432
|
+
unless @lexer_class = @parser_class.associated_lexer
|
433
|
+
fail(doc(<<-END))
|
434
|
+
| no lexer class has been specified with the --lexer-name option
|
435
|
+
| and #@parser_class does not appear to have an associated
|
436
|
+
| lexer class
|
437
|
+
END
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
@parser_rule ||= @parser_class.default_rule or
|
442
|
+
fail("a parser rule name must be specified via --rule NAME")
|
443
|
+
end
|
444
|
+
|
445
|
+
def recognize(in_stream)
|
446
|
+
parser_options = {}
|
447
|
+
if @debug
|
448
|
+
parser_options[:port] = @port
|
449
|
+
parser_options[:log] = @log
|
450
|
+
end
|
451
|
+
lexer = @lexer_class.new( in_stream )
|
452
|
+
token_stream = CommonTokenStream.new( lexer )
|
453
|
+
parser = @parser_class.new( token_stream, parser_options )
|
454
|
+
result = parser.send( @parser_rule ) and present( result )
|
455
|
+
end
|
456
|
+
|
457
|
+
def present( return_value )
|
458
|
+
ASTBuilder > @parser_class and return_value = return_value.tree
|
459
|
+
text =
|
460
|
+
begin
|
461
|
+
require 'pp'
|
462
|
+
return_value.pretty_inspect
|
463
|
+
rescue LoadError, NoMethodError
|
464
|
+
return_value.inspect
|
465
|
+
end
|
466
|
+
puts(text)
|
467
|
+
end
|
468
|
+
|
469
|
+
end
|
470
|
+
|
471
|
+
|
472
|
+
=begin rdoc ANTLR3::Main::WalkerMain
|
473
|
+
|
474
|
+
A class which implements a handy test script which is executed whenever an ANTLR
|
475
|
+
generated tree walker (tree parser) file is run directly from the command line.
|
476
|
+
|
477
|
+
=end
|
478
|
+
|
479
|
+
class WalkerMain < Main
|
480
|
+
attr_accessor :walker_class, :lexer_class, :parser_class
|
481
|
+
def initialize(walker_class, options = {})
|
482
|
+
super(options)
|
483
|
+
@walker_class = walker_class
|
484
|
+
@lexer_class_name = options[:lexer_class_name]
|
485
|
+
@lexer_class = options[:lexer_class]
|
486
|
+
@parser_class_name = options[:parser_class_name]
|
487
|
+
@parser_class = options[:parser_class]
|
488
|
+
if @debug = (@parser_class.debug? rescue false)
|
489
|
+
@port = options.fetch(:port, ANTLR3::Debug::DEFAULT_PORT)
|
490
|
+
@log = options.fetch(:log, @error)
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
def setup_options(opt)
|
495
|
+
super
|
496
|
+
opt.on('--lexer-name CLASS_NAME') { |val| @lexer_class_name = val }
|
497
|
+
opt.on('--lexer-file PATH_TO_LIBRARY') { |val|
|
498
|
+
begin
|
499
|
+
test(?f, val) ? load(val) : require(val)
|
500
|
+
rescue LoadError
|
501
|
+
warn("unable to load the library specified by --lexer-file: #{$!}")
|
502
|
+
end
|
503
|
+
}
|
504
|
+
opt.on('--parser-name CLASS_NAME') { |val| @parser_class_name = val }
|
505
|
+
opt.on('--parser-file PATH_TO_LIBRARY') { |val|
|
506
|
+
begin
|
507
|
+
test(?f, val) ? load(val) : require(val)
|
508
|
+
rescue LoadError
|
509
|
+
warn("unable to load the library specified by --parser-file: #{$!}")
|
510
|
+
end
|
511
|
+
}
|
512
|
+
opt.on('--parser-rule NAME') { |val| @parser_rule = val }
|
513
|
+
opt.on('--rule NAME') { |val| @walker_rule = val }
|
514
|
+
|
515
|
+
if @debug
|
516
|
+
opt.on('--port NUMBER', Integer, "port number to use for the debug socket") do |number|
|
517
|
+
@port = number
|
518
|
+
end
|
519
|
+
opt.on('--log PATH', "path of file to use to record socket activity",
|
520
|
+
"(stderr by default)" ) do |path|
|
521
|
+
@log = open(path, 'w')
|
522
|
+
end
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
526
|
+
# TODO: finish the Main modules
|
527
|
+
def setup
|
528
|
+
unless @lexer_class ||= fetch_class(@lexer_class_name)
|
529
|
+
fail("unable to locate the lexer class #@lexer_class_name")
|
530
|
+
end
|
531
|
+
unless @parser_class ||= fetch_class(@parser_class_name)
|
532
|
+
fail("unable to locate the parser class #@parser_class_name")
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
def recognize(in_stream)
|
537
|
+
walker_options = {}
|
538
|
+
if @debug
|
539
|
+
walker_options[:port] = @port
|
540
|
+
walker_options[:log] = @log
|
541
|
+
end
|
542
|
+
@lexer = @lexer_class.new(in_stream)
|
543
|
+
@token_stream = ANTLR3::CommonTokenStream.new(@lexer)
|
544
|
+
@parser = @parser_class.new(@token_stream)
|
545
|
+
if result = @parser.send(@parser_rule)
|
546
|
+
result.respond_to?(:tree) or fail("Parser did not return an AST for rule #@parser_rule")
|
547
|
+
@node_stream = ANTLR3::CommonTreeNodeStream.new(result.tree)
|
548
|
+
@node_stream.token_stream = @token_stream
|
549
|
+
@walker = @walker_class.new(@node_stream, walker_options)
|
550
|
+
if result = @walker.send(@walker_rule)
|
551
|
+
out = result.tree.inspect rescue result.inspect
|
552
|
+
puts(out)
|
553
|
+
else puts!("walker.#@walker_rule returned nil")
|
554
|
+
end
|
555
|
+
else puts!("parser.#@parser_rule returned nil")
|
556
|
+
end
|
557
|
+
end
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
561
|
+
end
|