1 #!/usr/bin/ruby 2 # encoding: utf-8 3 4 require 'antlr3' 5 require 'fileutils' 6 require 'antlr3/test/functional' 7 #require 'antlr3/test/diff' 8 9 class ANTLRDebugger < Thread 10 self.abort_on_exception = true 11 attr_accessor :events, :success, :port 12 include Timeout 13 14 def initialize( port ) 15 @events = [] 16 @success = false 17 @port = port 18 19 super do 20 timeout( 2 ) do 21 begin 22 @socket = TCPSocket.open( 'localhost', @port ) 23 #Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0) 24 #@socket.connect( Socket.pack_sockaddr_in(@port, '127.0.0.1') ) 25 rescue Errno::ECONNREFUSED => error 26 if $VERBOSE 27 $stderr.printf( 28 "%s:%s received connection refuse error: %p\n", 29 __FILE__, __LINE__, error 30 ) 31 $stderr.puts( "sleeping for 0.1 seconds before retrying" ) 32 end 33 sleep( 0.01 ) 34 retry 35 end 36 end 37 38 @socket.readline.strip.should == 'ANTLR 2' 39 @socket.readline.strip.start_with?( 'grammar "' ).should == true 40 ack 41 loop do 42 event = @socket.readline.strip 43 @events << event.split( "\t" ) 44 ack 45 break if event == 'terminate' 46 end 47 48 @socket.close 49 @success = true 50 end 51 52 end 53 54 def ack 55 @socket.write( "ACK\n" ) 56 @socket.flush 57 end 58 59 end # ANTLRDebugger 60 61 class TestDebugGrammars < ANTLR3::Test::Functional 62 compile_options :debug => true 63 64 #include ANTLR3::Test::Diff 65 66 def parse( grammar, rule, input, options = {} ) 67 @grammar = inline_grammar( grammar ) 68 @grammar.compile( self.class.compile_options ) 69 @grammar_path = File.expand_path( @grammar.path ) 70 for output_file in @grammar.target_files 71 self.class.import( output_file ) 72 end 73 grammar_module = self.class.const_get( @grammar.name ) 74 listener = options[ :listener ] or debugger = ANTLRDebugger.new( port = 49100 ) 75 76 begin 77 lexer = grammar_module::Lexer.new( input ) 78 tokens = ANTLR3::CommonTokenStream.new( lexer ) 79 options[ :debug_listener ] = listener 80 parser = grammar_module::Parser.new( tokens, options ) 81 parser.send( rule ) 82 ensure 83 if listener.nil? 84 debugger.join 85 return( debugger ) 86 end 87 end 88 end 89 90 example 'basic debug-mode parser using a RecordEventListener' do 91 grammar = %q< 92 grammar BasicParser; // line 1 93 options {language=Ruby;} // line 2 94 a : ID EOF; // line 3 95 ID : 'a'..'z'+ ; // line 4 96 WS : (' '|'\n') {$channel=HIDDEN;} ; 97 > 98 listener = ANTLR3::Debug::RecordEventListener.new 99 parse( grammar, :a, 'a', :listener => listener ) 100 lt_events, found = listener.events.partition { |event| event.start_with?( "(look): " ) } 101 lt_events.should_not be_empty 102 103 expected = [ "(enter_rule): rule=a", 104 "(location): line=3 position=1", 105 "(enter_alternative): number=1", 106 "(location): line=3 position=5", 107 "(location): line=3 position=8", 108 "(location): line=3 position=11", 109 "(exit_rule): rule=a" ] 110 found.should == expected 111 end 112 113 example 'debug-mode parser using a socket proxy to transmit events' do 114 grammar = %q< 115 grammar SocketProxy; // line 1 116 options {language=Ruby;} // line 2 117 a : ID EOF; // line 3 118 ID : 'a'..'z'+ ; // line 4 119 WS : (' '|'\n') {$channel=HIDDEN;} ; 120 > 121 debugger = parse( grammar, :a, 'a' ) 122 debugger.success.should be_true 123 expected = [ 124 [ 'enter_rule', @grammar_path, 'a' ], 125 [ 'location', '3', '1' ], 126 [ 'enter_alternative', '1' ], 127 [ 'location', '3', '5' ], 128 [ 'look', '1', '0', '4', 'default', '1', '0', '"a"' ], 129 [ 'look', '1', '0', '4', 'default', '1', '0', '"a"' ], 130 [ 'consume_token', '0', '4', 'default', '1', '0', '"a"' ], 131 [ 'location', '3', '8' ], 132 [ 'look', '1', '-1', '-1', 'default', '0', '-1', 'nil' ], 133 [ 'look', '1', '-1', '-1', 'default', '0', '-1', 'nil' ], 134 [ 'consume_token', '-1', '-1', 'default', '0', '-1', 'nil' ], 135 [ 'location', '3', '11' ], 136 [ 'exit_rule', @grammar_path, 'a' ], 137 [ 'terminate' ] 138 ] 139 140 debugger.events.should == expected 141 end 142 143 example 'debug-mode parser events triggered by recognition errors' do 144 grammar = %q< 145 grammar RecognitionError; 146 options { language=Ruby; } 147 a : ID EOF; 148 ID : 'a'..'z'+ ; 149 WS : (' '|'\n') {$channel=HIDDEN;} ; 150 > 151 debugger = parse( grammar, :a, "a b" ) 152 debugger.success.should be_true 153 154 expected = [ 155 [ "enter_rule", @grammar_path, "a" ], 156 [ "location", "3", "1" ], 157 [ "enter_alternative", "1" ], 158 [ "location", "3", "5" ], 159 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 160 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 161 [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ], 162 [ "consume_hidden_token", "1", "5", "hidden", "1", "1", '" "' ], 163 [ "location", "3", "8" ], 164 [ "look", "1", "2", "4", "default", "1", "2", "\"b\"" ], 165 [ "look", "1", "2", "4", "default", "1", "2", "\"b\"" ], 166 [ "look", "2", "-1", "-1", "default", "0", "-1", "nil" ], 167 [ "look", "1", "2", "4", "default", "1", "2", "\"b\"" ], 168 [ "begin_resync" ], 169 [ "consume_token", "2", "4", "default", "1", "2", "\"b\"" ], 170 [ "end_resync" ], 171 [ "recognition_exception", "ANTLR3::Error::UnwantedToken", "2", "1", "2" ], 172 [ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ], 173 [ "location", "3", "11" ], 174 [ "exit_rule", @grammar_path, "a" ], 175 [ "terminate" ] 176 ] 177 debugger.events.should == expected 178 end 179 180 example 'debug-mode parser events triggered by semantic predicate evaluation' do 181 grammar = %q< 182 grammar SemPred; 183 options { language=Ruby; } 184 a : {true}? ID EOF; 185 ID : 'a'..'z'+ ; 186 WS : (' '|'\n') {$channel=HIDDEN;} ; 187 > 188 189 debugger = parse( grammar, :a, "a" ) 190 debugger.success.should be_true 191 192 expected = [ 193 [ "enter_rule", @grammar_path, "a" ], 194 [ "location", "3", "1" ], 195 [ "enter_alternative", "1" ], 196 [ "location", "3", "5" ], 197 [ "semantic_predicate", "true", '"true"' ], 198 [ "location", "3", "13" ], 199 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 200 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 201 [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ], 202 [ "location", "3", "16" ], 203 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 204 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 205 [ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ], 206 [ "location", "3", "19" ], 207 [ "exit_rule", @grammar_path, "a" ], 208 [ "terminate" ] 209 ] 210 debugger.events.should == expected 211 end 212 213 example 'debug-mode parser events triggered by recognizing a (...)+ block' do 214 grammar = %q< 215 grammar PositiveClosureBlock; 216 options { language=Ruby; } 217 a : ID ( ID | INT )+ EOF; 218 ID : 'a'..'z'+ ; 219 INT : '0'..'9'+ ; 220 WS : (' '|'\n') {$channel=HIDDEN;} ; 221 > 222 223 debugger = parse( grammar, :a, "a 1 b c 3" ) 224 debugger.success.should be_true 225 226 expected = [ 227 [ "enter_rule", @grammar_path, "a" ], 228 [ "location", "3", "1" ], 229 [ "enter_alternative", "1" ], 230 [ "location", "3", "5" ], 231 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 232 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 233 [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ], 234 [ "consume_hidden_token", "1", "6", "hidden", "1", "1", '" "' ], 235 [ "location", "3", "8" ], 236 [ "enter_subrule", "1" ], 237 [ "enter_decision", "1" ], 238 [ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ], 239 [ "exit_decision", "1" ], 240 [ "enter_alternative", "1" ], 241 [ "location", "3", "8" ], 242 [ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ], 243 [ "consume_token", "2", "5", "default", "1", "2", "\"1\"" ], 244 [ "consume_hidden_token", "3", "6", "hidden", "1", "3", '" "' ], 245 [ "enter_decision", "1" ], 246 [ "look", "1", "4", "4", "default", "1", "4", "\"b\"" ], 247 [ "exit_decision", "1" ], 248 [ "enter_alternative", "1" ], 249 [ "location", "3", "8" ], 250 [ "look", "1", "4", "4", "default", "1", "4", "\"b\"" ], 251 [ "consume_token", "4", "4", "default", "1", "4", "\"b\"" ], 252 [ "consume_hidden_token", "5", "6", "hidden", "1", "5", '" "' ], 253 [ "enter_decision", "1" ], 254 [ "look", "1", "6", "4", "default", "1", "6", "\"c\"" ], 255 [ "exit_decision", "1" ], 256 [ "enter_alternative", "1" ], 257 [ "location", "3", "8" ], 258 [ "look", "1", "6", "4", "default", "1", "6", "\"c\"" ], 259 [ "consume_token", "6", "4", "default", "1", "6", "\"c\"" ], 260 [ "consume_hidden_token", "7", "6", "hidden", "1", "7", '" "' ], 261 [ "enter_decision", "1" ], 262 [ "look", "1", "8", "5", "default", "1", "8", "\"3\"" ], 263 [ "exit_decision", "1" ], 264 [ "enter_alternative", "1" ], 265 [ "location", "3", "8" ], 266 [ "look", "1", "8", "5", "default", "1", "8", "\"3\"" ], 267 [ "consume_token", "8", "5", "default", "1", "8", "\"3\"" ], 268 [ "enter_decision", "1" ], 269 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 270 [ "exit_decision", "1" ], 271 [ "exit_subrule", "1" ], 272 [ "location", "3", "22" ], 273 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 274 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 275 [ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ], 276 [ "location", "3", "25" ], 277 [ "exit_rule", @grammar_path, "a" ], 278 [ "terminate" ] 279 ] 280 281 debugger.events.should == expected 282 end 283 284 example 'debug-mode parser events triggered by recognizing a (...)* block' do 285 grammar = %q< 286 grammar ClosureBlock; 287 options { language=Ruby; } 288 a : ID ( ID | INT )* EOF; 289 ID : 'a'..'z'+ ; 290 INT : '0'..'9'+ ; 291 WS : (' '|'\n') {$channel=HIDDEN;} ; 292 > 293 294 debugger = parse( grammar, :a, "a 1 b c 3" ) 295 debugger.success.should be_true 296 297 expected = [ 298 [ "enter_rule", @grammar_path, "a" ], 299 [ "location", "3", "1" ], 300 [ "enter_alternative", "1" ], 301 [ "location", "3", "5" ], 302 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 303 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 304 [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ], 305 [ "consume_hidden_token", "1", "6", "hidden", "1", "1", '" "' ], 306 [ "location", "3", "8" ], 307 [ "enter_subrule", "1" ], 308 [ "enter_decision", "1" ], 309 [ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ], 310 [ "exit_decision", "1" ], 311 [ "enter_alternative", "1" ], 312 [ "location", "3", "8" ], 313 [ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ], 314 [ "consume_token", "2", "5", "default", "1", "2", "\"1\"" ], 315 [ "consume_hidden_token", "3", "6", "hidden", "1", "3", '" "' ], 316 [ "enter_decision", "1" ], 317 [ "look", "1", "4", "4", "default", "1", "4", "\"b\"" ], 318 [ "exit_decision", "1" ], 319 [ "enter_alternative", "1" ], 320 [ "location", "3", "8" ], 321 [ "look", "1", "4", "4", "default", "1", "4", "\"b\"" ], 322 [ "consume_token", "4", "4", "default", "1", "4", "\"b\"" ], 323 [ "consume_hidden_token", "5", "6", "hidden", "1", "5", '" "' ], 324 [ "enter_decision", "1" ], 325 [ "look", "1", "6", "4", "default", "1", "6", "\"c\"" ], 326 [ "exit_decision", "1" ], 327 [ "enter_alternative", "1" ], 328 [ "location", "3", "8" ], 329 [ "look", "1", "6", "4", "default", "1", "6", "\"c\"" ], 330 [ "consume_token", "6", "4", "default", "1", "6", "\"c\"" ], 331 [ "consume_hidden_token", "7", "6", "hidden", "1", "7", '" "' ], 332 [ "enter_decision", "1" ], 333 [ "look", "1", "8", "5", "default", "1", "8", "\"3\"" ], 334 [ "exit_decision", "1" ], 335 [ "enter_alternative", "1" ], 336 [ "location", "3", "8" ], 337 [ "look", "1", "8", "5", "default", "1", "8", "\"3\"" ], 338 [ "consume_token", "8", "5", "default", "1", "8", "\"3\"" ], 339 [ "enter_decision", "1" ], 340 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 341 [ "exit_decision", "1" ], 342 [ "exit_subrule", "1" ], 343 [ "location", "3", "22" ], 344 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 345 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 346 [ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ], 347 [ "location", "3", "25" ], 348 [ "exit_rule", @grammar_path, "a" ], 349 [ "terminate" ] 350 ] 351 debugger.events.should == expected 352 end 353 354 example 'debug-mode parser events triggered by a mismatched set error' do 355 grammar = %q< 356 grammar MismatchedSetError; 357 options { language=Ruby; } 358 a : ID ( ID | INT ) EOF; 359 ID : 'a'..'z'+ ; 360 INT : '0'..'9'+ ; 361 WS : (' '|'\n') {$channel=HIDDEN;} ; 362 > 363 364 debugger = parse( grammar, :a, "a" ) 365 debugger.success.should be_true 366 367 expected = [ 368 [ "enter_rule", @grammar_path, "a" ], 369 [ "location", "3", "1" ], 370 [ "enter_alternative", "1" ], 371 [ "location", "3", "5" ], 372 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 373 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 374 [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ], 375 [ "location", "3", "8" ], 376 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 377 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 378 [ "recognition_exception", "ANTLR3::Error::MismatchedSet", "1", "0", "-1" ], 379 [ "recognition_exception", "ANTLR3::Error::MismatchedSet", "1", "0", "-1" ], 380 [ "begin_resync" ], 381 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 382 [ "end_resync" ], 383 [ "location", "3", "24" ], 384 [ "exit_rule", @grammar_path, "a" ], 385 [ "terminate" ] 386 ] 387 388 debugger.events.should == expected 389 end 390 391 example 'debug-mode parser block-location events for subrules' do 392 grammar = %q< 393 grammar Block; 394 options { language=Ruby; } 395 a : ID ( b | c ) EOF; 396 b : ID; 397 c : INT; 398 ID : 'a'..'z'+ ; 399 INT : '0'..'9'+ ; 400 WS : (' '|'\n') {$channel=HIDDEN;} ; 401 > 402 403 debugger = parse( grammar, :a, "a 1" ) 404 debugger.success.should be_true 405 406 expected = [ 407 [ "enter_rule", @grammar_path, "a" ], 408 [ "location", "3", "1" ], 409 [ "enter_alternative", "1" ], 410 [ "location", "3", "5" ], 411 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 412 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 413 [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ], 414 [ "consume_hidden_token", "1", "6", "hidden", "1", "1", '" "' ], 415 [ "location", "3", "8" ], 416 [ "enter_subrule", "1" ], 417 [ "enter_decision", "1" ], 418 [ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ], 419 [ "exit_decision", "1" ], 420 [ "enter_alternative", "2" ], 421 [ "location", "3", "14" ], 422 [ "enter_rule", @grammar_path, "c" ], 423 [ "location", "5", "1" ], 424 [ "enter_alternative", "1" ], 425 [ "location", "5", "5" ], 426 [ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ], 427 [ "look", "1", "2", "5", "default", "1", "2", "\"1\"" ], 428 [ "consume_token", "2", "5", "default", "1", "2", "\"1\"" ], 429 [ "location", "5", "8" ], 430 [ "exit_rule", @grammar_path, "c" ], 431 [ "exit_subrule", "1" ], 432 [ "location", "3", "18" ], 433 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 434 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 435 [ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ], 436 [ "location", "3", "21" ], 437 [ "exit_rule", @grammar_path, "a" ], 438 [ "terminate" ] 439 ] 440 debugger.events.should == expected 441 end 442 443 example 'debug-mode parser events triggered by a no viable alternative error' do 444 grammar = %q< 445 grammar NoViableAlt; 446 options { language=Ruby; } 447 a : ID ( b | c ) EOF; 448 b : ID; 449 c : INT; 450 ID : 'a'..'z'+ ; 451 INT : '0'..'9'+ ; 452 BANG : '!' ; 453 WS : (' '|'\n') {$channel=HIDDEN;} ; 454 > 455 456 debugger = parse( grammar, :a, "a !" ) 457 debugger.success.should be_true 458 459 expected = [ 460 [ "enter_rule", @grammar_path, "a" ], 461 [ "location", "3", "1" ], 462 [ "enter_alternative", "1" ], 463 [ "location", "3", "5" ], 464 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 465 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 466 [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ], 467 [ "consume_hidden_token", "1", "7", "hidden", "1", "1", '" "' ], 468 [ "location", "3", "8" ], 469 [ "enter_subrule", "1" ], 470 [ "enter_decision", "1" ], 471 [ "look", "1", "2", "6", "default", "1", "2", "\"!\"" ], 472 [ "look", "1", "2", "6", "default", "1", "2", "\"!\"" ], 473 [ "recognition_exception", "ANTLR3::Error::NoViableAlternative", "2", "1", "2" ], 474 [ "exit_decision", "1" ], 475 [ "exit_subrule", "1" ], 476 [ "recognition_exception", "ANTLR3::Error::NoViableAlternative", "2", "1", "2" ], 477 [ "begin_resync" ], 478 [ "look", "1", "2", "6", "default", "1", "2", "\"!\"" ], 479 [ "consume_token", "2", "6", "default", "1", "2", "\"!\"" ], 480 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 481 [ "end_resync" ], 482 [ "location", "3", "21" ], 483 [ "exit_rule", @grammar_path, "a" ], 484 [ "terminate" ] 485 ] 486 debugger.events.should == expected 487 end 488 489 example 'debug-mode parser block-location events triggered by rules' do 490 grammar = %q< 491 grammar RuleBlock; 492 options { language=Ruby; } 493 a : b | c; 494 b : ID; 495 c : INT; 496 ID : 'a'..'z'+ ; 497 INT : '0'..'9'+ ; 498 WS : (' '|'\n') {$channel=HIDDEN;} ; 499 > 500 501 debugger = parse( grammar, :a, "1" ) 502 debugger.success.should be_true 503 504 expected = [ 505 [ "enter_rule", @grammar_path, "a" ], 506 [ "location", "3", "1" ], 507 [ "enter_decision", "1" ], 508 [ "look", "1", "0", "5", "default", "1", "0", "\"1\"" ], 509 [ "exit_decision", "1" ], 510 [ "enter_alternative", "2" ], 511 [ "location", "3", "9" ], 512 [ "enter_rule", @grammar_path, "c" ], 513 [ "location", "5", "1" ], 514 [ "enter_alternative", "1" ], 515 [ "location", "5", "5" ], 516 [ "look", "1", "0", "5", "default", "1", "0", "\"1\"" ], 517 [ "look", "1", "0", "5", "default", "1", "0", "\"1\"" ], 518 [ "consume_token", "0", "5", "default", "1", "0", "\"1\"" ], 519 [ "location", "5", "8" ], 520 [ "exit_rule", @grammar_path, "c" ], 521 [ "location", "3", "10" ], 522 [ "exit_rule", @grammar_path, "a" ], 523 [ "terminate" ] 524 ] 525 526 debugger.events.should == expected 527 end 528 529 example 'debug-mode parser block-location events triggered by single-alternative rules' do 530 grammar = %q< 531 grammar RuleBlockSingleAlt; 532 options { language=Ruby; } 533 a : b; 534 b : ID; 535 ID : 'a'..'z'+ ; 536 INT : '0'..'9'+ ; 537 WS : (' '|'\n') {$channel=HIDDEN;} ; 538 > 539 540 debugger = parse( grammar, :a, "a" ) 541 debugger.success.should be_true 542 543 expected = [ 544 [ "enter_rule", @grammar_path, "a" ], 545 [ "location", "3", "1" ], 546 [ "enter_alternative", "1" ], 547 [ "location", "3", "5" ], 548 [ "enter_rule", @grammar_path, "b" ], 549 [ "location", "4", "1" ], 550 [ "enter_alternative", "1" ], 551 [ "location", "4", "5" ], 552 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 553 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 554 [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ], 555 [ "location", "4", "7" ], 556 [ "exit_rule", @grammar_path, "b" ], 557 [ "location", "3", "6" ], 558 [ "exit_rule", @grammar_path, "a" ], 559 [ "terminate" ] 560 ] 561 562 debugger.events.should == expected 563 end 564 565 example 'debug-mode parser block-location events triggered by single-alternative subrules' do 566 grammar = %q< 567 grammar BlockSingleAlt; 568 options { language=Ruby; } 569 a : ( b ); 570 b : ID; 571 ID : 'a'..'z'+ ; 572 INT : '0'..'9'+ ; 573 WS : (' '|'\n') {$channel=HIDDEN;} ; 574 > 575 576 debugger = parse( grammar, :a, "a" ) 577 debugger.success.should be_true 578 579 expected = [ 580 [ "enter_rule", @grammar_path, "a" ], 581 [ "location", "3", "1" ], 582 [ "enter_alternative", "1" ], 583 [ "location", "3", "5" ], 584 [ "enter_alternative", "1" ], 585 [ "location", "3", "7" ], 586 [ "enter_rule", @grammar_path, "b" ], 587 [ "location", "4", "1" ], 588 [ "enter_alternative", "1" ], 589 [ "location", "4", "5" ], 590 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 591 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 592 [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ], 593 [ "location", "4", "7" ], 594 [ "exit_rule", @grammar_path, "b" ], 595 [ "location", "3", "10" ], 596 [ "exit_rule", @grammar_path, "a" ], 597 [ "terminate" ] 598 ] 599 debugger.events.should == expected 600 end 601 602 example 'debug-mode parser block-location events triggered by invoking a cyclic DFA for prediction' do 603 grammar = %q< 604 grammar DFA; 605 options { language=Ruby; } 606 a : ( b | c ) EOF; 607 b : ID* INT; 608 c : ID+ BANG; 609 ID : 'a'..'z'+ ; 610 INT : '0'..'9'+ ; 611 BANG : '!'; 612 WS : (' '|'\n') {$channel=HIDDEN;} ; 613 > 614 615 debugger = parse( grammar, :a, "a!" ) 616 debugger.success.should be_true 617 618 expected = [ 619 [ "enter_rule", @grammar_path, "a" ], 620 [ "location", "3", "1" ], 621 [ "enter_alternative", "1" ], 622 [ "location", "3", "5" ], 623 [ "enter_subrule", "1" ], 624 [ "enter_decision", "1" ], 625 [ "mark", "0" ], 626 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 627 [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ], 628 [ "look", "1", "1", "6", "default", "1", "1", "\"!\"" ], 629 [ "consume_token", "1", "6", "default", "1", "1", "\"!\"" ], 630 [ "rewind", "0" ], 631 [ "exit_decision", "1" ], 632 [ "enter_alternative", "2" ], 633 [ "location", "3", "11" ], 634 [ "enter_rule", @grammar_path, "c" ], 635 [ "location", "5", "1" ], 636 [ "enter_alternative", "1" ], 637 [ "location", "5", "5" ], 638 [ "enter_subrule", "3" ], 639 [ "enter_decision", "3" ], 640 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 641 [ "exit_decision", "3" ], 642 [ "enter_alternative", "1" ], 643 [ "location", "5", "5" ], 644 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 645 [ "look", "1", "0", "4", "default", "1", "0", "\"a\"" ], 646 [ "consume_token", "0", "4", "default", "1", "0", "\"a\"" ], 647 [ "enter_decision", "3" ], 648 [ "look", "1", "1", "6", "default", "1", "1", "\"!\"" ], 649 [ "exit_decision", "3" ], 650 [ "exit_subrule", "3" ], 651 [ "location", "5", "9" ], 652 [ "look", "1", "1", "6", "default", "1", "1", "\"!\"" ], 653 [ "look", "1", "1", "6", "default", "1", "1", "\"!\"" ], 654 [ "consume_token", "1", "6", "default", "1", "1", "\"!\"" ], 655 [ "location", "5", "13" ], 656 [ "exit_rule", @grammar_path, "c" ], 657 [ "exit_subrule", "1" ], 658 [ "location", "3", "15" ], 659 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 660 [ "look", "1", "-1", "-1", "default", "0", "-1", "nil" ], 661 [ "consume_token", "-1", "-1", "default", "0", "-1", "nil" ], 662 [ "location", "3", "18" ], 663 [ "exit_rule", @grammar_path, "a" ], 664 [ "terminate" ] 665 ] 666 debugger.events.should == expected 667 end 668 669 example 'debug-mode AST-building parser events' do 670 grammar = %q/ 671 grammar BasicAST; 672 options { 673 language=Ruby; 674 output=AST; 675 } 676 a : ( b | c ) EOF!; 677 b : ID* INT -> ^(INT ID*); 678 c : ID+ BANG -> ^(BANG ID+); 679 ID : 'a'..'z'+ ; 680 INT : '0'..'9'+ ; 681 BANG : '!'; 682 WS : (' '|'\n') {$channel=HIDDEN;} ; 683 / 684 listener = ANTLR3::Debug::RecordEventListener.new 685 parse( grammar, :a, "a!", :listener => listener ) 686 end 687 688 end 689