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

error-handling.mddocs/

0

# Error Handling

1

2

Comprehensive exception hierarchy and error recovery mechanisms for robust parsing. ANTLR provides detailed error reporting with position information and flexible recovery strategies.

3

4

## Capabilities

5

6

### Recognition Exception Hierarchy

7

8

Base exception class for all parsing and lexical analysis errors.

9

10

```java { .api }

11

/**

12

* Base class for all recognition exceptions

13

*/

14

public class RecognitionException extends Exception {

15

/** What input stream were we parsing that triggered this exception?

16

* This includes the current Token in a TokenStream or the current char

17

* in a CharStream.

18

*/

19

public IntStream input;

20

21

/** The current Token when an error occurred. Since not all streams

22

* can retrieve the ith Token, we have to track the Token object.

23

* For parsers. Even when it's a tree parser, token might be null.

24

*/

25

public Token token;

26

27

/** If this is a tree parser exception, node is set to the node with

28

* the problem.

29

*/

30

public Object node;

31

32

/** The current char when an error occurred. For lexers. */

33

public int c;

34

35

/** Track the line at which the error occurred in case this is

36

* generated from a lexer. We need to track this since the

37

* unexpected char doesn't carry the line info.

38

*/

39

public int line;

40

41

public int charPositionInLine;

42

43

/** If you are parsing a tree node stream, you will encounter som

44

* imaginary nodes but not others. We distinguish.

45

*/

46

public boolean approximateLineInfo;

47

48

/** Used for remote debugger deserialization */

49

public RecognitionException();

50

51

public RecognitionException(IntStream input);

52

53

/** Extract the unexpectedTokenType from the token */

54

protected int getUnexpectedType();

55

}

56

```

57

58

### Token Mismatch Exceptions

59

60

Exceptions for various token matching failures.

61

62

```java { .api }

63

/**

64

* Exception for token mismatch errors

65

*/

66

public class MismatchedTokenException extends RecognitionException {

67

public int expecting;

68

69

public MismatchedTokenException();

70

public MismatchedTokenException(int expecting, IntStream input);

71

72

public String toString();

73

}

74

75

/**

76

* Exception for missing expected token

77

*/

78

public class MissingTokenException extends MismatchedTokenException {

79

/** Used for remote debugger deserialization */

80

public MissingTokenException();

81

82

public MissingTokenException(int expecting, IntStream input, Object inserted);

83

84

public int getMissingType();

85

86

public String toString();

87

}

88

89

/**

90

* Exception for unwanted extra token

91

*/

92

public class UnwantedTokenException extends MismatchedTokenException {

93

public UnwantedTokenException();

94

public UnwantedTokenException(int expecting, IntStream input);

95

96

public Token getUnexpectedToken();

97

98

public String toString();

99

}

100

```

101

102

**Usage Examples:**

103

104

```java

105

import org.antlr.runtime.*;

106

107

// Catching specific token exceptions

108

try {

109

MyParser parser = new MyParser(tokens);

110

parser.program();

111

} catch (MismatchedTokenException e) {

112

System.err.println("Expected token: " + e.expecting +

113

" but found: " + e.getUnexpectedType());

114

System.err.println("At line: " + e.line +

115

" position: " + e.charPositionInLine);

116

} catch (MissingTokenException e) {

117

System.err.println("Missing token of type: " + e.getMissingType());

118

} catch (UnwantedTokenException e) {

119

System.err.println("Unwanted token: " + e.getUnexpectedToken().getText());

120

}

121

```

122

123

### Set Mismatch Exceptions

124

125

Exceptions for token set matching failures.

126

127

```java { .api }

128

/**

129

* Exception for set mismatch errors

130

*/

131

public class MismatchedSetException extends MismatchedTokenException {

132

public BitSet expecting;

133

134

public MismatchedSetException();

135

public MismatchedSetException(BitSet expecting, IntStream input);

136

137

public String toString();

138

}

139

140

/**

141

* Exception for negated set mismatch errors

142

*/

143

public class MismatchedNotSetException extends MismatchedSetException {

144

public MismatchedNotSetException();

145

public MismatchedNotSetException(BitSet expecting, IntStream input);

146

147

public String toString();

148

}

149

```

150

151

**Usage Examples:**

152

153

```java

154

// Handling set-based matching errors

155

try {

156

parser.statement();

157

} catch (MismatchedSetException e) {

158

System.err.println("Expected one of: " + e.expecting.toString(tokenNames));

159

System.err.println("But found: " + e.token.getText());

160

} catch (MismatchedNotSetException e) {

161

System.err.println("Did not expect: " + e.token.getText());

162

System.err.println("Forbidden tokens: " + e.expecting.toString(tokenNames));

163

}

164

```

165

166

### Alternative and Range Exceptions

167

168

Exceptions for alternative selection and character range failures.

169

170

```java { .api }

171

/**

172

* Exception when no alternative matches

173

*/

174

public class NoViableAltException extends RecognitionException {

175

public int decisionNumber;

176

public int stateNumber;

177

178

public NoViableAltException();

179

public NoViableAltException(String grammarDecisionDescription,

180

int decisionNumber,

181

int stateNumber,

182

IntStream input);

183

184

public String toString();

185

}

186

187

/**

188

* Exception for character range mismatch

189

*/

190

public class MismatchedRangeException extends RecognitionException {

191

public int a;

192

public int b;

193

194

public MismatchedRangeException();

195

public MismatchedRangeException(int a, int b, IntStream input);

196

197

public String toString();

198

}

199

200

/**

201

* Exception for early exit from loops

202

*/

203

public class EarlyExitException extends RecognitionException {

204

public int decisionNumber;

205

206

public EarlyExitException();

207

public EarlyExitException(int decisionNumber, IntStream input);

208

209

public String toString();

210

}

211

```

212

213

**Usage Examples:**

214

215

```java

216

// Handling decision-making exceptions

217

try {

218

parser.expression();

219

} catch (NoViableAltException e) {

220

System.err.println("No viable alternative at decision " + e.decisionNumber);

221

System.err.println("State: " + e.stateNumber);

222

System.err.println("Input: " + e.token.getText());

223

} catch (EarlyExitException e) {

224

System.err.println("Early exit from decision " + e.decisionNumber);

225

System.err.println("At least one iteration required");

226

}

227

```

228

229

### Predicate and Tree Exceptions

230

231

Exceptions for semantic predicates and tree parsing failures.

232

233

```java { .api }

234

/**

235

* Exception for failed predicate evaluation

236

*/

237

public class FailedPredicateException extends RecognitionException {

238

public String ruleName;

239

public String predicateText;

240

241

public FailedPredicateException();

242

public FailedPredicateException(IntStream input, String ruleName, String predicateText);

243

244

public String toString();

245

}

246

247

/**

248

* Exception for tree node mismatch

249

*/

250

public class MismatchedTreeNodeException extends RecognitionException {

251

public int expecting;

252

253

public MismatchedTreeNodeException();

254

public MismatchedTreeNodeException(int expecting, TreeNodeStream input);

255

256

public String toString();

257

}

258

```

259

260

**Usage Examples:**

261

262

```java

263

// Handling semantic and tree parsing exceptions

264

try {

265

parser.constrainedRule();

266

} catch (FailedPredicateException e) {

267

System.err.println("Predicate failed in rule: " + e.ruleName);

268

System.err.println("Predicate: " + e.predicateText);

269

System.err.println("At line: " + e.line);

270

} catch (MismatchedTreeNodeException e) {

271

System.err.println("Expected tree node type: " + e.expecting);

272

System.err.println("But found: " + e.getUnexpectedType());

273

}

274

```

275

276

## Error Recovery Strategies

277

278

### Single Token Recovery

279

280

Attempt to recover by inserting or deleting a single token.

281

282

```java { .api }

283

// In BaseRecognizer

284

protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow)

285

throws RecognitionException {

286

287

// Try single token deletion

288

if (mismatchIsUnwantedToken(input, ttype)) {

289

UnwantedTokenException e = new UnwantedTokenException(ttype, input);

290

beginResync();

291

input.consume(); // Delete current token

292

endResync();

293

reportError(e);

294

Object matchedSymbol = getCurrentInputSymbol(input);

295

input.consume(); // Move past the token we are recovering from

296

return matchedSymbol;

297

}

298

299

// Try single token insertion

300

if (mismatchIsMissingToken(input, follow)) {

301

Object inserted = getMissingSymbol(input, null, ttype, follow);

302

MissingTokenException e = new MissingTokenException(ttype, input, inserted);

303

reportError(e);

304

return inserted;

305

}

306

307

// Could not recover

308

throw new MismatchedTokenException(ttype, input);

309

}

310

```

311

312

**Usage Examples:**

313

314

```java

315

// Custom single token recovery

316

public class MyParser extends Parser {

317

@Override

318

protected Object recoverFromMismatchedToken(IntStream input, int ttype, BitSet follow)

319

throws RecognitionException {

320

321

// Log recovery attempt

322

System.err.println("Attempting single token recovery for type: " + ttype);

323

324

// Try standard recovery

325

try {

326

return super.recoverFromMismatchedToken(input, ttype, follow);

327

} catch (RecognitionException e) {

328

// Custom recovery logic

329

System.err.println("Standard recovery failed, using custom strategy");

330

throw e;

331

}

332

}

333

}

334

```

335

336

### Panic Mode Recovery

337

338

Skip tokens until a safe recovery point is found.

339

340

```java { .api }

341

// In BaseRecognizer

342

public void recover(IntStream input, RecognitionException re) {

343

if (state.lastErrorIndex == input.index()) {

344

// Ensure we consume at least one token to avoid infinite loops

345

input.consume();

346

}

347

state.lastErrorIndex = input.index();

348

349

BitSet followSet = computeErrorRecoverySet();

350

beginResync();

351

consumeUntil(input, followSet);

352

endResync();

353

}

354

355

protected void consumeUntil(IntStream input, BitSet set) {

356

int ttype = input.LA(1);

357

while (ttype != Token.EOF && !set.member(ttype)) {

358

input.consume();

359

ttype = input.LA(1);

360

}

361

}

362

```

363

364

**Usage Examples:**

365

366

```java

367

// Custom panic mode recovery

368

public class MyParser extends Parser {

369

@Override

370

public void recover(IntStream input, RecognitionException re) {

371

System.err.println("Entering panic mode recovery");

372

373

// Create custom recovery set

374

BitSet recoverySet = new BitSet();

375

recoverySet.add(SEMICOLON);

376

recoverySet.add(RBRACE);

377

recoverySet.add(EOF);

378

379

// Skip until recovery token

380

beginResync();

381

while (input.LA(1) != Token.EOF && !recoverySet.member(input.LA(1))) {

382

System.err.println("Skipping: " + input.LT(1).getText());

383

input.consume();

384

}

385

endResync();

386

387

System.err.println("Recovery complete at: " + input.LT(1).getText());

388

}

389

}

390

```

391

392

### Follow Set Computation

393

394

Calculate recovery points based on grammar structure.

395

396

```java { .api }

397

// In BaseRecognizer

398

protected BitSet computeErrorRecoverySet() {

399

return combineFollows(false);

400

}

401

402

protected BitSet computeContextSensitiveRuleFOLLOW() {

403

return combineFollows(true);

404

}

405

406

protected BitSet combineFollows(boolean exact) {

407

int top = state._fsp;

408

BitSet followSet = new BitSet();

409

410

for (int i = top; i >= 0; i--) {

411

BitSet localFollowSet = state.following[i];

412

followSet.or(localFollowSet);

413

414

if (exact && !localFollowSet.member(Token.EOR_TOKEN_TYPE)) {

415

break;

416

}

417

}

418

419

followSet.remove(Token.EOR_TOKEN_TYPE);

420

return followSet;

421

}

422

```

423

424

## Error Reporting

425

426

### Custom Error Messages

427

428

Override error message formatting for better user experience.

429

430

```java { .api }

431

// In BaseRecognizer

432

public String getErrorMessage(RecognitionException e, String[] tokenNames) {

433

String msg;

434

435

if (e instanceof MismatchedTokenException) {

436

MismatchedTokenException mte = (MismatchedTokenException)e;

437

msg = "mismatched input " + getTokenErrorDisplay(e.token) +

438

" expecting " + getTokenErrorDisplay(mte.expecting, tokenNames);

439

} else if (e instanceof MismatchedTreeNodeException) {

440

MismatchedTreeNodeException mtne = (MismatchedTreeNodeException)e;

441

msg = "mismatched tree node: " + mtne.node +

442

" expecting " + getTokenErrorDisplay(mtne.expecting, tokenNames);

443

} else if (e instanceof NoViableAltException) {

444

msg = "no viable alternative at input " + getTokenErrorDisplay(e.token);

445

} else if (e instanceof EarlyExitException) {

446

msg = "required (...)+ loop did not match anything at input " + getTokenErrorDisplay(e.token);

447

} else if (e instanceof MismatchedSetException) {

448

MismatchedSetException mse = (MismatchedSetException)e;

449

msg = "mismatched input " + getTokenErrorDisplay(e.token) +

450

" expecting set " + mse.expecting;

451

} else if (e instanceof MismatchedNotSetException) {

452

MismatchedNotSetException mse = (MismatchedNotSetException)e;

453

msg = "mismatched input " + getTokenErrorDisplay(e.token) +

454

" expecting set " + mse.expecting;

455

} else if (e instanceof FailedPredicateException) {

456

FailedPredicateException fpe = (FailedPredicateException)e;

457

msg = "rule " + fpe.ruleName + " " + fpe.predicateText;

458

} else {

459

msg = super.getErrorMessage(e, tokenNames);

460

}

461

462

return msg;

463

}

464

```

465

466

**Usage Examples:**

467

468

```java

469

// Custom error message formatting

470

public class MyParser extends Parser {

471

@Override

472

public String getErrorMessage(RecognitionException e, String[] tokenNames) {

473

StringBuilder buf = new StringBuilder();

474

475

// Add context information

476

buf.append("Parse error at line ").append(e.line);

477

buf.append(", column ").append(e.charPositionInLine).append(": ");

478

479

// Add specific error details

480

if (e instanceof MismatchedTokenException) {

481

MismatchedTokenException mte = (MismatchedTokenException)e;

482

buf.append("Expected '").append(tokenNames[mte.expecting]);

483

buf.append("' but found '").append(e.token.getText()).append("'");

484

} else {

485

buf.append(super.getErrorMessage(e, tokenNames));

486

}

487

488

// Add suggestions

489

buf.append("\nSuggestion: Check for missing semicolon or bracket");

490

491

return buf.toString();

492

}

493

494

@Override

495

public void displayRecognitionError(String[] tokenNames, RecognitionException e) {

496

String hdr = getErrorHeader(e);

497

String msg = getErrorMessage(e, tokenNames);

498

499

// Custom error display with colors/formatting

500

System.err.println("\u001B[31m" + hdr + " " + msg + "\u001B[0m");

501

502

// Show error context

503

if (e.token != null) {

504

showErrorContext(e.token);

505

}

506

}

507

508

private void showErrorContext(Token errorToken) {

509

// Display source line with error position highlighted

510

System.err.println("Source: " + getSourceLine(errorToken.getLine()));

511

System.err.print(" ");

512

for (int i = 0; i < errorToken.getCharPositionInLine(); i++) {

513

System.err.print(" ");

514

}

515

System.err.println("^");

516

}

517

}

518

```

519

520

### Error Listeners

521

522

Implement custom error handling strategies.

523

524

```java { .api }

525

public interface ErrorListener {

526

void syntaxError(Recognizer recognizer, Object offendingSymbol,

527

int line, int charPositionInLine, String msg, RecognitionException e);

528

}

529

530

// Custom error collector

531

public class ErrorCollector implements ErrorListener {

532

private List<SyntaxError> errors = new ArrayList<>();

533

534

@Override

535

public void syntaxError(Recognizer recognizer, Object offendingSymbol,

536

int line, int charPositionInLine, String msg, RecognitionException e) {

537

errors.add(new SyntaxError(line, charPositionInLine, msg, e));

538

}

539

540

public List<SyntaxError> getErrors() {

541

return errors;

542

}

543

544

public boolean hasErrors() {

545

return !errors.isEmpty();

546

}

547

}

548

```

549

550

## Common Patterns

551

552

### Robust Parser with Error Recovery

553

554

```java

555

public class RobustParser extends MyParser {

556

private List<String> errors = new ArrayList<>();

557

558

@Override

559

public void displayRecognitionError(String[] tokenNames, RecognitionException e) {

560

String msg = getErrorHeader(e) + " " + getErrorMessage(e, tokenNames);

561

errors.add(msg);

562

563

// Continue parsing after error

564

try {

565

recover(input, e);

566

} catch (Exception recovery) {

567

// Recovery failed, give up

568

throw new RuntimeException("Cannot recover from parse error", e);

569

}

570

}

571

572

public List<String> getErrors() {

573

return errors;

574

}

575

576

public boolean hasErrors() {

577

return !errors.isEmpty();

578

}

579

}

580

```

581

582

### Error-Tolerant Parsing

583

584

```java

585

// Parse with maximum error tolerance

586

public ParseResult parseWithErrors(String input) {

587

ANTLRStringStream stream = new ANTLRStringStream(input);

588

MyLexer lexer = new MyLexer(stream);

589

CommonTokenStream tokens = new CommonTokenStream(lexer);

590

RobustParser parser = new RobustParser(tokens);

591

592

Object tree = null;

593

try {

594

tree = parser.program().getTree();

595

} catch (RecognitionException e) {

596

// Even if parsing fails, collect partial results

597

System.err.println("Parsing failed but collected " +

598

parser.getErrors().size() + " errors");

599

}

600

601

return new ParseResult(tree, parser.getErrors());

602

}

603

```

604

605

### Incremental Error Recovery

606

607

```java

608

// Recovery that attempts multiple strategies

609

@Override

610

public void recover(IntStream input, RecognitionException re) {

611

// Try different recovery strategies in order

612

if (tryStatementRecovery(input, re)) return;

613

if (tryExpressionRecovery(input, re)) return;

614

if (tryBlockRecovery(input, re)) return;

615

616

// Fall back to standard recovery

617

super.recover(input, re);

618

}

619

620

private boolean tryStatementRecovery(IntStream input, RecognitionException re) {

621

BitSet stmtSet = new BitSet();

622

stmtSet.add(IF); stmtSet.add(WHILE); stmtSet.add(FOR);

623

stmtSet.add(SEMICOLON); stmtSet.add(RBRACE);

624

625

return consumeUntilSet(input, stmtSet);

626

}

627

```