or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

character-streams.mddebug-support.mderror-handling.mdindex.mdlexical-analysis.mdparsing.mdtoken-streams.mdtree-construction.md

debug-support.mddocs/

0

# Debug Support

1

2

Debugging, profiling, and tracing tools for parser development and optimization. The debug package provides comprehensive instrumentation for understanding parser behavior and performance characteristics.

3

4

## Capabilities

5

6

### Debug Event Listener

7

8

Interface for receiving detailed parsing events during execution.

9

10

```java { .api }

11

/**

12

* Interface for debug event handling

13

*/

14

public interface DebugEventListener {

15

/** The parser has just entered rule ruleName */

16

public void enterRule(String grammarFileName, String ruleName);

17

18

/** Because rules can have lots of alternatives, we need an event for each.

19

* The default implementation does nothing. The decision number is the decision

20

* in the DFA for the decision state.

21

*/

22

public void enterAlt(int alt);

23

24

/** The parser has just exited rule ruleName */

25

public void exitRule(String grammarFileName, String ruleName);

26

27

/** The parser has just entered a subrule in the parser such as

28

* the () subrule.

29

*/

30

public void enterSubRule(int decisionNumber);

31

32

/** The parser has just exited a subrule in the parser such as

33

* the () subrule.

34

*/

35

public void exitSubRule(int decisionNumber);

36

37

/** A decision was made about which alt to enter. */

38

public void enterDecision(int decisionNumber, boolean couldBacktrack);

39

40

/** We are done deciding which alt to enter. */

41

public void exitDecision(int decisionNumber);

42

43

/** The parser consumed a token; tell me which one and by which rule

44

* that token matched or what rule invoked nextToken. This is perfect

45

* place to count consumed input or to build trees.

46

*/

47

public void consumeToken(Token token);

48

49

/** Track the progress of consuming tokens during error recovery.

50

* This is useful to highlight the input during debugging and

51

* in error messages.

52

*/

53

public void consumeHiddenToken(Token token);

54

55

/** Input stream is requesting a look ahead the k-th token.

56

* k==1 is the current token. k==0 is invalid.

57

* This event is fired before the next token is actually

58

* computed so you can see in the debugger what could happen

59

* next. This is not an indication that the token will be

60

* consumed next.

61

*/

62

public void LT(int i, Token t);

63

64

/** Announce that the parser has created a nil node */

65

public void nilNode(Object t);

66

67

/** Announce that the parser has created an error node in the tree

68

* such as when you find input that does not match the input expected

69

* via the grammar.

70

*/

71

public void errorNode(Object t);

72

73

/** Announce that the parser has just created node t for rule r. */

74

public void createNode(Object t, Token token);

75

76

/** Announce that the parser has just altered the tree -- usually by

77

* making rule node t the new root of old root r.

78

*/

79

public void createNode(Object t, int tokenType, String text);

80

81

/** Announce that the parser has just altered the tree -- usually by

82

* making rule node t the new root of old root r.

83

*/

84

public void becomeRoot(Object newRoot, Object oldRoot);

85

86

/** Announce that the parser has just added child t as a child of root r. */

87

public void addChild(Object root, Object child);

88

89

/** The parser has set the token boundaries for tree node t from

90

* tokens with indexes start..stop.

91

*/

92

public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex);

93

94

/** Alter the type of tree node t to tokenType */

95

public void setType(Object node, int tokenType);

96

97

/** Alter the text of tree node t to tokenText */

98

public void setText(Object node, String tokenText);

99

100

/** We are done parsing; successfully or not. Track time and tell

101

* listeners we are done.

102

*/

103

public void terminate();

104

}

105

```

106

107

### Debug Parser

108

109

Parser wrapper that generates debug events during parsing.

110

111

```java { .api }

112

/**

113

* Parser with debugging capabilities

114

*/

115

public class DebugParser extends Parser {

116

/** Who to notify when events in the parser occur. */

117

protected DebugEventListener dbg = null;

118

119

/** Used to differentiate between fixed lookahead and cyclic DFA decisions

120

* while profiling.

121

*/

122

public boolean isCyclicDecision = false;

123

124

public DebugParser(TokenStream input, DebugEventListener dbg, RecognizerSharedState state);

125

public DebugParser(TokenStream input, RecognizerSharedState state);

126

public DebugParser(TokenStream input, DebugEventListener dbg);

127

128

/** Provide a new debug event listener for this parser. Notify the

129

* input stream too that it should send events to this listener.

130

*/

131

public void setDebugListener(DebugEventListener dbg);

132

133

public List<String> getRuleInvocationStack();

134

135

public void reportError(IOException e);

136

public void reportError(RecognitionException e);

137

138

public void beginResync();

139

public void endResync();

140

141

public void beginBacktrack(int level);

142

public void endBacktrack(int level, boolean successful);

143

}

144

```

145

146

**Usage Examples:**

147

148

```java

149

import org.antlr.runtime.debug.*;

150

import org.antlr.runtime.*;

151

152

// Create debug parser with custom listener

153

MyLexer lexer = new MyLexer(new ANTLRStringStream("x = 42;"));

154

DebugTokenStream tokens = new DebugTokenStream(new CommonTokenStream(lexer), null);

155

DebugEventListener listener = new TraceDebugEventListener();

156

DebugParser parser = new DebugParser(tokens, listener);

157

158

// Set up debugging

159

parser.setDebugListener(listener);

160

tokens.setDebugListener(listener);

161

162

// Parse with debugging enabled

163

try {

164

parser.program();

165

} catch (RecognitionException e) {

166

System.err.println("Parse failed: " + e.getMessage());

167

}

168

```

169

170

### Debug Token Stream

171

172

Token stream wrapper that generates debug events for token access.

173

174

```java { .api }

175

/**

176

* Token stream with debugging support

177

*/

178

public class DebugTokenStream implements TokenStream {

179

protected DebugEventListener dbg;

180

protected TokenStream input;

181

protected int lastMarker;

182

183

public DebugTokenStream(TokenStream input, DebugEventListener dbg);

184

185

public void setDebugListener(DebugEventListener dbg);

186

187

public void consume();

188

public Token get(int i);

189

public Token LT(int k);

190

public int mark();

191

public int index();

192

public void rewind(int marker);

193

public void rewind();

194

public void release(int marker);

195

public void seek(int index);

196

public int size();

197

public TokenSource getTokenSource();

198

public String getSourceName();

199

public String toString(int start, int stop);

200

public String toString(Token start, Token stop);

201

public String toString();

202

203

// Delegate to wrapped stream

204

public int LA(int i);

205

public int range();

206

}

207

```

208

209

**Usage Examples:**

210

211

```java

212

// Debug token stream with custom listener

213

CommonTokenStream baseStream = new CommonTokenStream(lexer);

214

DebugEventListener listener = new MyDebugListener();

215

DebugTokenStream debugStream = new DebugTokenStream(baseStream, listener);

216

217

// Token access generates debug events

218

Token token = debugStream.LT(1); // Fires LT event

219

debugStream.consume(); // Fires consumeToken event

220

221

// Use with debug parser

222

DebugParser parser = new DebugParser(debugStream, listener);

223

```

224

225

### Profiler

226

227

Performance profiler for analyzing parser efficiency and bottlenecks.

228

229

```java { .api }

230

/**

231

* Performance profiling for parsing

232

*/

233

public class Profiler extends BlankDebugEventListener {

234

public static final String DATA_SEP = "\t";

235

public static final String newline = System.getProperty("line.separator");

236

237

/** Because I may change the stats, I need to track that for later

238

* computations to be consistent.

239

*/

240

public static final String Version = "2";

241

public static final String RUNTIME_STATS_FILENAME = "runtime.stats";

242

243

protected Stats stats;

244

245

// all about a specific decision

246

public static class DecisionDescriptor {

247

public String fileName;

248

public String ruleName;

249

public int decision;

250

public int maxk;

251

public boolean couldBacktrack;

252

public boolean cyclic;

253

public boolean greedy;

254

public boolean blockLevel;

255

public boolean isFixed;

256

public int numAlts;

257

258

public String toString();

259

}

260

261

// Profile stats for decisions

262

public static class ProfileStats {

263

public String Version;

264

public String name;

265

public int numRuleInvocations;

266

public int numGuessedEarlyExits;

267

public int numMemoizationCacheMisses;

268

public int numMemoizationCacheHits;

269

public int numBacktrackOccurrences;

270

public List<DecisionEvent> events;

271

public List<DecisionDescriptor> decisions;

272

273

public String toString();

274

public String toNotifyString();

275

}

276

277

public Profiler();

278

public Profiler(Parser parser);

279

280

public void terminate();

281

public void enterDecision(int decisionNumber, boolean couldBacktrack);

282

public void exitDecision(int decisionNumber);

283

public void consumeToken(Token token);

284

public void consumeHiddenToken(Token token);

285

public void nextToken(Token t);

286

public void memoize(IntStream input, int ruleIndex, int ruleStartIndex, boolean success);

287

public void mark(int i);

288

public void rewind(int i);

289

public void rewind();

290

public void beginBacktrack(int level);

291

public void endBacktrack(int level, boolean successful);

292

public void location(int line, int pos);

293

public void recognitionException(RecognitionException e);

294

public void beginResync();

295

public void endResync();

296

public void semanticPredicate(boolean result, String predicate);

297

298

public void setParser(Parser parser);

299

public Parser getParser();

300

301

// Report generation

302

public String getReport();

303

public String getReport(String name);

304

305

public ProfileStats getDecisionProfile();

306

public String toNotifyString();

307

public String toString();

308

}

309

```

310

311

**Usage Examples:**

312

313

```java

314

// Profile parser performance

315

MyLexer lexer = new MyLexer(new ANTLRStringStream(input));

316

CommonTokenStream tokens = new CommonTokenStream(lexer);

317

MyParser parser = new MyParser(tokens);

318

319

// Add profiler

320

Profiler profiler = new Profiler(parser);

321

parser.setDebugListener(profiler);

322

323

// Parse and collect statistics

324

parser.program();

325

326

// Get performance report

327

String report = profiler.getReport();

328

System.out.println("Performance Report:");

329

System.out.println(report);

330

331

// Get decision profile

332

ProfileStats stats = profiler.getDecisionProfile();

333

System.out.println("Decision stats: " + stats.toString());

334

```

335

336

### Tracer

337

338

Simple trace listener that prints parsing events to console.

339

340

```java { .api }

341

/**

342

* Tracing debug event listener

343

*/

344

public class Tracer extends BlankDebugEventListener {

345

public Parser recognizer;

346

347

public Tracer(Parser recognizer);

348

349

public void enterRule(String ruleName);

350

public void exitRule(String ruleName);

351

}

352

353

/**

354

* Debug listener that prints trace information

355

*/

356

public class TraceDebugEventListener extends BlankDebugEventListener {

357

public void enterRule(String grammarFileName, String ruleName);

358

public void exitRule(String grammarFileName, String ruleName);

359

public void enterAlt(int alt);

360

public void enterSubRule(int decisionNumber);

361

public void exitSubRule(int decisionNumber);

362

public void enterDecision(int decisionNumber, boolean couldBacktrack);

363

public void exitDecision(int decisionNumber);

364

public void consumeToken(Token token);

365

public void consumeHiddenToken(Token token);

366

public void LT(int i, Token t);

367

public void nilNode(Object t);

368

public void errorNode(Object t);

369

public void createNode(Object t, Token token);

370

public void createNode(Object t, int tokenType, String text);

371

public void becomeRoot(Object newRoot, Object oldRoot);

372

public void addChild(Object root, Object child);

373

public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex);

374

}

375

```

376

377

**Usage Examples:**

378

379

```java

380

// Simple rule tracing

381

MyParser parser = new MyParser(tokens);

382

Tracer tracer = new Tracer(parser);

383

parser.setDebugListener(tracer);

384

385

// This will print rule entry/exit during parsing

386

parser.program();

387

388

// Full event tracing

389

TraceDebugEventListener trace = new TraceDebugEventListener();

390

DebugParser debugParser = new DebugParser(tokens, trace);

391

debugParser.program(); // Prints all parse events

392

```

393

394

### Remote Debugging

395

396

Support for remote debugging sessions via socket communication.

397

398

```java { .api }

399

/**

400

* Socket proxy for debug events

401

*/

402

public class DebugEventSocketProxy extends BlankDebugEventListener {

403

public static final int DEFAULT_DEBUGGER_PORT = 0xBFBF;

404

405

protected int port;

406

protected ServerSocket serverSocket;

407

protected Socket socket;

408

protected PrintWriter out;

409

protected BufferedReader in;

410

411

public DebugEventSocketProxy(Parser recognizer, int port, TreeAdaptor adaptor)

412

throws IOException;

413

414

public void handshake() throws IOException;

415

public void commence();

416

public void terminate();

417

418

protected void transmit(String event);

419

420

public void enterRule(String grammarFileName, String ruleName);

421

public void exitRule(String grammarFileName, String ruleName);

422

public void enterAlt(int alt);

423

public void enterSubRule(int decisionNumber);

424

public void exitSubRule(int decisionNumber);

425

public void enterDecision(int decisionNumber, boolean couldBacktrack);

426

public void exitDecision(int decisionNumber);

427

public void consumeToken(Token token);

428

public void consumeHiddenToken(Token token);

429

public void LT(int i, Token t);

430

public void mark(int marker);

431

public void rewind(int marker);

432

public void rewind();

433

public void beginBacktrack(int level);

434

public void endBacktrack(int level, boolean successful);

435

public void location(int line, int pos);

436

public void recognitionException(RecognitionException e);

437

public void beginResync();

438

public void endResync();

439

public void semanticPredicate(boolean result, String predicate);

440

}

441

442

/**

443

* Remote socket listener for debug events

444

*/

445

public class RemoteDebugEventSocketListener {

446

public static final int MAX_EVENT_ELEMENTS = 8;

447

448

protected String grammarFileName;

449

protected String[] ruleNames;

450

protected ServerSocket serverSocket;

451

protected Socket clientSocket;

452

protected PrintWriter out;

453

protected BufferedReader in;

454

protected boolean sessionStarted = false;

455

456

public RemoteDebugEventSocketListener(String grammarFileName, String[] ruleNames)

457

throws IOException;

458

459

public void start();

460

public void waitForDebuggerToAttach() throws IOException;

461

public void handshake() throws IOException;

462

public void commence();

463

public void terminate();

464

}

465

```

466

467

**Usage Examples:**

468

469

```java

470

// Remote debugging setup

471

try {

472

MyParser parser = new MyParser(tokens);

473

DebugEventSocketProxy proxy = new DebugEventSocketProxy(parser, 0xBFBF, new CommonTreeAdaptor());

474

parser.setDebugListener(proxy);

475

476

System.out.println("Waiting for debugger to attach...");

477

proxy.handshake(); // Wait for debugger connection

478

479

// Parse with remote debugging

480

parser.program();

481

482

} catch (IOException e) {

483

System.err.println("Remote debugging failed: " + e.getMessage());

484

}

485

```

486

487

## Utility Classes

488

489

### Blank Debug Event Listener

490

491

No-op implementation providing a base for selective event handling.

492

493

```java { .api }

494

/**

495

* No-op debug event listener implementation

496

*/

497

public class BlankDebugEventListener implements DebugEventListener {

498

public void enterRule(String grammarFileName, String ruleName) {}

499

public void exitRule(String grammarFileName, String ruleName) {}

500

public void enterAlt(int alt) {}

501

public void enterSubRule(int decisionNumber) {}

502

public void exitSubRule(int decisionNumber) {}

503

public void enterDecision(int decisionNumber, boolean couldBacktrack) {}

504

public void exitDecision(int decisionNumber) {}

505

public void consumeToken(Token token) {}

506

public void consumeHiddenToken(Token token) {}

507

public void LT(int i, Token t) {}

508

public void nilNode(Object t) {}

509

public void errorNode(Object t) {}

510

public void createNode(Object t, Token token) {}

511

public void createNode(Object t, int tokenType, String text) {}

512

public void becomeRoot(Object newRoot, Object oldRoot) {}

513

public void addChild(Object root, Object child) {}

514

public void setTokenBoundaries(Object t, int tokenStartIndex, int tokenStopIndex) {}

515

public void setType(Object node, int tokenType) {}

516

public void setText(Object node, String tokenText) {}

517

public void terminate() {}

518

}

519

```

520

521

### Debug Event Hub

522

523

Multiplexer for sending debug events to multiple listeners.

524

525

```java { .api }

526

/**

527

* Hub for managing multiple debug listeners

528

*/

529

public class DebugEventHub implements DebugEventListener {

530

protected List<DebugEventListener> listeners;

531

532

public DebugEventHub(DebugEventListener listener, DebugEventListener... others);

533

534

public void addListener(DebugEventListener listener);

535

public void removeListener(DebugEventListener listener);

536

537

/* All methods delegate to all listeners */

538

public void enterRule(String grammarFileName, String ruleName);

539

public void exitRule(String grammarFileName, String ruleName);

540

// ... (implements all DebugEventListener methods)

541

}

542

```

543

544

## Common Patterns

545

546

### Custom Debug Listener

547

548

```java

549

public class MyDebugListener extends BlankDebugEventListener {

550

private int ruleDepth = 0;

551

private long startTime;

552

553

@Override

554

public void enterRule(String grammarFileName, String ruleName) {

555

System.out.println(indent() + "-> " + ruleName);

556

ruleDepth++;

557

startTime = System.currentTimeMillis();

558

}

559

560

@Override

561

public void exitRule(String grammarFileName, String ruleName) {

562

ruleDepth--;

563

long elapsed = System.currentTimeMillis() - startTime;

564

System.out.println(indent() + "<- " + ruleName + " (" + elapsed + "ms)");

565

}

566

567

@Override

568

public void consumeToken(Token token) {

569

System.out.println(indent() + "consume: " + token.getText());

570

}

571

572

private String indent() {

573

return " ".repeat(ruleDepth);

574

}

575

}

576

```

577

578

### Performance Monitoring

579

580

```java

581

public class PerformanceMonitor extends BlankDebugEventListener {

582

private Map<String, RuleStats> ruleStats = new HashMap<>();

583

private Stack<RuleEntry> callStack = new Stack<>();

584

585

private static class RuleEntry {

586

String name;

587

long startTime;

588

589

RuleEntry(String name) {

590

this.name = name;

591

this.startTime = System.nanoTime();

592

}

593

}

594

595

private static class RuleStats {

596

int callCount;

597

long totalTime;

598

long maxTime;

599

600

void addCall(long time) {

601

callCount++;

602

totalTime += time;

603

maxTime = Math.max(maxTime, time);

604

}

605

}

606

607

@Override

608

public void enterRule(String grammarFileName, String ruleName) {

609

callStack.push(new RuleEntry(ruleName));

610

}

611

612

@Override

613

public void exitRule(String grammarFileName, String ruleName) {

614

if (!callStack.isEmpty()) {

615

RuleEntry entry = callStack.pop();

616

long elapsed = System.nanoTime() - entry.startTime;

617

618

ruleStats.computeIfAbsent(ruleName, k -> new RuleStats())

619

.addCall(elapsed);

620

}

621

}

622

623

public void printReport() {

624

System.out.println("Performance Report:");

625

System.out.println("Rule\t\tCalls\tTotal(ms)\tAvg(ms)\t\tMax(ms)");

626

627

for (Map.Entry<String, RuleStats> entry : ruleStats.entrySet()) {

628

RuleStats stats = entry.getValue();

629

double totalMs = stats.totalTime / 1_000_000.0;

630

double avgMs = totalMs / stats.callCount;

631

double maxMs = stats.maxTime / 1_000_000.0;

632

633

System.out.printf("%s\t\t%d\t%.2f\t\t%.2f\t\t%.2f%n",

634

entry.getKey(), stats.callCount, totalMs, avgMs, maxMs);

635

}

636

}

637

}

638

```

639

640

### Conditional Debugging

641

642

```java

643

public class ConditionalDebugger extends BlankDebugEventListener {

644

private final Set<String> debugRules;

645

private final boolean debugTokens;

646

private boolean inDebugRule = false;

647

648

public ConditionalDebugger(Set<String> debugRules, boolean debugTokens) {

649

this.debugRules = debugRules;

650

this.debugTokens = debugTokens;

651

}

652

653

@Override

654

public void enterRule(String grammarFileName, String ruleName) {

655

if (debugRules.contains(ruleName)) {

656

inDebugRule = true;

657

System.out.println("DEBUG: Entering " + ruleName);

658

}

659

}

660

661

@Override

662

public void exitRule(String grammarFileName, String ruleName) {

663

if (debugRules.contains(ruleName)) {

664

System.out.println("DEBUG: Exiting " + ruleName);

665

inDebugRule = false;

666

}

667

}

668

669

@Override

670

public void consumeToken(Token token) {

671

if (debugTokens && inDebugRule) {

672

System.out.println("DEBUG: Token: " + token.getText() +

673

" at " + token.getLine() + ":" + token.getCharPositionInLine());

674

}

675

}

676

}

677

```