diff --git a/reference/antlr4 b/reference/antlr4
index 5fb64ac91..8083e0b65 160000
--- a/reference/antlr4
+++ b/reference/antlr4
@@ -1 +1 @@
-Subproject commit 5fb64ac91e36209b99e37a6356e66c41f5e50aab
+Subproject commit 8083e0b659bb318eb4454591648a01d28e07f03e
diff --git a/runtime/CSharp/Antlr4.Runtime/Atn/LexerATNSimulator.cs b/runtime/CSharp/Antlr4.Runtime/Atn/LexerATNSimulator.cs
index b6a7a94c0..01d55a1e6 100644
--- a/runtime/CSharp/Antlr4.Runtime/Atn/LexerATNSimulator.cs
+++ b/runtime/CSharp/Antlr4.Runtime/Atn/LexerATNSimulator.cs
@@ -472,7 +472,7 @@ namespace Antlr4.Runtime.Atn
PredictionContext newContext = context.GetParent(i);
// "pop" return state
ATNState returnState = atn.states[returnStateNumber];
- ATNConfig c = ATNConfig.Create(returnState, config.Alt, newContext);
+ ATNConfig c = config.Transform(returnState, newContext, false);
currentAltReachedAcceptState = Closure(input, c, configs, currentAltReachedAcceptState, speculative);
}
return currentAltReachedAcceptState;
diff --git a/runtime/CSharp/Antlr4.Runtime/Atn/ParserATNSimulator.cs b/runtime/CSharp/Antlr4.Runtime/Atn/ParserATNSimulator.cs
index 5eaa13b15..71e68ad6f 100644
--- a/runtime/CSharp/Antlr4.Runtime/Atn/ParserATNSimulator.cs
+++ b/runtime/CSharp/Antlr4.Runtime/Atn/ParserATNSimulator.cs
@@ -1319,7 +1319,8 @@ namespace Antlr4.Runtime.Atn
/// .
///
Remove all configurations which predict an alternative greater than
/// 1, for which another configuration that predicts alternative 1 is in the
- /// same ATN state. This transformation is valid for the following reasons:
+ /// same ATN state with the same prediction context. This transformation is
+ /// valid for the following reasons:
///
/// - The closure block cannot contain any epsilon transitions which bypass
/// the body of the closure, so all states reachable via alternative 1 are
@@ -1333,6 +1334,35 @@ namespace Antlr4.Runtime.Atn
///
///
///
+ ///
+ /// The prediction context must be considered by this filter to address
+ /// situations like the following.
+ ///
+ ///
+ ///
+ /// grammar TA;
+ /// prog: statement* EOF;
+ /// statement: letterA | statement letterA 'b' ;
+ /// letterA: 'a';
+ ///
+ ///
+ ///
+ /// If the above grammar, the ATN state immediately before the token
+ /// reference
+ /// 'a'
+ /// in
+ /// letterA
+ /// is reachable from the left edge
+ /// of both the primary and closure blocks of the left-recursive rule
+ /// statement
+ /// . The prediction context associated with each of these
+ /// configurations distinguishes between them, and prevents the alternative
+ /// which stepped out to
+ /// prog
+ /// (and then back in to
+ /// statement
+ /// from being eliminated by the filter.
+ ///
///
///
/// The configuration set computed by
@@ -1349,7 +1379,7 @@ namespace Antlr4.Runtime.Atn
[return: NotNull]
protected internal virtual ATNConfigSet ApplyPrecedenceFilter(ATNConfigSet configs, ParserRuleContext globalContext, PredictionContextCache contextCache)
{
- HashSet statesFromAlt1 = new HashSet();
+ IDictionary statesFromAlt1 = new Dictionary();
ATNConfigSet configSet = new ATNConfigSet();
foreach (ATNConfig config in configs)
{
@@ -1364,7 +1394,7 @@ namespace Antlr4.Runtime.Atn
// the configuration was eliminated
continue;
}
- statesFromAlt1.Add(config.State.stateNumber);
+ statesFromAlt1.Put(config.State.stateNumber, config.Context);
if (updatedContext != config.SemanticContext)
{
configSet.Add(config.Transform(config.State, updatedContext, false), contextCache);
@@ -1381,7 +1411,8 @@ namespace Antlr4.Runtime.Atn
// already handled
continue;
}
- if (statesFromAlt1.Contains(config_1.State.stateNumber))
+ PredictionContext context = statesFromAlt1.Get(config_1.State.stateNumber);
+ if (context != null && context.Equals(config_1.Context))
{
// eliminated
continue;
@@ -1785,9 +1816,9 @@ namespace Antlr4.Runtime.Atn
return config.Transform(t.target, newContext, false);
}
- private sealed class _IComparer_1741 : IComparer
+ private sealed class _IComparer_1771 : IComparer
{
- public _IComparer_1741()
+ public _IComparer_1771()
{
}
@@ -1807,7 +1838,7 @@ namespace Antlr4.Runtime.Atn
}
}
- private static readonly IComparer StateAltSortComparator = new _IComparer_1741();
+ private static readonly IComparer StateAltSortComparator = new _IComparer_1771();
private BitSet IsConflicted(ATNConfigSet configset, PredictionContextCache contextCache)
{
diff --git a/runtime/CSharp/Antlr4.Runtime/ParserInterpreter.cs b/runtime/CSharp/Antlr4.Runtime/ParserInterpreter.cs
index ee01d635c..9d27180f8 100644
--- a/runtime/CSharp/Antlr4.Runtime/ParserInterpreter.cs
+++ b/runtime/CSharp/Antlr4.Runtime/ParserInterpreter.cs
@@ -144,8 +144,18 @@ namespace Antlr4.Runtime
// pop; return from rule
if (_ctx.IsEmpty())
{
- ExitRule();
- return rootContext;
+ if (startRuleStartState.isPrecedenceRule)
+ {
+ ParserRuleContext result = _ctx;
+ Tuple parentContext = _parentContextStack.Pop();
+ UnrollRecursionContexts(parentContext.Item1);
+ return result;
+ }
+ else
+ {
+ ExitRule();
+ return rootContext;
+ }
}
VisitRuleStopState(p);
break;
diff --git a/runtime/CSharp/Antlr4.Runtime/Recognizer`2.cs b/runtime/CSharp/Antlr4.Runtime/Recognizer`2.cs
index adcab8135..13df4c056 100644
--- a/runtime/CSharp/Antlr4.Runtime/Recognizer`2.cs
+++ b/runtime/CSharp/Antlr4.Runtime/Recognizer`2.cs
@@ -229,6 +229,8 @@ namespace Antlr4.Runtime
/// your token objects because you don't have to go modify your lexer
/// so that it creates a new Java type.
///
+ [Obsolete]
+ [System.ObsoleteAttribute(@"This method is not called by the ANTLR 4 Runtime. Specific implementations of IAntlrErrorStrategy may provide a similar feature when necessary. For example, seeDefaultErrorStrategy.GetTokenErrorDisplay(IToken) .")]
public virtual string GetTokenErrorDisplay(IToken t)
{
if (t == null)