1*16467b97STreehugger Robot#!/usr/bin/ruby 2*16467b97STreehugger Robot# encoding: utf-8 3*16467b97STreehugger Robot 4*16467b97STreehugger Robotrequire 'antlr3' 5*16467b97STreehugger Robot 6*16467b97STreehugger Robot=begin LICENSE 7*16467b97STreehugger Robot 8*16467b97STreehugger Robot[The "BSD licence"] 9*16467b97STreehugger RobotCopyright (c) 2009-2010 Kyle Yetter 10*16467b97STreehugger RobotAll rights reserved. 11*16467b97STreehugger Robot 12*16467b97STreehugger RobotRedistribution and use in source and binary forms, with or without 13*16467b97STreehugger Robotmodification, are permitted provided that the following conditions 14*16467b97STreehugger Robotare met: 15*16467b97STreehugger Robot 16*16467b97STreehugger Robot 1. Redistributions of source code must retain the above copyright 17*16467b97STreehugger Robot notice, this list of conditions and the following disclaimer. 18*16467b97STreehugger Robot 2. Redistributions in binary form must reproduce the above copyright 19*16467b97STreehugger Robot notice, this list of conditions and the following disclaimer in the 20*16467b97STreehugger Robot documentation and/or other materials provided with the distribution. 21*16467b97STreehugger Robot 3. The name of the author may not be used to endorse or promote products 22*16467b97STreehugger Robot derived from this software without specific prior written permission. 23*16467b97STreehugger Robot 24*16467b97STreehugger RobotTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25*16467b97STreehugger RobotIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26*16467b97STreehugger RobotOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27*16467b97STreehugger RobotIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28*16467b97STreehugger RobotINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29*16467b97STreehugger RobotNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30*16467b97STreehugger RobotDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31*16467b97STreehugger RobotTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32*16467b97STreehugger Robot(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33*16467b97STreehugger RobotTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34*16467b97STreehugger Robot 35*16467b97STreehugger Robot=end 36*16467b97STreehugger Robot 37*16467b97STreehugger Robotmodule ANTLR3 38*16467b97STreehugger Robot 39*16467b97STreehugger Robot=begin rdoc ANTLR3::Debug 40*16467b97STreehugger Robot 41*16467b97STreehugger RobotNamespace for all debugging-related class and module definitions. 42*16467b97STreehugger Robot 43*16467b97STreehugger Robot=end 44*16467b97STreehugger Robot 45*16467b97STreehugger Robotmodule Debug 46*16467b97STreehugger Robot 47*16467b97STreehugger RobotDEFAULT_PORT = 49100 48*16467b97STreehugger Robot 49*16467b97STreehugger Robot# since there are many components to the debug-mode 50*16467b97STreehugger Robot# section of the antlr3 runtime library, most of which 51*16467b97STreehugger Robot# are not used simultaneously, debug.rb contains the 52*16467b97STreehugger Robot# base of the debug library and the various listeners 53*16467b97STreehugger Robot# and tree-related code are autloaded on-demand 54*16467b97STreehugger Robotautoload :EventSocketProxy, 'antlr3/debug/socket' 55*16467b97STreehugger Robotautoload :RemoteEventSocketListener, 'antlr3/debug/socket' 56*16467b97STreehugger Robotautoload :TraceEventListener, 'antlr3/debug/trace-event-listener' 57*16467b97STreehugger Robotautoload :RecordEventListener, 'antlr3/debug/record-event-listener' 58*16467b97STreehugger Robotautoload :RuleTracer, 'antlr3/debug/rule-tracer' 59*16467b97STreehugger Robotautoload :EventHub, 'antlr3/debug/event-hub' 60*16467b97STreehugger Robotautoload :TreeAdaptor, 'antlr3/tree/debug' 61*16467b97STreehugger Robotautoload :TreeNodeStream, 'antlr3/tree/debug' 62*16467b97STreehugger Robot 63*16467b97STreehugger RobotRecognizerSharedState = Struct.new( 64*16467b97STreehugger Robot # the rule invocation depth 65*16467b97STreehugger Robot :rule_invocation_stack, 66*16467b97STreehugger Robot # a boolean flag to indicate whether or not the current decision is cyclic 67*16467b97STreehugger Robot :cyclic_decision, 68*16467b97STreehugger Robot # a stack that tracks follow sets for error recovery 69*16467b97STreehugger Robot :following, 70*16467b97STreehugger Robot # a flag indicating whether or not the recognizer is in error recovery mode 71*16467b97STreehugger Robot :error_recovery, 72*16467b97STreehugger Robot # the index in the input stream of the last error 73*16467b97STreehugger Robot :last_error_index, 74*16467b97STreehugger Robot # tracks the backtracking depth 75*16467b97STreehugger Robot :backtracking, 76*16467b97STreehugger Robot # if a grammar is compiled with the memoization option, this will 77*16467b97STreehugger Robot # be set to a hash mapping previously parsed rules to cached indices 78*16467b97STreehugger Robot :rule_memory, 79*16467b97STreehugger Robot # tracks the number of syntax errors seen so far 80*16467b97STreehugger Robot :syntax_errors, 81*16467b97STreehugger Robot # holds newly constructed tokens for lexer rules 82*16467b97STreehugger Robot :token, 83*16467b97STreehugger Robot # the input stream index at which the token starts 84*16467b97STreehugger Robot :token_start_position, 85*16467b97STreehugger Robot # the input stream line number at which the token starts 86*16467b97STreehugger Robot :token_start_line, 87*16467b97STreehugger Robot # the input stream column at which the token starts 88*16467b97STreehugger Robot :token_start_column, 89*16467b97STreehugger Robot # the channel value of the target token 90*16467b97STreehugger Robot :channel, 91*16467b97STreehugger Robot # the type value of the target token 92*16467b97STreehugger Robot :type, 93*16467b97STreehugger Robot # the text of the target token 94*16467b97STreehugger Robot :text 95*16467b97STreehugger Robot) 96*16467b97STreehugger Robot 97*16467b97STreehugger Robot=begin rdoc ANTLR3::Debug::RecognizerSharedState 98*16467b97STreehugger Robot 99*16467b97STreehugger RobotANTLR3::Debug::RecognizerSharedState is identical to 100*16467b97STreehugger RobotANTLR3::RecognizerSharedState, but adds additional fields used for recognizers 101*16467b97STreehugger Robotgenerated in debug or profiling mode. 102*16467b97STreehugger Robot 103*16467b97STreehugger Robot=end 104*16467b97STreehugger Robotclass RecognizerSharedState 105*16467b97STreehugger Robot def initialize 106*16467b97STreehugger Robot super( [], false, [], false, -1, 0, nil, 0, nil, -1 ) 107*16467b97STreehugger Robot # ^-- same as this --v 108*16467b97STreehugger Robot # self.following = [] 109*16467b97STreehugger Robot # self.error_recovery = false 110*16467b97STreehugger Robot # self.last_error_index = -1 111*16467b97STreehugger Robot # self.backtracking = 0 112*16467b97STreehugger Robot # self.syntax_errors = 0 113*16467b97STreehugger Robot # self.rule_level = 0 114*16467b97STreehugger Robot # self.token_start_position = -1 115*16467b97STreehugger Robot end 116*16467b97STreehugger Robot 117*16467b97STreehugger Robot def reset! 118*16467b97STreehugger Robot self.following.clear 119*16467b97STreehugger Robot self.error_recovery = false 120*16467b97STreehugger Robot self.last_error_index = -1 121*16467b97STreehugger Robot self.backtracking = 0 122*16467b97STreehugger Robot self.rule_memory and rule_memory.clear 123*16467b97STreehugger Robot self.syntax_errors = 0 124*16467b97STreehugger Robot self.token = nil 125*16467b97STreehugger Robot self.token_start_position = -1 126*16467b97STreehugger Robot self.token_start_line = nil 127*16467b97STreehugger Robot self.token_start_column = nil 128*16467b97STreehugger Robot self.channel = nil 129*16467b97STreehugger Robot self.type = nil 130*16467b97STreehugger Robot self.text = nil 131*16467b97STreehugger Robot self.rule_invocation_stack.clear 132*16467b97STreehugger Robot end 133*16467b97STreehugger Robot 134*16467b97STreehugger Robotend 135*16467b97STreehugger Robot 136*16467b97STreehugger Robot=begin rdoc ANTLR3::Debug::ParserEvents 137*16467b97STreehugger Robot 138*16467b97STreehugger RobotParserEvents adds debugging event hook methods and functionality that is 139*16467b97STreehugger Robotrequired by the code ANTLR generated when called with the <tt>-debug</tt> 140*16467b97STreehugger Robotswitch. 141*16467b97STreehugger Robot 142*16467b97STreehugger Robot=end 143*16467b97STreehugger Robotmodule ParserEvents 144*16467b97STreehugger Robot include ANTLR3::Error 145*16467b97STreehugger Robot 146*16467b97STreehugger Robot def self.included( klass ) 147*16467b97STreehugger Robot super 148*16467b97STreehugger Robot if klass.is_a?( ::Class ) 149*16467b97STreehugger Robot def klass.debug? 150*16467b97STreehugger Robot true 151*16467b97STreehugger Robot end 152*16467b97STreehugger Robot end 153*16467b97STreehugger Robot end 154*16467b97STreehugger Robot 155*16467b97STreehugger Robot 156*16467b97STreehugger Robot attr_reader :debug_listener 157*16467b97STreehugger Robot 158*16467b97STreehugger Robot def initialize( stream, options = {} ) 159*16467b97STreehugger Robot @debug_listener = options[ :debug_listener ] ||= begin 160*16467b97STreehugger Robot EventSocketProxy.new( self, options ).handshake 161*16467b97STreehugger Robot end 162*16467b97STreehugger Robot options[ :state ] ||= Debug::RecognizerSharedState.new 163*16467b97STreehugger Robot super( stream, options ) 164*16467b97STreehugger Robot if @input.is_a?( Debug::TokenStream ) 165*16467b97STreehugger Robot @input.debug_listener ||= @debug_listener 166*16467b97STreehugger Robot else 167*16467b97STreehugger Robot @input = Debug::TokenStream.wrap( @input, @debug_listener ) 168*16467b97STreehugger Robot end 169*16467b97STreehugger Robot end 170*16467b97STreehugger Robot 171*16467b97STreehugger Robot def rule_level 172*16467b97STreehugger Robot @state.rule_invocation_stack.length 173*16467b97STreehugger Robot end 174*16467b97STreehugger Robot 175*16467b97STreehugger Robot def cyclic_decision? 176*16467b97STreehugger Robot @state.cyclic_decision 177*16467b97STreehugger Robot end 178*16467b97STreehugger Robot 179*16467b97STreehugger Robot def cyclic_decision=( flag ) 180*16467b97STreehugger Robot @state.cyclic_decision = flag 181*16467b97STreehugger Robot end 182*16467b97STreehugger Robot 183*16467b97STreehugger Robot # custom attribute writer for debug_listener 184*16467b97STreehugger Robot # propegates the change in listener to the 185*16467b97STreehugger Robot # parser's debugging input stream 186*16467b97STreehugger Robot def debug_listener=( dbg ) 187*16467b97STreehugger Robot @debug_listener = dbg 188*16467b97STreehugger Robot @input.debug_listener = dbg rescue nil 189*16467b97STreehugger Robot end 190*16467b97STreehugger Robot 191*16467b97STreehugger Robot def begin_resync 192*16467b97STreehugger Robot @debug_listener.begin_resync 193*16467b97STreehugger Robot super 194*16467b97STreehugger Robot end 195*16467b97STreehugger Robot 196*16467b97STreehugger Robot def end_resync 197*16467b97STreehugger Robot @debug_listener.end_resync 198*16467b97STreehugger Robot super 199*16467b97STreehugger Robot end 200*16467b97STreehugger Robot 201*16467b97STreehugger Robot # TO-DO: is this pointless? 202*16467b97STreehugger Robot def resync 203*16467b97STreehugger Robot begin_resync 204*16467b97STreehugger Robot yield( self ) 205*16467b97STreehugger Robot ensure 206*16467b97STreehugger Robot end_resync 207*16467b97STreehugger Robot end 208*16467b97STreehugger Robot 209*16467b97STreehugger Robot def begin_backtrack 210*16467b97STreehugger Robot @debug_listener.begin_backtrack( @state.backtracking ) 211*16467b97STreehugger Robot end 212*16467b97STreehugger Robot 213*16467b97STreehugger Robot def end_backtrack( successful ) 214*16467b97STreehugger Robot @debug_listener.end_backtrack( @state.backtracking, successful ) 215*16467b97STreehugger Robot end 216*16467b97STreehugger Robot 217*16467b97STreehugger Robot def backtrack 218*16467b97STreehugger Robot @state.backtracking += 1 219*16467b97STreehugger Robot @debug_listener.begin_backtrack( @state.backtracking ) 220*16467b97STreehugger Robot start = @input.mark 221*16467b97STreehugger Robot success = 222*16467b97STreehugger Robot begin yield 223*16467b97STreehugger Robot rescue BacktrackingFailed then false 224*16467b97STreehugger Robot else true 225*16467b97STreehugger Robot end 226*16467b97STreehugger Robot return success 227*16467b97STreehugger Robot ensure 228*16467b97STreehugger Robot @input.rewind( start ) 229*16467b97STreehugger Robot @debug_listener.end_backtrack( @state.backtracking, ( success rescue nil ) ) 230*16467b97STreehugger Robot @state.backtracking -= 1 231*16467b97STreehugger Robot end 232*16467b97STreehugger Robot 233*16467b97STreehugger Robot def report_error( exc ) 234*16467b97STreehugger Robot ANTLR3::RecognitionError === exc and 235*16467b97STreehugger Robot @debug_listener.recognition_exception( exc ) 236*16467b97STreehugger Robot super 237*16467b97STreehugger Robot end 238*16467b97STreehugger Robot 239*16467b97STreehugger Robot def missing_symbol( error, expected_type, follow ) 240*16467b97STreehugger Robot symbol = super 241*16467b97STreehugger Robot @debug_listener.consume_node( symbol ) 242*16467b97STreehugger Robot return( symbol ) 243*16467b97STreehugger Robot end 244*16467b97STreehugger Robot 245*16467b97STreehugger Robot def in_rule( grammar_file, rule_name ) 246*16467b97STreehugger Robot @state.rule_invocation_stack.empty? and @debug_listener.commence 247*16467b97STreehugger Robot @debug_listener.enter_rule( grammar_file, rule_name ) 248*16467b97STreehugger Robot @state.rule_invocation_stack.push( grammar_file, rule_name ) 249*16467b97STreehugger Robot yield 250*16467b97STreehugger Robot ensure 251*16467b97STreehugger Robot @state.rule_invocation_stack.pop( 2 ) 252*16467b97STreehugger Robot @debug_listener.exit_rule( grammar_file, rule_name ) 253*16467b97STreehugger Robot @state.rule_invocation_stack.empty? and @debug_listener.terminate 254*16467b97STreehugger Robot end 255*16467b97STreehugger Robot 256*16467b97STreehugger Robot def rule_invocation_stack 257*16467b97STreehugger Robot @state.rule_invocation_stack.each_slice( 2 ).to_a 258*16467b97STreehugger Robot end 259*16467b97STreehugger Robot 260*16467b97STreehugger Robot def predicate?( description ) 261*16467b97STreehugger Robot result = yield 262*16467b97STreehugger Robot @debug_listener.semantic_predicate( result, description ) 263*16467b97STreehugger Robot return result 264*16467b97STreehugger Robot end 265*16467b97STreehugger Robot 266*16467b97STreehugger Robot def in_alternative( alt_number ) 267*16467b97STreehugger Robot @debug_listener.enter_alternative( alt_number ) 268*16467b97STreehugger Robot end 269*16467b97STreehugger Robot 270*16467b97STreehugger Robot def in_subrule( decision_number ) 271*16467b97STreehugger Robot @debug_listener.enter_subrule( decision_number ) 272*16467b97STreehugger Robot yield 273*16467b97STreehugger Robot ensure 274*16467b97STreehugger Robot @debug_listener.exit_subrule( decision_number ) 275*16467b97STreehugger Robot end 276*16467b97STreehugger Robot 277*16467b97STreehugger Robot def in_decision( decision_number ) 278*16467b97STreehugger Robot @debug_listener.enter_decision( decision_number ) 279*16467b97STreehugger Robot yield 280*16467b97STreehugger Robot ensure 281*16467b97STreehugger Robot @debug_listener.exit_decision( decision_number ) 282*16467b97STreehugger Robot end 283*16467b97STreehugger Robotend 284*16467b97STreehugger Robot 285*16467b97STreehugger Robot 286*16467b97STreehugger Robot=begin rdoc ANTLR3::Debug::TokenStream 287*16467b97STreehugger Robot 288*16467b97STreehugger RobotA module that wraps token stream methods with debugging event code. A debuggable 289*16467b97STreehugger Robotparser will <tt>extend</tt> its input stream with this module if the stream is 290*16467b97STreehugger Robotnot already a Debug::TokenStream. 291*16467b97STreehugger Robot 292*16467b97STreehugger Robot=end 293*16467b97STreehugger Robotmodule TokenStream 294*16467b97STreehugger Robot 295*16467b97STreehugger Robot def self.wrap( stream, debug_listener = nil ) 296*16467b97STreehugger Robot stream.extend( self ) 297*16467b97STreehugger Robot stream.instance_eval do 298*16467b97STreehugger Robot @initial_stream_state = true 299*16467b97STreehugger Robot @debug_listener = debug_listener 300*16467b97STreehugger Robot @last_marker = nil 301*16467b97STreehugger Robot end 302*16467b97STreehugger Robot return( stream ) 303*16467b97STreehugger Robot end 304*16467b97STreehugger Robot attr_reader :last_marker 305*16467b97STreehugger Robot attr_accessor :debug_listener 306*16467b97STreehugger Robot 307*16467b97STreehugger Robot def consume 308*16467b97STreehugger Robot @initial_stream_state and consume_initial_hidden_tokens 309*16467b97STreehugger Robot a = index + 1 # the next position IF there are no hidden tokens in between 310*16467b97STreehugger Robot t = super 311*16467b97STreehugger Robot b = index # the actual position after consuming 312*16467b97STreehugger Robot @debug_listener.consume_token( t ) if @debug_listener 313*16467b97STreehugger Robot 314*16467b97STreehugger Robot # if b > a, report the consumption of hidden tokens 315*16467b97STreehugger Robot for i in a...b 316*16467b97STreehugger Robot @debug_listener.consume_hidden_token at( i ) 317*16467b97STreehugger Robot end 318*16467b97STreehugger Robot end 319*16467b97STreehugger Robot 320*16467b97STreehugger Robot 321*16467b97STreehugger Robot # after a token stream fills up its buffer 322*16467b97STreehugger Robot # by exhausting its token source, it may 323*16467b97STreehugger Robot # skip to an initial position beyond the first 324*16467b97STreehugger Robot # actual token, if there are hidden tokens 325*16467b97STreehugger Robot # at the beginning of the stream. 326*16467b97STreehugger Robot # 327*16467b97STreehugger Robot # This private method is used to 328*16467b97STreehugger Robot # figure out if any hidden tokens 329*16467b97STreehugger Robot # were skipped initially, and then 330*16467b97STreehugger Robot # report their consumption to 331*16467b97STreehugger Robot # the debug listener 332*16467b97STreehugger Robot def consume_initial_hidden_tokens 333*16467b97STreehugger Robot first_on_channel_token_index = self.index 334*16467b97STreehugger Robot first_on_channel_token_index.times do |index| 335*16467b97STreehugger Robot @debug_listener.consume_hidden_token at( index ) 336*16467b97STreehugger Robot end 337*16467b97STreehugger Robot @initial_stream_state = false 338*16467b97STreehugger Robot end 339*16467b97STreehugger Robot 340*16467b97STreehugger Robot private :consume_initial_hidden_tokens 341*16467b97STreehugger Robot 342*16467b97STreehugger Robot ############################################################################################ 343*16467b97STreehugger Robot ###################################### Stream Methods ###################################### 344*16467b97STreehugger Robot ############################################################################################ 345*16467b97STreehugger Robot 346*16467b97STreehugger Robot def look( steps = 1 ) 347*16467b97STreehugger Robot @initial_stream_state and consume_initial_hidden_tokens 348*16467b97STreehugger Robot token = super( steps ) 349*16467b97STreehugger Robot @debug_listener.look( steps, token ) 350*16467b97STreehugger Robot return token 351*16467b97STreehugger Robot end 352*16467b97STreehugger Robot 353*16467b97STreehugger Robot def peek( steps = 1 ) 354*16467b97STreehugger Robot look( steps ).type 355*16467b97STreehugger Robot end 356*16467b97STreehugger Robot 357*16467b97STreehugger Robot def mark 358*16467b97STreehugger Robot @last_marker = super 359*16467b97STreehugger Robot @debug_listener.mark( @last_marker ) 360*16467b97STreehugger Robot return @last_marker 361*16467b97STreehugger Robot end 362*16467b97STreehugger Robot 363*16467b97STreehugger Robot def rewind( marker = nil, release = true ) 364*16467b97STreehugger Robot @debug_listener.rewind( marker ) 365*16467b97STreehugger Robot super 366*16467b97STreehugger Robot end 367*16467b97STreehugger Robotend 368*16467b97STreehugger Robot 369*16467b97STreehugger Robot=begin rdoc ANTLR3::Debug::EventListener 370*16467b97STreehugger Robot 371*16467b97STreehugger RobotA listener that simply records text representations of the events. Useful for debugging the 372*16467b97STreehugger Robotdebugging facility ;) Subclasses can override the record() method (which defaults to printing 373*16467b97STreehugger Robotto stdout) to record the events in a different way. 374*16467b97STreehugger Robot 375*16467b97STreehugger Robot=end 376*16467b97STreehugger Robotmodule EventListener 377*16467b97STreehugger Robot PROTOCOL_VERSION = '2' 378*16467b97STreehugger Robot # The parser has just entered a rule. No decision has been made about 379*16467b97STreehugger Robot # which alt is predicted. This is fired AFTER init actions have been 380*16467b97STreehugger Robot # executed. Attributes are defined and available etc... 381*16467b97STreehugger Robot # The grammarFileName allows composite grammars to jump around among 382*16467b97STreehugger Robot # multiple grammar files. 383*16467b97STreehugger Robot 384*16467b97STreehugger Robot def enter_rule( grammar_file, rule_name ) 385*16467b97STreehugger Robot # do nothing 386*16467b97STreehugger Robot end 387*16467b97STreehugger Robot 388*16467b97STreehugger Robot # Because rules can have lots of alternatives, it is very useful to 389*16467b97STreehugger Robot # know which alt you are entering. This is 1..n for n alts. 390*16467b97STreehugger Robot 391*16467b97STreehugger Robot def enter_alternative( alt ) 392*16467b97STreehugger Robot # do nothing 393*16467b97STreehugger Robot end 394*16467b97STreehugger Robot 395*16467b97STreehugger Robot # This is the last thing executed before leaving a rule. It is 396*16467b97STreehugger Robot # executed even if an exception is thrown. This is triggered after 397*16467b97STreehugger Robot # error reporting and recovery have occurred (unless the exception is 398*16467b97STreehugger Robot # not caught in this rule). This implies an "exitAlt" event. 399*16467b97STreehugger Robot # The grammarFileName allows composite grammars to jump around among 400*16467b97STreehugger Robot # multiple grammar files. 401*16467b97STreehugger Robot 402*16467b97STreehugger Robot def exit_rule( grammar_file, rule_name ) 403*16467b97STreehugger Robot # do nothing 404*16467b97STreehugger Robot end 405*16467b97STreehugger Robot 406*16467b97STreehugger Robot # Track entry into any (...) subrule other EBNF construct 407*16467b97STreehugger Robot 408*16467b97STreehugger Robot def enter_subrule( decision_number ) 409*16467b97STreehugger Robot # do nothing 410*16467b97STreehugger Robot end 411*16467b97STreehugger Robot 412*16467b97STreehugger Robot def exit_subrule( decision_number ) 413*16467b97STreehugger Robot # do nothing 414*16467b97STreehugger Robot end 415*16467b97STreehugger Robot 416*16467b97STreehugger Robot # Every decision, fixed k or arbitrary, has an enter/exit event 417*16467b97STreehugger Robot # so that a GUI can easily track what look/consume events are 418*16467b97STreehugger Robot # associated with prediction. You will see a single enter/exit 419*16467b97STreehugger Robot # subrule but multiple enter/exit decision events, one for each 420*16467b97STreehugger Robot # loop iteration. 421*16467b97STreehugger Robot 422*16467b97STreehugger Robot def enter_decision( decision_number ) 423*16467b97STreehugger Robot # do nothing 424*16467b97STreehugger Robot end 425*16467b97STreehugger Robot 426*16467b97STreehugger Robot def exit_decision( decision_number ) 427*16467b97STreehugger Robot # do nothing 428*16467b97STreehugger Robot end 429*16467b97STreehugger Robot 430*16467b97STreehugger Robot # An input token was consumed; matched by any kind of element. 431*16467b97STreehugger Robot # Trigger after the token was matched by things like match(), matchAny(). 432*16467b97STreehugger Robot 433*16467b97STreehugger Robot def consume_token( tree ) 434*16467b97STreehugger Robot # do nothing 435*16467b97STreehugger Robot end 436*16467b97STreehugger Robot 437*16467b97STreehugger Robot # An off-channel input token was consumed. 438*16467b97STreehugger Robot # Trigger after the token was matched by things like match(), matchAny(). 439*16467b97STreehugger Robot # (unless of course the hidden token is first stuff in the input stream). 440*16467b97STreehugger Robot 441*16467b97STreehugger Robot def consume_hidden_token( tree ) 442*16467b97STreehugger Robot # do nothing 443*16467b97STreehugger Robot end 444*16467b97STreehugger Robot 445*16467b97STreehugger Robot # Somebody (anybody) looked ahead. Note that this actually gets 446*16467b97STreehugger Robot # triggered by both peek and look calls. The debugger will want to know 447*16467b97STreehugger Robot # which Token object was examined. Like consumeToken, this indicates 448*16467b97STreehugger Robot # what token was seen at that depth. A remote debugger cannot look 449*16467b97STreehugger Robot # ahead into a file it doesn't have so look events must pass the token 450*16467b97STreehugger Robot # even if the info is redundant. 451*16467b97STreehugger Robot 452*16467b97STreehugger Robot def look( i, tree ) 453*16467b97STreehugger Robot # do nothing 454*16467b97STreehugger Robot end 455*16467b97STreehugger Robot 456*16467b97STreehugger Robot # The parser is going to look arbitrarily ahead; mark this location, 457*16467b97STreehugger Robot # the token stream's marker is sent in case you need it. 458*16467b97STreehugger Robot 459*16467b97STreehugger Robot def mark( marker ) 460*16467b97STreehugger Robot # do nothing 461*16467b97STreehugger Robot end 462*16467b97STreehugger Robot 463*16467b97STreehugger Robot # After an arbitrairly long look as with a cyclic DFA (or with 464*16467b97STreehugger Robot # any backtrack), this informs the debugger that stream should be 465*16467b97STreehugger Robot # rewound to the position associated with marker. 466*16467b97STreehugger Robot 467*16467b97STreehugger Robot def rewind( marker = nil ) 468*16467b97STreehugger Robot # do nothing 469*16467b97STreehugger Robot end 470*16467b97STreehugger Robot 471*16467b97STreehugger Robot def begin_backtrack( level ) 472*16467b97STreehugger Robot # do nothing 473*16467b97STreehugger Robot end 474*16467b97STreehugger Robot 475*16467b97STreehugger Robot def end_backtrack( level, successful ) 476*16467b97STreehugger Robot # do nothing 477*16467b97STreehugger Robot end 478*16467b97STreehugger Robot 479*16467b97STreehugger Robot def backtrack( level ) 480*16467b97STreehugger Robot begin_backtrack( level ) 481*16467b97STreehugger Robot successful = yield( self ) 482*16467b97STreehugger Robot end_backtrack( level, successful ) 483*16467b97STreehugger Robot end 484*16467b97STreehugger Robot 485*16467b97STreehugger Robot # To watch a parser move through the grammar, the parser needs to 486*16467b97STreehugger Robot # inform the debugger what line/charPos it is passing in the grammar. 487*16467b97STreehugger Robot # For now, this does not know how to switch from one grammar to the 488*16467b97STreehugger Robot # other and back for island grammars etc... 489*16467b97STreehugger Robot # This should also allow breakpoints because the debugger can stop 490*16467b97STreehugger Robot # the parser whenever it hits this line/pos. 491*16467b97STreehugger Robot 492*16467b97STreehugger Robot def location( line, position ) 493*16467b97STreehugger Robot # do nothing 494*16467b97STreehugger Robot end 495*16467b97STreehugger Robot 496*16467b97STreehugger Robot # A recognition exception occurred such as NoViableAltError. I made 497*16467b97STreehugger Robot # this a generic event so that I can alter the exception hierachy later 498*16467b97STreehugger Robot # without having to alter all the debug objects. 499*16467b97STreehugger Robot # Upon error, the stack of enter rule/subrule must be properly unwound. 500*16467b97STreehugger Robot # If no viable alt occurs it is within an enter/exit decision, which 501*16467b97STreehugger Robot # also must be rewound. Even the rewind for each mark must be unwount. 502*16467b97STreehugger Robot # In the Java target this is pretty easy using try/finally, if a bit 503*16467b97STreehugger Robot # ugly in the generated code. The rewind is generated in DFA.predict() 504*16467b97STreehugger Robot # actually so no code needs to be generated for that. For languages 505*16467b97STreehugger Robot # w/o this "finally" feature (C++?), the target implementor will have 506*16467b97STreehugger Robot # to build an event stack or something. 507*16467b97STreehugger Robot # Across a socket for remote debugging, only the RecognitionError 508*16467b97STreehugger Robot # data fields are transmitted. The token object or whatever that 509*16467b97STreehugger Robot # caused the problem was the last object referenced by look. The 510*16467b97STreehugger Robot # immediately preceding look event should hold the unexpected Token or 511*16467b97STreehugger Robot # char. 512*16467b97STreehugger Robot # Here is a sample event trace for grammar: 513*16467b97STreehugger Robot # b : C ({;}A|B) // {;} is there to prevent A|B becoming a set 514*16467b97STreehugger Robot # | D 515*16467b97STreehugger Robot # ; 516*16467b97STreehugger Robot # The sequence for this rule (with no viable alt in the subrule) for 517*16467b97STreehugger Robot # input 'c c' (there are 3 tokens) is: 518*16467b97STreehugger Robot # commence 519*16467b97STreehugger Robot # look 520*16467b97STreehugger Robot # enterRule b 521*16467b97STreehugger Robot # location 7 1 522*16467b97STreehugger Robot # enter decision 3 523*16467b97STreehugger Robot # look 524*16467b97STreehugger Robot # exit decision 3 525*16467b97STreehugger Robot # enterAlt1 526*16467b97STreehugger Robot # location 7 5 527*16467b97STreehugger Robot # look 528*16467b97STreehugger Robot # consumeToken [c/<4>,1:0] 529*16467b97STreehugger Robot # location 7 7 530*16467b97STreehugger Robot # enterSubRule 2 531*16467b97STreehugger Robot # enter decision 2 532*16467b97STreehugger Robot # look 533*16467b97STreehugger Robot # look 534*16467b97STreehugger Robot # recognitionError NoViableAltError 2 1 2 535*16467b97STreehugger Robot # exit decision 2 536*16467b97STreehugger Robot # exitSubRule 2 537*16467b97STreehugger Robot # beginResync 538*16467b97STreehugger Robot # look 539*16467b97STreehugger Robot # consumeToken [c/<4>,1:1] 540*16467b97STreehugger Robot # look 541*16467b97STreehugger Robot # endResync 542*16467b97STreehugger Robot # look(-1) 543*16467b97STreehugger Robot # exitRule b 544*16467b97STreehugger Robot # terminate 545*16467b97STreehugger Robot 546*16467b97STreehugger Robot def recognition_exception( exception ) 547*16467b97STreehugger Robot # do nothing 548*16467b97STreehugger Robot end 549*16467b97STreehugger Robot 550*16467b97STreehugger Robot # Indicates the recognizer is about to consume tokens to resynchronize 551*16467b97STreehugger Robot # the parser. Any consume events from here until the recovered event 552*16467b97STreehugger Robot # are not part of the parse--they are dead tokens. 553*16467b97STreehugger Robot 554*16467b97STreehugger Robot def begin_resync() 555*16467b97STreehugger Robot # do nothing 556*16467b97STreehugger Robot end 557*16467b97STreehugger Robot 558*16467b97STreehugger Robot # Indicates that the recognizer has finished consuming tokens in order 559*16467b97STreehugger Robot # to resychronize. There may be multiple beginResync/endResync pairs 560*16467b97STreehugger Robot # before the recognizer comes out of errorRecovery mode (in which 561*16467b97STreehugger Robot # multiple errors are suppressed). This will be useful 562*16467b97STreehugger Robot # in a gui where you want to probably grey out tokens that are consumed 563*16467b97STreehugger Robot # but not matched to anything in grammar. Anything between 564*16467b97STreehugger Robot # a beginResync/endResync pair was tossed out by the parser. 565*16467b97STreehugger Robot 566*16467b97STreehugger Robot def end_resync() 567*16467b97STreehugger Robot # do nothing 568*16467b97STreehugger Robot end 569*16467b97STreehugger Robot 570*16467b97STreehugger Robot def resync 571*16467b97STreehugger Robot begin_resync 572*16467b97STreehugger Robot yield( self ) 573*16467b97STreehugger Robot end_resync 574*16467b97STreehugger Robot end 575*16467b97STreehugger Robot 576*16467b97STreehugger Robot # A semantic predicate was evaluate with this result and action text 577*16467b97STreehugger Robot 578*16467b97STreehugger Robot def semantic_predicate( result, predicate ) 579*16467b97STreehugger Robot # do nothing 580*16467b97STreehugger Robot end 581*16467b97STreehugger Robot 582*16467b97STreehugger Robot # Announce that parsing has begun. Not technically useful except for 583*16467b97STreehugger Robot # sending events over a socket. A GUI for example will launch a thread 584*16467b97STreehugger Robot # to connect and communicate with a remote parser. The thread will want 585*16467b97STreehugger Robot # to notify the GUI when a connection is made. ANTLR parsers 586*16467b97STreehugger Robot # trigger this upon entry to the first rule (the ruleLevel is used to 587*16467b97STreehugger Robot # figure this out). 588*16467b97STreehugger Robot 589*16467b97STreehugger Robot def commence( ) 590*16467b97STreehugger Robot # do nothing 591*16467b97STreehugger Robot end 592*16467b97STreehugger Robot 593*16467b97STreehugger Robot # Parsing is over; successfully or not. Mostly useful for telling 594*16467b97STreehugger Robot # remote debugging listeners that it's time to quit. When the rule 595*16467b97STreehugger Robot # invocation level goes to zero at the end of a rule, we are done 596*16467b97STreehugger Robot # parsing. 597*16467b97STreehugger Robot 598*16467b97STreehugger Robot def terminate( ) 599*16467b97STreehugger Robot # do nothing 600*16467b97STreehugger Robot end 601*16467b97STreehugger Robot 602*16467b97STreehugger Robot # Input for a tree parser is an AST, but we know nothing for sure 603*16467b97STreehugger Robot # about a node except its type and text (obtained from the adaptor). 604*16467b97STreehugger Robot # This is the analog of the consumeToken method. Again, the ID is 605*16467b97STreehugger Robot # the hashCode usually of the node so it only works if hashCode is 606*16467b97STreehugger Robot # not implemented. If the type is UP or DOWN, then 607*16467b97STreehugger Robot # the ID is not really meaningful as it's fixed--there is 608*16467b97STreehugger Robot # just one UP node and one DOWN navigation node. 609*16467b97STreehugger Robot 610*16467b97STreehugger Robot def consume_node( tree ) 611*16467b97STreehugger Robot # do nothing 612*16467b97STreehugger Robot end 613*16467b97STreehugger Robot 614*16467b97STreehugger Robot # A nil was created (even nil nodes have a unique ID... 615*16467b97STreehugger Robot # they are not "null" per se). As of 4/28/2006, this 616*16467b97STreehugger Robot # seems to be uniquely triggered when starting a new subtree 617*16467b97STreehugger Robot # such as when entering a subrule in automatic mode and when 618*16467b97STreehugger Robot # building a tree in rewrite mode. 619*16467b97STreehugger Robot # If you are receiving this event over a socket via 620*16467b97STreehugger Robot # RemoteDebugEventSocketListener then only tree.ID is set. 621*16467b97STreehugger Robot 622*16467b97STreehugger Robot def flat_node( tree ) 623*16467b97STreehugger Robot # do nothing 624*16467b97STreehugger Robot end 625*16467b97STreehugger Robot 626*16467b97STreehugger Robot # Upon syntax error, recognizers bracket the error with an error node 627*16467b97STreehugger Robot # if they are building ASTs. 628*16467b97STreehugger Robot 629*16467b97STreehugger Robot def error_node( tree ) 630*16467b97STreehugger Robot # do nothing 631*16467b97STreehugger Robot end 632*16467b97STreehugger Robot 633*16467b97STreehugger Robot # Announce a new node built from token elements such as type etc... 634*16467b97STreehugger Robot # If you are receiving this event over a socket via 635*16467b97STreehugger Robot # RemoteDebugEventSocketListener then only tree.ID, type, text are 636*16467b97STreehugger Robot # set. 637*16467b97STreehugger Robot 638*16467b97STreehugger Robot def create_node( node, token = nil ) 639*16467b97STreehugger Robot # do nothing 640*16467b97STreehugger Robot end 641*16467b97STreehugger Robot 642*16467b97STreehugger Robot # Make a node the new root of an existing root. 643*16467b97STreehugger Robot # Note: the newRootID parameter is possibly different 644*16467b97STreehugger Robot # than the TreeAdaptor.becomeRoot() newRoot parameter. 645*16467b97STreehugger Robot # In our case, it will always be the result of calling 646*16467b97STreehugger Robot # TreeAdaptor.becomeRoot() and not root_n or whatever. 647*16467b97STreehugger Robot # The listener should assume that this event occurs 648*16467b97STreehugger Robot # only when the current subrule (or rule) subtree is 649*16467b97STreehugger Robot # being reset to newRootID. 650*16467b97STreehugger Robot # If you are receiving this event over a socket via 651*16467b97STreehugger Robot # RemoteDebugEventSocketListener then only IDs are set. 652*16467b97STreehugger Robot # @see antlr3.tree.TreeAdaptor.becomeRoot() 653*16467b97STreehugger Robot 654*16467b97STreehugger Robot def become_root( new_root, old_root ) 655*16467b97STreehugger Robot # do nothing 656*16467b97STreehugger Robot end 657*16467b97STreehugger Robot 658*16467b97STreehugger Robot # Make childID a child of rootID. 659*16467b97STreehugger Robot # If you are receiving this event over a socket via 660*16467b97STreehugger Robot # RemoteDebugEventSocketListener then only IDs are set. 661*16467b97STreehugger Robot # @see antlr3.tree.TreeAdaptor.addChild() 662*16467b97STreehugger Robot 663*16467b97STreehugger Robot def add_child( root, child ) 664*16467b97STreehugger Robot # do nothing 665*16467b97STreehugger Robot end 666*16467b97STreehugger Robot 667*16467b97STreehugger Robot # Set the token start/stop token index for a subtree root or node. 668*16467b97STreehugger Robot # If you are receiving this event over a socket via 669*16467b97STreehugger Robot # RemoteDebugEventSocketListener then only tree.ID is set. 670*16467b97STreehugger Robot 671*16467b97STreehugger Robot def set_token_boundaries( tree, token_start_index, token_stop_index ) 672*16467b97STreehugger Robot # do nothing 673*16467b97STreehugger Robot end 674*16467b97STreehugger Robot 675*16467b97STreehugger Robot def examine_rule_memoization( rule ) 676*16467b97STreehugger Robot # do nothing 677*16467b97STreehugger Robot end 678*16467b97STreehugger Robot 679*16467b97STreehugger Robot def on( event_name, &block ) 680*16467b97STreehugger Robot sclass = class << self; self; end 681*16467b97STreehugger Robot sclass.send( :define_method, event_name, &block ) 682*16467b97STreehugger Robot end 683*16467b97STreehugger Robot 684*16467b97STreehugger Robot EVENTS = [ 685*16467b97STreehugger Robot :add_child, :backtrack, :become_root, :begin_backtrack, 686*16467b97STreehugger Robot :begin_resync, :commence, :consume_hidden_token, 687*16467b97STreehugger Robot :consume_node, :consume_token, :create_node, :end_backtrack, 688*16467b97STreehugger Robot :end_resync, :enter_alternative, :enter_decision, :enter_rule, 689*16467b97STreehugger Robot :enter_sub_rule, :error_node, :exit_decision, :exit_rule, 690*16467b97STreehugger Robot :exit_sub_rule, :flat_node, :location, :look, :mark, 691*16467b97STreehugger Robot :recognition_exception, :resync, :rewind, 692*16467b97STreehugger Robot :semantic_predicate, :set_token_boundaries, :terminate 693*16467b97STreehugger Robot ].freeze 694*16467b97STreehugger Robot 695*16467b97STreehugger Robotend 696*16467b97STreehugger Robotend 697*16467b97STreehugger Robotend 698