Advanced Augmented Transition Network and Deterministic Finite Automaton classes for parser optimization and configuration. These classes provide the low-level parsing engine that powers ANTLR4's adaptive parsing capabilities.
Core ATN classes for representing the parsing automaton.
/**
* Augmented Transition Network representing parser logic
*/
class ATN {
/** Invalid alternative number constant */
static readonly INVALID_ALT_NUMBER: number;
/** Array of all ATN states */
states: ATNState[];
/** Decision states indexed by decision number */
decisionToState: DecisionState[];
/** Rule start states indexed by rule number */
ruleToStartState: RuleStartState[];
/** Rule stop states indexed by rule number */
ruleToStopState: RuleStopState[];
/**
* Get expected tokens at a specific ATN state
* @param stateNumber - ATN state number
* @param ctx - Rule context for prediction
* @returns Set of expected token types
*/
getExpectedTokens(stateNumber: number, ctx: RuleContext): IntervalSet;
/**
* Get next possible tokens from ATN state
* @param atnState - ATN state to analyze
* @param ctx - Rule context (optional)
* @returns Set of possible next tokens
*/
nextTokens(atnState: ATNState, ctx?: RuleContext): IntervalSet;
}
/**
* Configuration state during ATN simulation
*/
class ATNConfig {
/** ATN state this configuration represents */
state: ATNState;
// Additional configuration data for prediction
}
/**
* Set of ATN configurations for decision making
*/
class ATNConfigSet {
/** Array of ATN configurations */
configs: ATNConfig[];
}Classes for loading serialized ATN data.
/**
* Options for ATN deserialization
*/
class ATNDeserializationOptions {
/** Whether ATN should be read-only (optional) */
readOnly?: boolean;
/** Whether to verify ATN integrity (optional) */
verifyATN?: boolean;
/** Whether to generate rule bypass transitions (optional) */
generateRuleBypassTransitions?: boolean;
}
/**
* Deserializes ATN from serialized data format
*/
class ATNDeserializer {
/**
* Create ATN deserializer with options
* @param options - Deserialization options (optional)
*/
constructor(options?: ATNDeserializationOptions);
/**
* Deserialize ATN from numeric array data
* @param data - Serialized ATN data as number array
* @returns Deserialized ATN instance
*/
deserialize(data: number[]): ATN;
}Simulators that execute the ATN for parsing decisions.
/**
* Base class for ATN simulators
*/
abstract class ATNSimulator {
// Empty base class providing common interface
}
/**
* ATN simulator for lexer operations
*/
class LexerATNSimulator implements ATNSimulator {
/** Array of DFA instances for decisions */
decisionToDFA: DFA[];
/**
* Create lexer ATN simulator
* @param recog - Recognizer using this simulator
* @param atn - ATN to simulate
* @param decisionToDFA - DFA array for caching decisions
* @param sharedContextCache - Shared prediction context cache
*/
constructor(recog: Recognizer<number>, atn: ATN, decisionToDFA: DFA[], sharedContextCache: PredictionContextCache);
/**
* Consume input character and update simulation state
* @param input - Character stream to consume from
*/
consume(input: CharStream): void;
}
/**
* ATN simulator for parser operations
*/
class ParserATNSimulator extends ATNSimulator {
/** Current prediction mode */
predictionMode: PredictionMode;
/** Array of DFA instances for decisions */
decisionToDFA: DFA[];
/** ATN being simulated */
atn: ATN;
/** Debug mode flag (optional) */
debug?: boolean;
/** ATN simulation tracing flag (optional) */
trace_atn_sim?: boolean;
/**
* Create parser ATN simulator
* @param recog - Recognizer using this simulator
* @param atn - ATN to simulate
* @param decisionToDFA - DFA array for caching decisions
* @param sharedContextCache - Shared prediction context cache
*/
constructor(recog: Recognizer<Token>, atn: ATN, decisionToDFA: DFA[], sharedContextCache: PredictionContextCache);
/**
* Perform adaptive prediction for a decision
* @param input - Token stream to predict from
* @param decision - Decision number to predict
* @param outerContext - Outer parser rule context
* @returns Predicted alternative number
*/
adaptivePredict(input: TokenStream, decision: number, outerContext: ParserRuleContext): number;
}Configuration for parser prediction behavior.
/**
* Prediction modes for parsing decisions
*/
class PredictionMode {
/** Strong LL prediction mode */
static readonly SLL: number;
/** Full LL prediction mode */
static readonly LL: number;
/** LL with exact ambiguity detection */
static readonly LL_EXACT_AMBIG_DETECTION: number;
}
/**
* Cache for prediction contexts to improve performance
*/
class PredictionContextCache {
// Empty base class for caching prediction contexts
}DFA classes for optimized decision caching.
/**
* Deterministic Finite Automaton for caching parser decisions
*/
class DFA {
/**
* Create DFA for decision caching
* @param ds - Decision state
* @param index - DFA index
*/
constructor(ds: any, index: number);
/**
* Convert DFA to string representation for lexer
* @returns String representation of DFA
*/
toLexerString(): string;
}Different types of states in the ATN.
/**
* Base class for ATN states
*/
abstract class ATNState {
/** ATN containing this state */
atn: ATN;
/** Unique state number within ATN */
stateNumber: number;
}
/**
* ATN state that represents a decision point
*/
class DecisionState extends ATNState {
/** Decision number for this state */
decision: number;
/** Whether decision is non-greedy */
nonGreedy: boolean;
}
/**
* Start state of a grammar rule
*/
class RuleStartState extends ATNState {
/** Corresponding rule stop state */
stopState: RuleStopState;
/** Whether this rule is left-recursive */
isLeftRecursiveRule: boolean;
}
/**
* Final state of a grammar rule
*/
class RuleStopState extends ATNState {
// Final state - no additional properties
}Creating and configuring ATN simulator:
import { ParserATNSimulator, ATN, DFA, PredictionContextCache, PredictionMode } from "antlr4";
// Typically done by generated parser, but can be customized
class CustomParser extends Parser {
constructor(input: TokenStream) {
super(input);
// Create custom ATN simulator with debug mode
const atn = this.getATN(); // Get parser's ATN
const decisionToDFA = this._interp.decisionToDFA; // Get DFA array
const sharedContextCache = new PredictionContextCache();
this._interp = new ParserATNSimulator(this, atn, decisionToDFA, sharedContextCache);
this._interp.predictionMode = PredictionMode.LL; // Use full LL parsing
this._interp.debug = true; // Enable debug mode
}
}Setting different prediction modes:
import { PredictionMode } from "antlr4";
const parser = new MyParser(tokens);
// Use Strong LL for faster parsing (may not handle all grammars)
parser._interp.predictionMode = PredictionMode.SLL;
try {
const tree = parser.expression();
console.log("SLL parsing successful");
} catch (e) {
// Fall back to full LL on SLL failure
console.log("SLL failed, falling back to LL");
parser.reset();
parser._interp.predictionMode = PredictionMode.LL;
const tree = parser.expression();
}Using exact ambiguity detection:
import { PredictionMode, DiagnosticErrorListener } from "antlr4";
const parser = new MyParser(tokens);
// Enable exact ambiguity detection
parser._interp.predictionMode = PredictionMode.LL_EXACT_AMBIG_DETECTION;
// Add diagnostic listener to catch ambiguities
const diagnosticListener = new DiagnosticErrorListener();
parser.addErrorListener(diagnosticListener);
const tree = parser.expression();
console.log("Parsing complete - check listener for ambiguity reports");Custom ATN deserialization:
import { ATNDeserializer, ATNDeserializationOptions } from "antlr4";
// Custom deserialization options
const options = new ATNDeserializationOptions();
options.verifyATN = true; // Verify ATN integrity
options.generateRuleBypassTransitions = true; // Generate bypass transitions
const deserializer = new ATNDeserializer(options);
// Deserialize ATN from data (typically embedded in generated parser)
const atnData = getATNData(); // Your serialized ATN data
const atn = deserializer.deserialize(atnData);
console.log(`ATN loaded with ${atn.states.length} states`);
console.log(`Number of rules: ${atn.ruleToStartState.length}`);Analyzing ATN structure:
import { ATN, DecisionState, RuleStartState } from "antlr4";
function analyzeATN(atn: ATN): void {
console.log(`ATN Analysis:`);
console.log(` Total states: ${atn.states.length}`);
console.log(` Rules: ${atn.ruleToStartState.length}`);
console.log(` Decisions: ${atn.decisionToState.length}`);
// Count state types
let decisionStates = 0;
let ruleStartStates = 0;
for (const state of atn.states) {
if (state instanceof DecisionState) {
decisionStates++;
} else if (state instanceof RuleStartState) {
ruleStartStates++;
}
}
console.log(` Decision states: ${decisionStates}`);
console.log(` Rule start states: ${ruleStartStates}`);
// Analyze decisions
for (let i = 0; i < atn.decisionToState.length; i++) {
const decisionState = atn.decisionToState[i];
if (decisionState) {
console.log(` Decision ${i}: State ${decisionState.stateNumber}, Non-greedy: ${decisionState.nonGreedy}`);
}
}
}
// Usage with parser's ATN
const parser = new MyParser(tokens);
const atn = parser.getATN();
analyzeATN(atn);Getting expected tokens from ATN:
import { ATN, RuleContext, IntervalSet } from "antlr4";
function getExpectedTokensAtState(parser: Parser, stateNumber: number, context: RuleContext): string[] {
const atn = parser.getATN();
const expectedTokens = atn.getExpectedTokens(stateNumber, context);
const tokenNames = parser.getTokenNames();
const expected: string[] = [];
for (let i = 0; i < expectedTokens.intervals.length; i++) {
const interval = expectedTokens.intervals[i];
for (let token = interval.start; token <= interval.stop; token++) {
const tokenName = tokenNames[token] || `Token${token}`;
expected.push(tokenName);
}
}
return expected;
}
// Usage during error handling
class AnalyzingErrorListener extends ErrorListener<Token> {
syntaxError(recognizer: Recognizer<Token>, offendingSymbol: Token, line: number, column: number, msg: string, e: RecognitionException | undefined): void {
if (recognizer instanceof Parser) {
const parser = recognizer as Parser;
const expectedTokens = getExpectedTokensAtState(parser, parser.state, parser._ctx);
console.error(`Syntax error at ${line}:${column}`);
console.error(`Expected one of: ${expectedTokens.join(', ')}`);
console.error(`But found: ${offendingSymbol?.text || 'EOF'}`);
}
}
// Other methods...
reportAmbiguity(): void {}
reportAttemptingFullContext(): void {}
reportContextSensitivity(): void {}
}DFA performance monitoring:
import { DFA } from "antlr4";
class PerformanceMonitoringParser extends Parser {
private dfaHits = new Map<number, number>();
private dfaMisses = new Map<number, number>();
constructor(input: TokenStream) {
super(input);
this.monitorDFAPerformance();
}
private monitorDFAPerformance(): void {
// Override adaptivePredict to monitor DFA usage
const originalPredict = this._interp.adaptivePredict.bind(this._interp);
this._interp.adaptivePredict = (input: TokenStream, decision: number, outerContext: ParserRuleContext): number => {
const dfa = this._interp.decisionToDFA[decision];
const startState = dfa?.s0;
if (startState) {
// DFA has cached state
this.dfaHits.set(decision, (this.dfaHits.get(decision) || 0) + 1);
} else {
// DFA miss - will need ATN simulation
this.dfaMisses.set(decision, (this.dfaMisses.get(decision) || 0) + 1);
}
return originalPredict(input, decision, outerContext);
};
}
getDFAStats(): { decision: number; hits: number; misses: number; hitRate: number }[] {
const stats: { decision: number; hits: number; misses: number; hitRate: number }[] = [];
const allDecisions = new Set([...this.dfaHits.keys(), ...this.dfaMisses.keys()]);
for (const decision of allDecisions) {
const hits = this.dfaHits.get(decision) || 0;
const misses = this.dfaMisses.get(decision) || 0;
const total = hits + misses;
const hitRate = total > 0 ? hits / total : 0;
stats.push({ decision, hits, misses, hitRate });
}
return stats.sort((a, b) => a.decision - b.decision);
}
printDFAStats(): void {
const stats = this.getDFAStats();
console.log("DFA Performance Statistics:");
console.log("Decision | Hits | Misses | Hit Rate");
console.log("---------|------|--------|----------");
for (const stat of stats) {
console.log(`${stat.decision.toString().padStart(8)} | ${stat.hits.toString().padStart(4)} | ${stat.misses.toString().padStart(6)} | ${(stat.hitRate * 100).toFixed(1)}%`);
}
}
}
// Usage
const parser = new PerformanceMonitoringParser(tokens);
const tree = parser.expression();
parser.printDFAStats();