diff --git a/reference/antlr4 b/reference/antlr4 index 1930a7b29..84f92bd93 160000 --- a/reference/antlr4 +++ b/reference/antlr4 @@ -1 +1 @@ -Subproject commit 1930a7b29d4e0bcc47f22d68282d70ad2552dc2e +Subproject commit 84f92bd938e05f803f81634f43902e4b47f08ab2 diff --git a/runtime/CSharp/Antlr4.Runtime/ANTLRFileStream.cs b/runtime/CSharp/Antlr4.Runtime/ANTLRFileStream.cs index 2c78faf5c..3b6f950df 100644 --- a/runtime/CSharp/Antlr4.Runtime/ANTLRFileStream.cs +++ b/runtime/CSharp/Antlr4.Runtime/ANTLRFileStream.cs @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -using System.IO; +using Antlr4.Runtime.Misc; using Antlr4.Runtime.Sharpen; namespace Antlr4.Runtime @@ -58,35 +58,8 @@ namespace Antlr4.Runtime /// public virtual void Load(string fileName, string encoding) { - if (fileName == null) - { - return; - } - FilePath f = new FilePath(fileName); - int size = (int)f.Length(); - StreamReader isr; - FileInputStream fis = new FileInputStream(fileName); - if (encoding != null) - { - isr = new StreamReader(fis, encoding); - } - else - { - isr = new StreamReader(fis); - } - try - { - data = new char[size]; - n = isr.Read(data); - if (n < data.Length) - { - data = Arrays.CopyOf(data, n); - } - } - finally - { - isr.Close(); - } + data = Utils.ReadFile(fileName, encoding); + this.n = data.Length; } public override string SourceName diff --git a/runtime/CSharp/Antlr4.Runtime/ANTLRInputStream.cs b/runtime/CSharp/Antlr4.Runtime/ANTLRInputStream.cs index 70cea1a02..932dff5fd 100644 --- a/runtime/CSharp/Antlr4.Runtime/ANTLRInputStream.cs +++ b/runtime/CSharp/Antlr4.Runtime/ANTLRInputStream.cs @@ -314,6 +314,10 @@ namespace Antlr4.Runtime { get { + if (name == null || name.IsEmpty()) + { + return IntStreamConstants.UnknownSourceName; + } return name; } } diff --git a/runtime/CSharp/Antlr4.Runtime/Atn/ATNConfig.cs b/runtime/CSharp/Antlr4.Runtime/Atn/ATNConfig.cs index 975de41e1..ea7c4265f 100644 --- a/runtime/CSharp/Antlr4.Runtime/Atn/ATNConfig.cs +++ b/runtime/CSharp/Antlr4.Runtime/Atn/ATNConfig.cs @@ -48,10 +48,29 @@ namespace Antlr4.Runtime.Atn /// public class ATNConfig { + /// + /// This field stores the bit mask for implementing the + /// + /// property as a bit within the + /// existing + /// + /// field. + /// + private const int SuppressPrecedenceFilter = unchecked((int)(0x80000000)); + /// The ATN state associated with this configuration [NotNull] private readonly ATNState state; + /// This is a bit-field currently containing the following values. + /// + /// This is a bit-field currently containing the following values. + /// + /// private int altAndOuterContextDepth; /// @@ -70,14 +89,14 @@ namespace Antlr4.Runtime.Atn { System.Diagnostics.Debug.Assert((alt & unchecked((int)(0xFFFFFF))) == alt); this.state = state; - this.altAndOuterContextDepth = alt & unchecked((int)(0x7FFFFFFF)); + this.altAndOuterContextDepth = alt; this.context = context; } protected internal ATNConfig(Antlr4.Runtime.Atn.ATNConfig c, ATNState state, PredictionContext context) { this.state = state; - this.altAndOuterContextDepth = c.altAndOuterContextDepth & unchecked((int)(0x7FFFFFFF)); + this.altAndOuterContextDepth = c.altAndOuterContextDepth; this.context = context; } @@ -137,25 +156,6 @@ namespace Antlr4.Runtime.Atn } } - public virtual bool IsHidden - { - get - { - return altAndOuterContextDepth < 0; - } - set - { - if (value) - { - altAndOuterContextDepth |= unchecked((int)(0x80000000)); - } - else - { - altAndOuterContextDepth &= ~unchecked((int)(0x80000000)); - } - } - } - public virtual PredictionContext Context { get @@ -187,9 +187,10 @@ namespace Antlr4.Runtime.Atn /// no way to do this efficiently, we simply cannot evaluate /// dependent predicates unless we are in the rule that initially /// invokes the ATN simulator. - /// closure() tracks the depth of how far we dip into the - /// outer context: depth > 0. Note that it may not be totally - /// accurate depth since I don't ever decrement. TODO: make it a boolean then + ///

+ /// closure() tracks the depth of how far we dip into the outer context: + /// depth > 0. Note that it may not be totally accurate depth since I + /// don't ever decrement. TODO: make it a boolean then

/// public virtual int OuterContextDepth { @@ -346,6 +347,25 @@ namespace Antlr4.Runtime.Atn return false; } + public bool PrecedenceFilterSuppressed + { + get + { + return (altAndOuterContextDepth & SuppressPrecedenceFilter) != 0; + } + set + { + if (value) + { + this.altAndOuterContextDepth |= SuppressPrecedenceFilter; + } + else + { + this.altAndOuterContextDepth &= ~SuppressPrecedenceFilter; + } + } + } + /// /// An ATN configuration is equal to another if both have /// the same state, they predict the same alternative, and @@ -378,7 +398,7 @@ namespace Antlr4.Runtime.Atn return false; } } - return this.State.stateNumber == other.State.stateNumber && this.Alt == other.Alt && this.ReachesIntoOuterContext == other.ReachesIntoOuterContext && this.Context.Equals(other.Context) && this.SemanticContext.Equals(other.SemanticContext) && this.PassedThroughNonGreedyDecision == other.PassedThroughNonGreedyDecision && ObjectEqualityComparator.Instance.Equals(this.ActionExecutor, other.ActionExecutor); + return this.State.stateNumber == other.State.stateNumber && this.Alt == other.Alt && this.ReachesIntoOuterContext == other.ReachesIntoOuterContext && this.Context.Equals(other.Context) && this.SemanticContext.Equals(other.SemanticContext) && this.PrecedenceFilterSuppressed == other.PrecedenceFilterSuppressed && this.PassedThroughNonGreedyDecision == other.PassedThroughNonGreedyDecision && ObjectEqualityComparator.Instance.Equals(this.ActionExecutor, other.ActionExecutor); } public override int GetHashCode() diff --git a/runtime/CSharp/Antlr4.Runtime/Atn/ATNConfigSet.cs b/runtime/CSharp/Antlr4.Runtime/Atn/ATNConfigSet.cs index 9a2c7d200..d98136ea7 100644 --- a/runtime/CSharp/Antlr4.Runtime/Atn/ATNConfigSet.cs +++ b/runtime/CSharp/Antlr4.Runtime/Atn/ATNConfigSet.cs @@ -81,7 +81,7 @@ namespace Antlr4.Runtime.Atn private int uniqueAlt; - private BitSet conflictingAlts; + private ConflictInfo conflictInfo; private bool hasSemanticContext; @@ -144,7 +144,7 @@ namespace Antlr4.Runtime.Atn if (@readonly || !set.IsReadOnly) { this.uniqueAlt = set.uniqueAlt; - this.conflictingAlts = set.conflictingAlts; + this.conflictInfo = set.conflictInfo; } } @@ -161,9 +161,9 @@ namespace Antlr4.Runtime.Atn get { // if (!readonly && set.isReadOnly()) -> addAll is called from clone() - if (conflictingAlts != null) + if (conflictInfo != null) { - return (BitSet)conflictingAlts.Clone(); + return (BitSet)conflictInfo.ConflictedAlts.Clone(); } BitSet alts = new BitSet(); foreach (ATNConfig config in this) @@ -182,35 +182,6 @@ namespace Antlr4.Runtime.Atn } } - public void StripHiddenConfigs() - { - EnsureWritable(); - IEnumerator> iterator = mergedConfigs.EntrySet().GetEnumerator(); - while (iterator.HasNext()) - { - if (iterator.Next().Value.IsHidden) - { - iterator.Remove(); - } - } - IListIterator iterator2 = unmerged.ListIterator(); - while (iterator2.HasNext()) - { - if (iterator2.Next().IsHidden) - { - iterator2.Remove(); - } - } - iterator2 = configs.ListIterator(); - while (iterator2.HasNext()) - { - if (iterator2.Next().IsHidden) - { - iterator2.Remove(); - } - } - } - public virtual bool IsOutermostConfigSet { get @@ -320,7 +291,6 @@ namespace Antlr4.Runtime.Atn { EnsureWritable(); System.Diagnostics.Debug.Assert(!outermostConfigSet || !e.ReachesIntoOuterContext); - System.Diagnostics.Debug.Assert(!e.IsHidden); if (contextCache == null) { contextCache = PredictionContextCache.Uncached; @@ -332,6 +302,10 @@ namespace Antlr4.Runtime.Atn if (mergedConfig != null && CanMerge(e, key, mergedConfig)) { mergedConfig.OuterContextDepth = Math.Max(mergedConfig.OuterContextDepth, e.OuterContextDepth); + if (e.PrecedenceFilterSuppressed) + { + mergedConfig.PrecedenceFilterSuppressed = true; + } PredictionContext joined = PredictionContext.Join(mergedConfig.Context, e.Context, contextCache); UpdatePropertiesForMergedConfig(e); if (mergedConfig.Context == joined) @@ -347,6 +321,10 @@ namespace Antlr4.Runtime.Atn if (CanMerge(e, key, unmergedConfig)) { unmergedConfig.OuterContextDepth = Math.Max(unmergedConfig.OuterContextDepth, e.OuterContextDepth); + if (e.PrecedenceFilterSuppressed) + { + unmergedConfig.PrecedenceFilterSuppressed = true; + } PredictionContext joined = PredictionContext.Join(unmergedConfig.Context, e.Context, contextCache); UpdatePropertiesForMergedConfig(e); if (unmergedConfig.Context == joined) @@ -481,7 +459,7 @@ namespace Antlr4.Runtime.Atn dipsIntoOuterContext = false; hasSemanticContext = false; uniqueAlt = ATN.InvalidAltNumber; - conflictingAlts = null; + conflictInfo = null; } public override bool Equals(object obj) @@ -495,7 +473,7 @@ namespace Antlr4.Runtime.Atn return false; } Antlr4.Runtime.Atn.ATNConfigSet other = (Antlr4.Runtime.Atn.ATNConfigSet)obj; - return this.outermostConfigSet == other.outermostConfigSet && Utils.Equals(conflictingAlts, other.conflictingAlts) && configs.Equals(other.configs); + return this.outermostConfigSet == other.outermostConfigSet && Utils.Equals(conflictInfo, other.conflictInfo) && configs.Equals(other.configs); } public override int GetHashCode() @@ -523,7 +501,7 @@ namespace Antlr4.Runtime.Atn { StringBuilder buf = new StringBuilder(); IList sortedConfigs = new List(configs); - sortedConfigs.Sort(new _IComparer_495()); + sortedConfigs.Sort(new _IComparer_475()); buf.Append("["); for (int i = 0; i < sortedConfigs.Count; i++) { @@ -542,9 +520,13 @@ namespace Antlr4.Runtime.Atn { buf.Append(",uniqueAlt=").Append(uniqueAlt); } - if (conflictingAlts != null) + if (conflictInfo != null) { - buf.Append(",conflictingAlts=").Append(conflictingAlts); + buf.Append(",conflictingAlts=").Append(conflictInfo.ConflictedAlts); + if (!conflictInfo.IsExact) + { + buf.Append("*"); + } } if (dipsIntoOuterContext) { @@ -553,9 +535,9 @@ namespace Antlr4.Runtime.Atn return buf.ToString(); } - private sealed class _IComparer_495 : IComparer + private sealed class _IComparer_475 : IComparer { - public _IComparer_495() + public _IComparer_475() { } @@ -607,17 +589,41 @@ namespace Antlr4.Runtime.Atn hasSemanticContext = true; } + public virtual ConflictInfo ConflictInformation + { + get + { + return conflictInfo; + } + set + { + ConflictInfo conflictInfo = value; + EnsureWritable(); + this.conflictInfo = conflictInfo; + } + } + public virtual BitSet ConflictingAlts { get { - return conflictingAlts; + if (conflictInfo == null) + { + return null; + } + return conflictInfo.ConflictedAlts; } - set + } + + public virtual bool IsExactConflict + { + get { - BitSet conflictingAlts = value; - EnsureWritable(); - this.conflictingAlts = conflictingAlts; + if (conflictInfo == null) + { + return false; + } + return conflictInfo.IsExact; } } diff --git a/runtime/CSharp/Antlr4.Runtime/Atn/ATNDeserializer.cs b/runtime/CSharp/Antlr4.Runtime/Atn/ATNDeserializer.cs index e7b2bb974..352a83f91 100644 --- a/runtime/CSharp/Antlr4.Runtime/Atn/ATNDeserializer.cs +++ b/runtime/CSharp/Antlr4.Runtime/Atn/ATNDeserializer.cs @@ -354,7 +354,16 @@ namespace Antlr4.Runtime.Atn { continue; } - atn.ruleToStopState[ruleTransition.target.ruleIndex].AddTransition(new EpsilonTransition(ruleTransition.followState)); + int outermostPrecedenceReturn = -1; + if (atn.ruleToStartState[ruleTransition.target.ruleIndex].isPrecedenceRule) + { + if (ruleTransition.precedence == 0) + { + outermostPrecedenceReturn = ruleTransition.target.ruleIndex; + } + } + EpsilonTransition returnTransition = new EpsilonTransition(ruleTransition.followState, outermostPrecedenceReturn); + atn.ruleToStopState[ruleTransition.target.ruleIndex].AddTransition(returnTransition); } } foreach (ATNState state_2 in atn.states) @@ -847,7 +856,7 @@ namespace Antlr4.Runtime.Atn { Transition transition = state.GetOptimizedTransition(i); ATNState intermediate = transition.target; - if (transition.TransitionType != TransitionType.Epsilon || intermediate.StateType != StateType.Basic || !intermediate.OnlyHasEpsilonTransitions) + if (transition.TransitionType != TransitionType.Epsilon || ((EpsilonTransition)transition).OutermostPrecedenceReturn != -1 || intermediate.StateType != StateType.Basic || !intermediate.OnlyHasEpsilonTransitions) { if (optimizedTransitions != null) { @@ -857,7 +866,7 @@ namespace Antlr4.Runtime.Atn } for (int j = 0; j < intermediate.NumberOfOptimizedTransitions; j++) { - if (intermediate.GetOptimizedTransition(j).TransitionType != TransitionType.Epsilon) + if (intermediate.GetOptimizedTransition(j).TransitionType != TransitionType.Epsilon || ((EpsilonTransition)intermediate.GetOptimizedTransition(j)).OutermostPrecedenceReturn != -1) { if (optimizedTransitions != null) { diff --git a/runtime/CSharp/Antlr4.Runtime/Atn/ATNSimulator.cs b/runtime/CSharp/Antlr4.Runtime/Atn/ATNSimulator.cs index 3e8f2ab7c..bd406dae1 100644 --- a/runtime/CSharp/Antlr4.Runtime/Atn/ATNSimulator.cs +++ b/runtime/CSharp/Antlr4.Runtime/Atn/ATNSimulator.cs @@ -71,7 +71,7 @@ namespace Antlr4.Runtime.Atn static ATNSimulator() { - Error = new DFAState(new ATNConfigSet(), 0, 0); + Error = new DFAState(new EmptyEdgeMap(0, -1), new EmptyEdgeMap(0, -1), new ATNConfigSet()); Error.stateNumber = int.MaxValue; } diff --git a/runtime/CSharp/Antlr4.Runtime/Atn/ConflictInfo.cs b/runtime/CSharp/Antlr4.Runtime/Atn/ConflictInfo.cs new file mode 100644 index 000000000..049b001a9 --- /dev/null +++ b/runtime/CSharp/Antlr4.Runtime/Atn/ConflictInfo.cs @@ -0,0 +1,106 @@ +/* + * [The "BSD license"] + * Copyright (c) 2013 Terence Parr + * Copyright (c) 2013 Sam Harwell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using Antlr4.Runtime.Misc; +using Antlr4.Runtime.Sharpen; + +namespace Antlr4.Runtime.Atn +{ + /// This class stores information about a configuration conflict. + /// This class stores information about a configuration conflict. + /// Sam Harwell + public class ConflictInfo + { + private readonly BitSet conflictedAlts; + + private readonly bool exact; + + public ConflictInfo(BitSet conflictedAlts, bool exact) + { + this.conflictedAlts = conflictedAlts; + this.exact = exact; + } + + /// Gets the set of conflicting alternatives for the configuration set. + /// Gets the set of conflicting alternatives for the configuration set. + public BitSet ConflictedAlts + { + get + { + return conflictedAlts; + } + } + + /// Gets whether or not the configuration conflict is an exact conflict. + /// + /// Gets whether or not the configuration conflict is an exact conflict. + /// An exact conflict occurs when the prediction algorithm determines that + /// the represented alternatives for a particular configuration set cannot be + /// further reduced by consuming additional input. After reaching an exact + /// conflict during an SLL prediction, only switch to full-context prediction + /// could reduce the set of viable alternatives. In LL prediction, an exact + /// conflict indicates a true ambiguity in the input. + ///

+ /// For the + /// + /// prediction mode, + /// accept states are conflicting but not exact are treated as non-accept + /// states.

+ ///
+ public bool IsExact + { + get + { + return exact; + } + } + + public override bool Equals(object obj) + { + if (obj == this) + { + return true; + } + else + { + if (!(obj is Antlr4.Runtime.Atn.ConflictInfo)) + { + return false; + } + } + Antlr4.Runtime.Atn.ConflictInfo other = (Antlr4.Runtime.Atn.ConflictInfo)obj; + return IsExact == other.IsExact && Utils.Equals(ConflictedAlts, other.ConflictedAlts); + } + + public override int GetHashCode() + { + return ConflictedAlts.GetHashCode(); + } + } +} diff --git a/runtime/CSharp/Antlr4.Runtime/Atn/EpsilonTransition.cs b/runtime/CSharp/Antlr4.Runtime/Atn/EpsilonTransition.cs index 852f9c25d..da966c24b 100644 --- a/runtime/CSharp/Antlr4.Runtime/Atn/EpsilonTransition.cs +++ b/runtime/CSharp/Antlr4.Runtime/Atn/EpsilonTransition.cs @@ -35,9 +35,32 @@ namespace Antlr4.Runtime.Atn { public sealed class EpsilonTransition : Transition { + private readonly int outermostPrecedenceReturn; + public EpsilonTransition(ATNState target) + : this(target, -1) + { + } + + public EpsilonTransition(ATNState target, int outermostPrecedenceReturn) : base(target) { + this.outermostPrecedenceReturn = outermostPrecedenceReturn; + } + + /// + /// the rule index of a precedence rule for which this transition is + /// returning from, where the precedence value is 0; otherwise, -1. + /// + /// + /// + /// 4.4.1 + public int OutermostPrecedenceReturn + { + get + { + return outermostPrecedenceReturn; + } } public override Antlr4.Runtime.Atn.TransitionType TransitionType diff --git a/runtime/CSharp/Antlr4.Runtime/Atn/LexerATNSimulator.cs b/runtime/CSharp/Antlr4.Runtime/Atn/LexerATNSimulator.cs index 101cf476c..d3f2ac6ba 100644 --- a/runtime/CSharp/Antlr4.Runtime/Atn/LexerATNSimulator.cs +++ b/runtime/CSharp/Antlr4.Runtime/Atn/LexerATNSimulator.cs @@ -190,6 +190,13 @@ namespace Antlr4.Runtime.Atn protected internal virtual int ExecATN(ICharStream input, DFAState ds0) { //System.out.println("enter exec index "+input.index()+" from "+ds0.configs); + if (ds0.IsAcceptState) + { + // allow zero-length tokens + CaptureSimState(prevAccept, input, ds0); + // adjust index since the current input character was not yet consumed + prevAccept.index--; + } int t = input.La(1); DFAState s = ds0; // s is current/from DFA state @@ -222,7 +229,7 @@ namespace Antlr4.Runtime.Atn { break; } - if (target.isAcceptState) + if (target.IsAcceptState) { CaptureSimState(prevAccept, input, target); if (t == IntStreamConstants.Eof) @@ -318,9 +325,9 @@ namespace Antlr4.Runtime.Atn { if (prevAccept.dfaState != null) { - LexerActionExecutor lexerActionExecutor = prevAccept.dfaState.lexerActionExecutor; + LexerActionExecutor lexerActionExecutor = prevAccept.dfaState.LexerActionExecutor; Accept(input, lexerActionExecutor, startIndex, prevAccept.index, prevAccept.line, prevAccept.charPos); - return prevAccept.dfaState.prediction; + return prevAccept.dfaState.Prediction; } else { @@ -719,14 +726,14 @@ namespace Antlr4.Runtime.Atn protected internal virtual DFAState AddDFAState(ATNConfigSet configs) { System.Diagnostics.Debug.Assert(!configs.HasSemanticContext); - DFAState proposed = new DFAState(configs, 0, MaxDfaEdge); + DFAState proposed = new DFAState(atn.modeToDFA[mode], configs); DFAState existing = atn.modeToDFA[mode].states.Get(proposed); if (existing != null) { return existing; } configs.OptimizeConfigs(this); - DFAState newState = new DFAState(configs.Clone(true), 0, MaxDfaEdge); + DFAState newState = new DFAState(atn.modeToDFA[mode], configs.Clone(true)); ATNConfig firstConfigWithRuleStopState = null; foreach (ATNConfig c in configs) { @@ -738,9 +745,9 @@ namespace Antlr4.Runtime.Atn } if (firstConfigWithRuleStopState != null) { - newState.isAcceptState = true; - newState.lexerActionExecutor = firstConfigWithRuleStopState.ActionExecutor; - newState.prediction = atn.ruleToTokenType[firstConfigWithRuleStopState.State.ruleIndex]; + int prediction = atn.ruleToTokenType[firstConfigWithRuleStopState.State.ruleIndex]; + LexerActionExecutor lexerActionExecutor = firstConfigWithRuleStopState.ActionExecutor; + newState.AcceptStateInfo = new AcceptStateInfo(prediction, lexerActionExecutor); } return atn.modeToDFA[mode].AddState(newState); } diff --git a/runtime/CSharp/Antlr4.Runtime/Atn/ParserATNSimulator.cs b/runtime/CSharp/Antlr4.Runtime/Atn/ParserATNSimulator.cs index 567bed8ea..0a5b404ba 100644 --- a/runtime/CSharp/Antlr4.Runtime/Atn/ParserATNSimulator.cs +++ b/runtime/CSharp/Antlr4.Runtime/Atn/ParserATNSimulator.cs @@ -341,6 +341,7 @@ namespace Antlr4.Runtime.Atn public bool optimize_ll1 = true; + [System.ObsoleteAttribute(@"This flag is not currently used by the ATN simulator.")] public bool optimize_hidden_conflicted_configs = false; public bool optimize_tail_calls = true; @@ -386,6 +387,8 @@ namespace Antlr4.Runtime.Atn /// protected internal bool userWantsCtxSensitive = true; + private DFA dfa; + /// Testing only! public ParserATNSimulator(ATN atn) : this(null, atn) @@ -437,6 +440,7 @@ namespace Antlr4.Runtime.Atn } } } + this.dfa = dfa; if (force_global_context) { useContext = true; @@ -475,6 +479,7 @@ namespace Antlr4.Runtime.Atn } finally { + this.dfa = null; input.Seek(index); input.Release(m); } @@ -568,7 +573,7 @@ namespace Antlr4.Runtime.Atn s = next; } } - if (s.isAcceptState) + if (IsAcceptState(s, state.useContext)) { if (s.predicates != null) { @@ -580,14 +585,14 @@ namespace Antlr4.Runtime.Atn break; } // t is not updated if one of these states is reached - System.Diagnostics.Debug.Assert(!s.isAcceptState); + System.Diagnostics.Debug.Assert(!IsAcceptState(s, state.useContext)); // if no edge, pop over to ATN interpreter, update DFA and return DFAState target = GetExistingTargetState(s, t); if (target == null) { if (dfa_debug && t >= 0) { - System.Console.Out.WriteLine("no edge for " + parser.TokenNames[t]); + System.Console.Out.WriteLine("no edge for " + parser.Vocabulary.GetDisplayName(t)); } int alt; SimulatorState initialState = new SimulatorState(outerContext, s, state.useContext, remainingOuterContext); @@ -606,7 +611,7 @@ namespace Antlr4.Runtime.Atn } } s = target; - if (!s.isAcceptState && t != IntStreamConstants.Eof) + if (!IsAcceptState(s, state.useContext) && t != IntStreamConstants.Eof) { input.Consume(); t = input.La(1); @@ -616,11 +621,11 @@ namespace Antlr4.Runtime.Atn // if ( debug ) System.out.println("!!! no viable alt in dfa"); // return -1; // } - if (s.configs.ConflictingAlts != null) + if (!state.useContext && s.configs.ConflictInformation != null) { if (dfa.atnStartState is DecisionState) { - if (!userWantsCtxSensitive || !s.configs.DipsIntoOuterContext || (treat_sllk1_conflict_as_ambiguity && input.Index == startIndex)) + if (!userWantsCtxSensitive || (!s.configs.DipsIntoOuterContext && s.configs.IsExactConflict) || (treat_sllk1_conflict_as_ambiguity && input.Index == startIndex)) { } else @@ -695,12 +700,82 @@ namespace Antlr4.Runtime.Atn { input.Seek(stopIndex); } - ReportAmbiguity(dfa, s, startIndex, stopIndex, predictionMode == Antlr4.Runtime.Atn.PredictionMode.LlExactAmbigDetection, alts, s.configs); + ReportAmbiguity(dfa, s, startIndex, stopIndex, s.configs.IsExactConflict, alts, s.configs); return alts.NextSetBit(0); } } } - return s.prediction; + return s.Prediction; + } + + /// + /// Determines if a particular DFA state should be treated as an accept state + /// for the current prediction mode. + /// + /// + /// Determines if a particular DFA state should be treated as an accept state + /// for the current prediction mode. In addition to the + /// + /// parameter, the + /// + /// method provides the + /// prediction mode controlling the prediction algorithm as a whole. + ///

+ /// The default implementation simply returns the value of + /// + /// except for conflict states when + /// + /// is + /// + /// and + /// + /// is + /// + /// . In that case, only + /// conflict states where + /// + /// is + /// + /// are considered accept states. + ///

+ ///
+ /// The DFA state to check. + /// + /// + /// + /// if the prediction algorithm is currently + /// considering the full parser context; otherwise, + /// + /// if the + /// algorithm is currently performing a local context prediction. + /// + /// + /// + /// + /// if the specified + /// + /// is an accept state; + /// otherwise, + /// + /// . + /// + protected internal virtual bool IsAcceptState(DFAState state, bool useContext) + { + if (!state.IsAcceptState) + { + return false; + } + if (state.configs.ConflictingAlts == null) + { + // unambiguous + return true; + } + // More picky when we need exact conflicts + if (useContext && predictionMode == Antlr4.Runtime.Atn.PredictionMode.LlExactAmbigDetection) + { + return state.configs.IsExactConflict; + } + return true; } /// @@ -764,13 +839,13 @@ namespace Antlr4.Runtime.Atn } DFAState D = nextState.s0; // predicted alt => accept state - System.Diagnostics.Debug.Assert(D.isAcceptState || GetUniqueAlt(D.configs) == ATN.InvalidAltNumber); + System.Diagnostics.Debug.Assert(D.IsAcceptState || D.Prediction == ATN.InvalidAltNumber); // conflicted => accept state - System.Diagnostics.Debug.Assert(D.isAcceptState || D.configs.ConflictingAlts == null); - if (D.isAcceptState) + System.Diagnostics.Debug.Assert(D.IsAcceptState || D.configs.ConflictInformation == null); + if (IsAcceptState(D, useContext)) { BitSet conflictingAlts = D.configs.ConflictingAlts; - int predictedAlt = conflictingAlts == null ? GetUniqueAlt(D.configs) : ATN.InvalidAltNumber; + int predictedAlt = conflictingAlts == null ? D.Prediction : ATN.InvalidAltNumber; if (predictedAlt != ATN.InvalidAltNumber) { if (optimize_ll1 && input.Index == startIndex && !dfa.IsPrecedenceDfa && nextState.outerContext == nextState.remainingOuterContext && dfa.decision >= 0 && !D.configs.HasSemanticContext) @@ -786,20 +861,15 @@ namespace Antlr4.Runtime.Atn ReportContextSensitivity(dfa, predictedAlt, nextState, startIndex, input.Index); } } - predictedAlt = D.prediction; + predictedAlt = D.Prediction; // int k = input.index() - startIndex + 1; // how much input we used // System.out.println("used k="+k); bool attemptFullContext = conflictingAlts != null && userWantsCtxSensitive; if (attemptFullContext) { - if (predictionMode == Antlr4.Runtime.Atn.PredictionMode.LlExactAmbigDetection) - { - attemptFullContext = !useContext && (D.configs.DipsIntoOuterContext || D.configs.ConflictingAlts.Cardinality() > 2) && (!treat_sllk1_conflict_as_ambiguity || input.Index != startIndex); - } - else - { - attemptFullContext = D.configs.DipsIntoOuterContext && (!treat_sllk1_conflict_as_ambiguity || input.Index != startIndex); - } + // Only exact conflicts are known to be ambiguous when local + // prediction does not step out of the decision rule. + attemptFullContext = !useContext && (D.configs.DipsIntoOuterContext || !D.configs.IsExactConflict) && (!treat_sllk1_conflict_as_ambiguity || input.Index != startIndex); } if (D.configs.HasSemanticContext) { @@ -844,7 +914,7 @@ namespace Antlr4.Runtime.Atn { if (reportAmbiguities && conflictingAlts.Cardinality() > 1) { - ReportAmbiguity(dfa, D, startIndex, input.Index, predictionMode == Antlr4.Runtime.Atn.PredictionMode.LlExactAmbigDetection, conflictingAlts, D.configs); + ReportAmbiguity(dfa, D, startIndex, input.Index, D.configs.IsExactConflict, conflictingAlts, D.configs); } predictedAlt = conflictingAlts.NextSetBit(0); } @@ -853,7 +923,7 @@ namespace Antlr4.Runtime.Atn else { System.Diagnostics.Debug.Assert(!useContext); - System.Diagnostics.Debug.Assert(D.isAcceptState); + System.Diagnostics.Debug.Assert(IsAcceptState(D, false)); SimulatorState fullContextState = ComputeStartState(dfa, outerContext, true); if (reportAmbiguities) { @@ -1055,8 +1125,8 @@ namespace Antlr4.Runtime.Atn s = next; } } - System.Diagnostics.Debug.Assert(!s.isAcceptState); - if (s.isAcceptState) + System.Diagnostics.Debug.Assert(!IsAcceptState(s, useContext)); + if (IsAcceptState(s, useContext)) { return new SimulatorState(previous.outerContext, s, useContext, remainingGlobalContext); } @@ -1357,6 +1427,16 @@ namespace Antlr4.Runtime.Atn { configs.IsOutermostConfigSet = true; } + if (!useContext || enable_global_context_dfa) + { + if (!dfa.IsPrecedenceDfa && dfa.atnStartState is StarLoopEntryState) + { + if (((StarLoopEntryState)dfa.atnStartState).precedenceRuleDecision) + { + dfa.IsPrecedenceDfa = true; + } + } + } bool collectPredicates = true; Closure(reachIntermediate, configs, collectPredicates, hasMoreContext, contextCache, false); bool stepIntoGlobal = configs.DipsIntoOuterContext; @@ -1370,13 +1450,6 @@ namespace Antlr4.Runtime.Atn { if (s0 == null) { - if (!dfa.IsPrecedenceDfa && dfa.atnStartState is StarLoopEntryState) - { - if (((StarLoopEntryState)dfa.atnStartState).precedenceRuleDecision) - { - dfa.IsPrecedenceDfa = true; - } - } if (!dfa.IsPrecedenceDfa) { AtomicReference reference = useContext ? dfa.s0full : dfa.s0; @@ -1441,8 +1514,13 @@ namespace Antlr4.Runtime.Atn ///
  • Evaluate the precedence predicates for each configuration using /// /// .
  • - ///
  • Remove all configurations which predict an alternative greater than - /// 1, for which another configuration that predicts alternative 1 is in the + ///
  • When + /// + /// is + /// + /// , + /// remove all configurations which predict an alternative greater than 1, + /// for which another configuration that predicts alternative 1 is in the /// same ATN state with the same prediction context. This transformation is /// valid for the following reasons: ///
      @@ -1454,7 +1532,11 @@ namespace Antlr4.Runtime.Atn /// epsilon transition, so the only way an alternative other than 1 can exist /// in a state that is also reachable via alternative 1 is by nesting calls /// to the left-recursive rule, with the outer calls not being at the - /// preferred precedence level. + /// preferred precedence level. The + /// + /// property marks ATN + /// configurations which do not meet this condition, and therefore are not + /// eligible for elimination during the filtering process. ///
    ///
  • /// @@ -1535,11 +1617,14 @@ namespace Antlr4.Runtime.Atn // already handled continue; } - PredictionContext context = statesFromAlt1.Get(config_1.State.stateNumber); - if (context != null && context.Equals(config_1.Context)) + if (!config_1.PrecedenceFilterSuppressed) { - // eliminated - continue; + PredictionContext context = statesFromAlt1.Get(config_1.State.stateNumber); + if (context != null && context.Equals(config_1.Context)) + { + // eliminated + continue; + } } configSet.Add(config_1, contextCache); } @@ -1569,9 +1654,7 @@ namespace Antlr4.Runtime.Atn // Update DFA so reach becomes accept state with predicate predPredictions = GetPredicatePredictions(conflictingAlts, altToPred); D.predicates = predPredictions; - D.prediction = ATN.InvalidAltNumber; } - // make sure we use preds return predPredictions; } @@ -1767,6 +1850,7 @@ namespace Antlr4.Runtime.Atn // gotten that context AFTER having fallen off a rule. // Make sure we track that we are now out of context. c.OuterContextDepth = config.OuterContextDepth; + c.PrecedenceFilterSuppressed = config.PrecedenceFilterSuppressed; System.Diagnostics.Debug.Assert(depth > int.MinValue); Closure(c, configs, intermediate, closureBusy, collectPredicates, hasMoreContexts, contextCache, depth - 1, treatEofAsEpsilon); } @@ -1791,6 +1875,14 @@ namespace Antlr4.Runtime.Atn // no need to keep full context overhead when we step out config = config.Transform(config.State, PredictionContext.EmptyLocal, false); } + else + { + if (!config.ReachesIntoOuterContext && PredictionContext.IsEmptyLocal(config.Context)) + { + // add stop state when leaving decision rule for the first time + configs.Add(config, contextCache); + } + } } } } @@ -1835,6 +1927,14 @@ namespace Antlr4.Runtime.Atn // avoid infinite recursion for right-recursive rules continue; } + if (dfa != null && dfa.IsPrecedenceDfa) + { + int outermostPrecedenceReturn = ((EpsilonTransition)t).OutermostPrecedenceReturn; + if (outermostPrecedenceReturn == dfa.atnStartState.ruleIndex) + { + c.PrecedenceFilterSuppressed = true; + } + } c.OuterContextDepth = c.OuterContextDepth + 1; System.Diagnostics.Debug.Assert(newDepth > int.MinValue); newDepth--; @@ -1997,9 +2097,9 @@ namespace Antlr4.Runtime.Atn return config.Transform(t.target, newContext, false); } - private sealed class _IComparer_1928 : IComparer + private sealed class _IComparer_1996 : IComparer { - public _IComparer_1928() + public _IComparer_1996() { } @@ -2019,9 +2119,9 @@ namespace Antlr4.Runtime.Atn } } - private static readonly IComparer StateAltSortComparator = new _IComparer_1928(); + private static readonly IComparer StateAltSortComparator = new _IComparer_1996(); - private BitSet IsConflicted(ATNConfigSet configset, PredictionContextCache contextCache) + private ConflictInfo IsConflicted(ATNConfigSet configset, PredictionContextCache contextCache) { if (configset.UniqueAlt != ATN.InvalidAltNumber || configset.Count <= 1) { @@ -2029,7 +2129,7 @@ namespace Antlr4.Runtime.Atn } IList configs = new List(configset); configs.Sort(StateAltSortComparator); - bool exact = !configset.DipsIntoOuterContext && predictionMode == Antlr4.Runtime.Atn.PredictionMode.LlExactAmbigDetection; + bool exact = !configset.DipsIntoOuterContext; BitSet alts = new BitSet(); int minAlt = configs[0].Alt; alts.Set(minAlt); @@ -2077,7 +2177,8 @@ namespace Antlr4.Runtime.Atn { if (currentAlt != maxAlt) { - return null; + exact = false; + break; } currentState = stateNumber; currentAlt = minAlt; @@ -2088,7 +2189,8 @@ namespace Antlr4.Runtime.Atn { if (alt != representedAlts.NextSetBit(currentAlt + 1)) { - return null; + exact = false; + break; } currentAlt = alt; } @@ -2159,43 +2261,15 @@ namespace Antlr4.Runtime.Atn joinedCheckContext2 = contextCache.Join(joinedCheckContext2, config2.Context); } i_1 = lastIndexCurrentStateCurrentAlt; - if (exact) + PredictionContext check = contextCache.Join(joinedCheckContext, joinedCheckContext2); + if (!joinedCheckContext.Equals(check)) { - if (!joinedCheckContext.Equals(joinedCheckContext2)) - { - return null; - } - } - else - { - PredictionContext check = contextCache.Join(joinedCheckContext, joinedCheckContext2); - if (!joinedCheckContext.Equals(check)) - { - return null; - } - } - if (!exact && optimize_hidden_conflicted_configs) - { - for (int j = firstIndexCurrentState; j_1 <= lastIndexCurrentStateMinAlt; j_1++) - { - ATNConfig checkConfig = configs[j_1]; - if (checkConfig.SemanticContext != SemanticContext.None && !checkConfig.SemanticContext.Equals(config_1.SemanticContext)) - { - continue; - } - if (joinedCheckContext != checkConfig.Context) - { - PredictionContext check = contextCache.Join(checkConfig.Context, config_1.Context); - if (!checkConfig.Context.Equals(check)) - { - continue; - } - } - config_1.IsHidden = true; - } + return null; } + // update exact if necessary + exact = exact && joinedCheckContext.Equals(joinedCheckContext2); } - return alts; + return new ConflictInfo(alts, exact); } protected internal virtual BitSet GetConflictingAltsFromConfigSet(ATNConfigSet configs) @@ -2209,14 +2283,6 @@ namespace Antlr4.Runtime.Atn return conflictingAlts; } - protected internal virtual int ResolveToMinAlt(DFAState D, BitSet conflictingAlts) - { - // kill dead alts so we don't chase them ever - // killAlts(conflictingAlts, D.configset); - D.prediction = conflictingAlts.NextSetBit(0); - return D.prediction; - } - [NotNull] public virtual string GetTokenName(int t) { @@ -2224,20 +2290,13 @@ namespace Antlr4.Runtime.Atn { return "EOF"; } - if (parser != null && parser.TokenNames != null) + IVocabulary vocabulary = parser != null ? parser.Vocabulary : Vocabulary.EmptyVocabulary; + string displayName = vocabulary.GetDisplayName(t); + if (displayName.Equals(Antlr4.Runtime.Sharpen.Extensions.ToString(t))) { - string[] tokensNames = parser.TokenNames; - if (t >= tokensNames.Length) - { - System.Console.Error.WriteLine(t + " ttype out of range: " + Arrays.ToString(tokensNames)); - System.Console.Error.WriteLine(((CommonTokenStream)((ITokenStream)parser.InputStream)).GetTokens()); - } - else - { - return tokensNames[t] + "<" + t + ">"; - } + return displayName; } - return t.ToString(); + return displayName + "<" + t + ">"; } public virtual string GetLookaheadName(ITokenStream input) @@ -2393,7 +2452,7 @@ namespace Antlr4.Runtime.Atn { configs.OptimizeConfigs(this); } - DFAState proposed = CreateDFAState(configs); + DFAState proposed = CreateDFAState(dfa, configs); DFAState existing = dfa.states.Get(proposed); if (existing != null) { @@ -2402,42 +2461,26 @@ namespace Antlr4.Runtime.Atn } if (!configs.IsReadOnly) { - if (configs.ConflictingAlts == null) + if (configs.ConflictInformation == null) { - configs.ConflictingAlts = IsConflicted(configs, contextCache); - if (optimize_hidden_conflicted_configs && configs.ConflictingAlts != null) - { - int size = configs.Count; - configs.StripHiddenConfigs(); - if (enableDfa && configs.Count < size) - { - DFAState proposed = CreateDFAState(configs); - DFAState existing = dfa.states.Get(proposed); - if (existing != null) - { - return existing; - } - } - } + configs.ConflictInformation = IsConflicted(configs, contextCache); } } - DFAState newState = CreateDFAState(configs.Clone(true)); + DFAState newState = CreateDFAState(dfa, configs.Clone(true)); DecisionState decisionState = atn.GetDecisionState(dfa.decision); int predictedAlt = GetUniqueAlt(configs); if (predictedAlt != ATN.InvalidAltNumber) { - newState.isAcceptState = true; - newState.prediction = predictedAlt; + newState.AcceptStateInfo = new AcceptStateInfo(predictedAlt); } else { if (configs.ConflictingAlts != null) { - newState.isAcceptState = true; - newState.prediction = ResolveToMinAlt(newState, newState.configs.ConflictingAlts); + newState.AcceptStateInfo = new AcceptStateInfo(newState.configs.ConflictingAlts.NextSetBit(0)); } } - if (newState.isAcceptState && configs.HasSemanticContext) + if (newState.IsAcceptState && configs.HasSemanticContext) { PredicateDFAState(newState, configs, decisionState.NumberOfTransitions); } @@ -2454,9 +2497,9 @@ namespace Antlr4.Runtime.Atn } [NotNull] - protected internal virtual DFAState CreateDFAState(ATNConfigSet configs) + protected internal virtual DFAState CreateDFAState(DFA dfa, ATNConfigSet configs) { - return new DFAState(configs, -1, atn.maxTokenType); + return new DFAState(dfa, configs); } protected internal virtual void ReportAttemptingFullContext(DFA dfa, BitSet conflictingAlts, SimulatorState conflictState, int startIndex, int stopIndex) diff --git a/runtime/CSharp/Antlr4.Runtime/Atn/ProfilingATNSimulator.cs b/runtime/CSharp/Antlr4.Runtime/Atn/ProfilingATNSimulator.cs index 5f4da44ba..a519421b0 100644 --- a/runtime/CSharp/Antlr4.Runtime/Atn/ProfilingATNSimulator.cs +++ b/runtime/CSharp/Antlr4.Runtime/Atn/ProfilingATNSimulator.cs @@ -91,7 +91,8 @@ namespace Antlr4.Runtime.Atn { this._input = input; this._startIndex = input.Index; - this._sllStopIndex = -1; + // it's possible for SLL to reach a conflict state without consuming any input + this._sllStopIndex = _startIndex - 1; this._llStopIndex = -1; this.currentDecision = decision; this.currentState = null; diff --git a/runtime/CSharp/Antlr4.Runtime/DefaultErrorStrategy.cs b/runtime/CSharp/Antlr4.Runtime/DefaultErrorStrategy.cs index 3ffd3547a..1bab12679 100644 --- a/runtime/CSharp/Antlr4.Runtime/DefaultErrorStrategy.cs +++ b/runtime/CSharp/Antlr4.Runtime/DefaultErrorStrategy.cs @@ -376,7 +376,7 @@ namespace Antlr4.Runtime /// the recognition exception protected internal virtual void ReportInputMismatch(Parser recognizer, InputMismatchException e) { - string msg = "mismatched input " + GetTokenErrorDisplay(e.OffendingToken) + " expecting " + e.GetExpectedTokens().ToString(recognizer.TokenNames); + string msg = "mismatched input " + GetTokenErrorDisplay(e.OffendingToken) + " expecting " + e.GetExpectedTokens().ToString(recognizer.Vocabulary); NotifyErrorListeners(recognizer, msg, e); } @@ -434,7 +434,7 @@ namespace Antlr4.Runtime IToken t = recognizer.CurrentToken; string tokenName = GetTokenErrorDisplay(t); IntervalSet expecting = GetExpectedTokens(recognizer); - string msg = "extraneous input " + tokenName + " expecting " + expecting.ToString(recognizer.TokenNames); + string msg = "extraneous input " + tokenName + " expecting " + expecting.ToString(recognizer.Vocabulary); recognizer.NotifyErrorListeners(t, msg, null); } @@ -472,7 +472,7 @@ namespace Antlr4.Runtime BeginErrorCondition(recognizer); IToken t = recognizer.CurrentToken; IntervalSet expecting = GetExpectedTokens(recognizer); - string msg = "missing " + expecting.ToString(recognizer.TokenNames) + " at " + GetTokenErrorDisplay(t); + string msg = "missing " + expecting.ToString(recognizer.Vocabulary) + " at " + GetTokenErrorDisplay(t); recognizer.NotifyErrorListeners(t, msg, null); } @@ -713,7 +713,7 @@ namespace Antlr4.Runtime } else { - tokenText = ""; + tokenText = ""; } IToken current = currentSymbol; IToken lookback = ((ITokenStream)recognizer.InputStream).Lt(-1); diff --git a/runtime/CSharp/Antlr4.Runtime/Dfa/AcceptStateInfo.cs b/runtime/CSharp/Antlr4.Runtime/Dfa/AcceptStateInfo.cs new file mode 100644 index 000000000..823ea44d3 --- /dev/null +++ b/runtime/CSharp/Antlr4.Runtime/Dfa/AcceptStateInfo.cs @@ -0,0 +1,96 @@ +/* + * [The "BSD license"] + * Copyright (c) 2013 Terence Parr + * Copyright (c) 2013 Sam Harwell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using Antlr4.Runtime.Sharpen; + +namespace Antlr4.Runtime.Dfa +{ + /// + /// Stores information about a + /// + /// which is an accept state under + /// some condition. Certain settings, such as + /// + /// , may be used in addition to + /// this information to determine whether or not a particular state is an accept + /// state. + /// + /// Sam Harwell + public class AcceptStateInfo + { + private readonly int prediction; + + private readonly Antlr4.Runtime.Atn.LexerActionExecutor lexerActionExecutor; + + public AcceptStateInfo(int prediction) + { + this.prediction = prediction; + this.lexerActionExecutor = null; + } + + public AcceptStateInfo(int prediction, Antlr4.Runtime.Atn.LexerActionExecutor lexerActionExecutor) + { + this.prediction = prediction; + this.lexerActionExecutor = lexerActionExecutor; + } + + /// Gets the prediction made by this accept state. + /// + /// Gets the prediction made by this accept state. Note that this value + /// assumes the predicates, if any, in the + /// + /// evaluate to + /// + /// . If predicate evaluation is enabled, the final prediction of + /// the accept state will be determined by the result of predicate + /// evaluation. + /// + public virtual int Prediction + { + get + { + return prediction; + } + } + + /// + /// Gets the + /// + /// which can be used to execute actions + /// and/or commands after the lexer matches a token. + /// + public virtual Antlr4.Runtime.Atn.LexerActionExecutor LexerActionExecutor + { + get + { + return lexerActionExecutor; + } + } + } +} diff --git a/runtime/CSharp/Antlr4.Runtime/Dfa/ArrayEdgeMap`1.cs b/runtime/CSharp/Antlr4.Runtime/Dfa/ArrayEdgeMap`1.cs index f6ab12454..a8f337b72 100644 --- a/runtime/CSharp/Antlr4.Runtime/Dfa/ArrayEdgeMap`1.cs +++ b/runtime/CSharp/Antlr4.Runtime/Dfa/ArrayEdgeMap`1.cs @@ -34,24 +34,25 @@ using Antlr4.Runtime.Sharpen; namespace Antlr4.Runtime.Dfa { - /// sam - public class ArrayEdgeMap : AbstractEdgeMap + /// Sam Harwell + public sealed class ArrayEdgeMap : AbstractEdgeMap { - private readonly T[] arrayData; + private readonly AtomicReferenceArray arrayData; - private int size; + private readonly AtomicInteger size; public ArrayEdgeMap(int minIndex, int maxIndex) : base(minIndex, maxIndex) { - arrayData = (T[])new object[maxIndex - minIndex + 1]; + arrayData = new AtomicReferenceArray(maxIndex - minIndex + 1); + size = new AtomicInteger(); } public override int Count { get { - return size; + return size.Get(); } } @@ -59,7 +60,7 @@ namespace Antlr4.Runtime.Dfa { get { - return size == 0; + return Count == 0; } } @@ -76,7 +77,7 @@ namespace Antlr4.Runtime.Dfa { return null; } - return arrayData[key - minIndex]; + return arrayData.Get(key - minIndex); } } @@ -84,17 +85,16 @@ namespace Antlr4.Runtime.Dfa { if (key >= minIndex && key <= maxIndex) { - T existing = arrayData[key - minIndex]; - arrayData[key - minIndex] = value; + T existing = arrayData.GetAndSet(key - minIndex, value); if (existing == null && value != null) { - size++; + size.IncrementAndGet(); } else { if (existing != null && value == null) { - size--; + size.DecrementAndGet(); } } } @@ -117,17 +117,12 @@ namespace Antlr4.Runtime.Dfa Antlr4.Runtime.Dfa.ArrayEdgeMap other = (Antlr4.Runtime.Dfa.ArrayEdgeMap)m; int minOverlap = Math.Max(minIndex, other.minIndex); int maxOverlap = Math.Min(maxIndex, other.maxIndex); + Antlr4.Runtime.Dfa.ArrayEdgeMap result = this; for (int i = minOverlap; i <= maxOverlap; i++) { - T target = other.arrayData[i - other.minIndex]; - if (target != null) - { - T current = this.arrayData[i - this.minIndex]; - this.arrayData[i - this.minIndex] = target; - size += (current != null ? 0 : 1); - } + result = ((Antlr4.Runtime.Dfa.ArrayEdgeMap)result.Put(i, m[i])); } - return this; + return result; } else { @@ -142,14 +137,17 @@ namespace Antlr4.Runtime.Dfa if (m is SparseEdgeMap) { SparseEdgeMap other = (SparseEdgeMap)m; - int[] keys = other.Keys; - IList values = other.Values; - Antlr4.Runtime.Dfa.ArrayEdgeMap result = this; - for (int i = 0; i < values.Count; i++) + lock (other) { - result = ((Antlr4.Runtime.Dfa.ArrayEdgeMap)result.Put(keys[i], values[i])); + int[] keys = other.Keys; + IList values = other.Values; + Antlr4.Runtime.Dfa.ArrayEdgeMap result = this; + for (int i = 0; i < values.Count; i++) + { + result = ((Antlr4.Runtime.Dfa.ArrayEdgeMap)result.Put(keys[i], values[i])); + } + return result; } - return result; } else { @@ -161,8 +159,7 @@ namespace Antlr4.Runtime.Dfa public override AbstractEdgeMap Clear() { - Arrays.Fill(arrayData, null); - return this; + return new EmptyEdgeMap(minIndex, maxIndex); } public override IDictionary ToMap() @@ -172,13 +169,14 @@ namespace Antlr4.Runtime.Dfa return Antlr4.Runtime.Sharpen.Collections.EmptyMap(); } IDictionary result = new LinkedHashMap(); - for (int i = 0; i < arrayData.Length; i++) + for (int i = 0; i < arrayData.Length(); i++) { - if (arrayData[i] == null) + T element = arrayData.Get(i); + if (element == null) { continue; } - result.Put(i + minIndex, arrayData[i]); + result.Put(i + minIndex, element); } return result; } diff --git a/runtime/CSharp/Antlr4.Runtime/Dfa/DFA.cs b/runtime/CSharp/Antlr4.Runtime/Dfa/DFA.cs index dbaea1a88..a86688e81 100644 --- a/runtime/CSharp/Antlr4.Runtime/Dfa/DFA.cs +++ b/runtime/CSharp/Antlr4.Runtime/Dfa/DFA.cs @@ -29,6 +29,7 @@ */ using System; using System.Collections.Concurrent; +using Antlr4.Runtime; using Antlr4.Runtime.Atn; using Antlr4.Runtime.Dfa; using Antlr4.Runtime.Misc; @@ -64,6 +65,19 @@ namespace Antlr4.Runtime.Dfa private readonly AtomicInteger nextStateNumber = new AtomicInteger(); + private readonly int minDfaEdge; + + private readonly int maxDfaEdge; + + [NotNull] + private static readonly Antlr4.Runtime.Dfa.EmptyEdgeMap emptyPrecedenceEdges = new Antlr4.Runtime.Dfa.EmptyEdgeMap(0, 200); + + [NotNull] + private readonly Antlr4.Runtime.Dfa.EmptyEdgeMap emptyEdgeMap; + + [NotNull] + private readonly Antlr4.Runtime.Dfa.EmptyEdgeMap emptyContextEdgeMap; + /// /// /// if this DFA is for a precedence decision; otherwise, @@ -85,6 +99,50 @@ namespace Antlr4.Runtime.Dfa { this.atnStartState = atnStartState; this.decision = decision; + if (this.atnStartState.atn.grammarType == ATNType.Lexer) + { + minDfaEdge = LexerATNSimulator.MinDfaEdge; + maxDfaEdge = LexerATNSimulator.MaxDfaEdge; + } + else + { + minDfaEdge = TokenConstants.Eof; + maxDfaEdge = atnStartState.atn.maxTokenType; + } + this.emptyEdgeMap = new Antlr4.Runtime.Dfa.EmptyEdgeMap(minDfaEdge, maxDfaEdge); + this.emptyContextEdgeMap = new Antlr4.Runtime.Dfa.EmptyEdgeMap(-1, atnStartState.atn.states.Count - 1); + } + + public int MinDfaEdge + { + get + { + return minDfaEdge; + } + } + + public int MaxDfaEdge + { + get + { + return maxDfaEdge; + } + } + + public virtual Antlr4.Runtime.Dfa.EmptyEdgeMap EmptyEdgeMap + { + get + { + return emptyEdgeMap; + } + } + + public virtual Antlr4.Runtime.Dfa.EmptyEdgeMap EmptyContextEdgeMap + { + get + { + return emptyContextEdgeMap; + } } /// Gets whether this DFA is a precedence DFA. @@ -161,12 +219,8 @@ namespace Antlr4.Runtime.Dfa this.states.Clear(); if (precedenceDfa) { - DFAState precedenceState = new DFAState(new ATNConfigSet(), 0, 200); - precedenceState.isAcceptState = false; - this.s0.Set(precedenceState); - DFAState fullContextPrecedenceState = new DFAState(new ATNConfigSet(), 0, 200); - fullContextPrecedenceState.isAcceptState = false; - this.s0full.Set(fullContextPrecedenceState); + this.s0.Set(new DFAState(emptyPrecedenceEdges, EmptyContextEdgeMap, new ATNConfigSet())); + this.s0full.Set(new DFAState(emptyPrecedenceEdges, EmptyContextEdgeMap, new ATNConfigSet())); } else { @@ -277,9 +331,10 @@ namespace Antlr4.Runtime.Dfa public override string ToString() { - return ToString(null); + return ToString(Vocabulary.EmptyVocabulary); } + [System.ObsoleteAttribute(@"Use ToString(Antlr4.Runtime.IVocabulary) instead.")] public virtual string ToString(string[] tokenNames) { if (s0.Get() == null) @@ -290,6 +345,17 @@ namespace Antlr4.Runtime.Dfa return serializer.ToString(); } + public virtual string ToString(IVocabulary vocabulary) + { + if (s0.Get() == null) + { + return string.Empty; + } + DFASerializer serializer = new DFASerializer(this, vocabulary); + return serializer.ToString(); + } + + [System.ObsoleteAttribute(@"Use ToString(Antlr4.Runtime.IVocabulary, string[]) instead.")] public virtual string ToString(string[] tokenNames, string[] ruleNames) { if (s0.Get() == null) @@ -300,6 +366,16 @@ namespace Antlr4.Runtime.Dfa return serializer.ToString(); } + public virtual string ToString(IVocabulary vocabulary, string[] ruleNames) + { + if (s0.Get() == null) + { + return string.Empty; + } + DFASerializer serializer = new DFASerializer(this, vocabulary, ruleNames, atnStartState.atn); + return serializer.ToString(); + } + public virtual string ToLexerString() { if (s0.Get() == null) diff --git a/runtime/CSharp/Antlr4.Runtime/Dfa/DFASerializer.cs b/runtime/CSharp/Antlr4.Runtime/Dfa/DFASerializer.cs index ab96f8c18..47b9aef3c 100644 --- a/runtime/CSharp/Antlr4.Runtime/Dfa/DFASerializer.cs +++ b/runtime/CSharp/Antlr4.Runtime/Dfa/DFASerializer.cs @@ -27,6 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System; using System.Collections.Generic; using System.Text; using Antlr4.Runtime; @@ -42,10 +43,10 @@ namespace Antlr4.Runtime.Dfa public class DFASerializer { [NotNull] - internal readonly DFA dfa; + private readonly DFA dfa; - [Nullable] - internal readonly string[] tokenNames; + [NotNull] + private readonly IVocabulary vocabulary; [Nullable] internal readonly string[] ruleNames; @@ -53,20 +54,32 @@ namespace Antlr4.Runtime.Dfa [Nullable] internal readonly ATN atn; + [System.ObsoleteAttribute(@"Use DFASerializer(DFA, Antlr4.Runtime.IVocabulary) instead.")] public DFASerializer(DFA dfa, string[] tokenNames) - : this(dfa, tokenNames, null, null) + : this(dfa, Vocabulary.FromTokenNames(tokenNames), null, null) + { + } + + public DFASerializer(DFA dfa, IVocabulary vocabulary) + : this(dfa, vocabulary, null, null) { } public DFASerializer(DFA dfa, Recognizer parser) - : this(dfa, parser != null ? parser.TokenNames : null, parser != null ? parser.RuleNames : null, parser != null ? parser.Atn : null) + : this(dfa, parser != null ? parser.Vocabulary : Vocabulary.EmptyVocabulary, parser != null ? parser.RuleNames : null, parser != null ? parser.Atn : null) { } + [System.ObsoleteAttribute(@"Use DFASerializer(DFA, Antlr4.Runtime.IVocabulary, string[], Antlr4.Runtime.Atn.ATN) instead.")] public DFASerializer(DFA dfa, string[] tokenNames, string[] ruleNames, ATN atn) + : this(dfa, Vocabulary.FromTokenNames(tokenNames), ruleNames, atn) + { + } + + public DFASerializer(DFA dfa, IVocabulary vocabulary, string[] ruleNames, ATN atn) { this.dfa = dfa; - this.tokenNames = tokenNames; + this.vocabulary = vocabulary; this.ruleNames = ruleNames; this.atn = atn; } @@ -81,7 +94,7 @@ namespace Antlr4.Runtime.Dfa if (dfa.states != null) { IList states = new List(dfa.states.Values); - states.Sort(new _IComparer_85()); + states.Sort(new _IComparer_103()); foreach (DFAState s in states) { IDictionary edges = s.EdgeMap; @@ -130,9 +143,9 @@ namespace Antlr4.Runtime.Dfa return output; } - private sealed class _IComparer_85 : IComparer + private sealed class _IComparer_103 : IComparer { - public _IComparer_85() + public _IComparer_103() { } @@ -169,20 +182,7 @@ namespace Antlr4.Runtime.Dfa protected internal virtual string GetEdgeLabel(int i) { - string label; - if (i == -1) - { - return "EOF"; - } - if (tokenNames != null) - { - label = tokenNames[i]; - } - else - { - label = i.ToString(); - } - return label; + return vocabulary.GetDisplayName(i); } internal virtual string GetStateString(DFAState s) @@ -193,7 +193,7 @@ namespace Antlr4.Runtime.Dfa } int n = s.stateNumber; string stateStr = "s" + n; - if (s.isAcceptState) + if (s.IsAcceptState) { if (s.predicates != null) { @@ -201,7 +201,7 @@ namespace Antlr4.Runtime.Dfa } else { - stateStr = ":s" + n + "=>" + s.prediction; + stateStr = ":s" + n + "=>" + s.Prediction; } } if (s.IsContextSensitive) diff --git a/runtime/CSharp/Antlr4.Runtime/Dfa/DFAState.cs b/runtime/CSharp/Antlr4.Runtime/Dfa/DFAState.cs index 09572e64a..43fcd3144 100644 --- a/runtime/CSharp/Antlr4.Runtime/Dfa/DFAState.cs +++ b/runtime/CSharp/Antlr4.Runtime/Dfa/DFAState.cs @@ -72,32 +72,15 @@ namespace Antlr4.Runtime.Dfa /// edges.get(symbol) /// points to target of symbol. /// - [Nullable] - private AbstractEdgeMap edges; + [NotNull] + private volatile AbstractEdgeMap edges; - private readonly int minSymbol; - - private readonly int maxSymbol; - - public bool isAcceptState = false; - - /// - /// if accept state, what ttype do we match or alt do we predict? - /// This is set to - /// - /// when - /// - /// !=null - /// . - /// - public int prediction; - - public LexerActionExecutor lexerActionExecutor; + private Antlr4.Runtime.Dfa.AcceptStateInfo acceptStateInfo; /// These keys for these edges are the top level element of the global context. /// These keys for these edges are the top level element of the global context. - [Nullable] - private AbstractEdgeMap contextEdges; + [NotNull] + private volatile AbstractEdgeMap contextEdges; /// Symbols in this set require a global context transition before matching an input symbol. /// Symbols in this set require a global context transition before matching an input symbol. @@ -134,86 +117,120 @@ namespace Antlr4.Runtime.Dfa } } - public DFAState(ATNConfigSet configs, int minSymbol, int maxSymbol) + public DFAState(DFA dfa, ATNConfigSet configs) + : this(dfa.EmptyEdgeMap, dfa.EmptyContextEdgeMap, configs) + { + } + + public DFAState(EmptyEdgeMap emptyEdges, EmptyEdgeMap emptyContextEdges, ATNConfigSet configs) { this.configs = configs; - this.minSymbol = minSymbol; - this.maxSymbol = maxSymbol; + this.edges = emptyEdges; + this.contextEdges = emptyContextEdges; } public bool IsContextSensitive { get { - return contextEdges != null; + return contextSymbols != null; } } public bool IsContextSymbol(int symbol) { - if (!IsContextSensitive || symbol < minSymbol) + if (!IsContextSensitive || symbol < edges.minIndex) { return false; } - return contextSymbols.Get(symbol - minSymbol); + return contextSymbols.Get(symbol - edges.minIndex); } public void SetContextSymbol(int symbol) { System.Diagnostics.Debug.Assert(IsContextSensitive); - if (symbol < minSymbol) + if (symbol < edges.minIndex) { return; } - contextSymbols.Set(symbol - minSymbol); + contextSymbols.Set(symbol - edges.minIndex); } public virtual void SetContextSensitive(ATN atn) { + System.Diagnostics.Debug.Assert(!configs.IsOutermostConfigSet); + if (IsContextSensitive) + { + return; + } lock (this) { - System.Diagnostics.Debug.Assert(!configs.IsOutermostConfigSet); - if (IsContextSensitive) + if (contextSymbols == null) { - return; + contextSymbols = new BitSet(); } - contextSymbols = new BitSet(); - contextEdges = new SingletonEdgeMap(-1, atn.states.Count - 1); + } + } + + public AcceptStateInfo AcceptStateInfo + { + get + { + return acceptStateInfo; + } + set + { + AcceptStateInfo acceptStateInfo = value; + this.acceptStateInfo = acceptStateInfo; + } + } + + public bool IsAcceptState + { + get + { + return acceptStateInfo != null; + } + } + + public int Prediction + { + get + { + if (acceptStateInfo == null) + { + return ATN.InvalidAltNumber; + } + return acceptStateInfo.Prediction; + } + } + + public LexerActionExecutor LexerActionExecutor + { + get + { + if (acceptStateInfo == null) + { + return null; + } + return acceptStateInfo.LexerActionExecutor; } } public virtual DFAState GetTarget(int symbol) { - lock (this) - { - if (edges == null) - { - return null; - } - return edges[symbol]; - } + return edges[symbol]; } public virtual void SetTarget(int symbol, DFAState target) { - lock (this) - { - if (edges == null) - { - edges = new SingletonEdgeMap(minSymbol, maxSymbol); - } - edges = edges.Put(symbol, target); - } + edges = edges.Put(symbol, target); } public virtual IDictionary EdgeMap { get { - if (edges == null) - { - return Antlr4.Runtime.Sharpen.Collections.EmptyMap(); - } return edges.ToMap(); } } @@ -222,10 +239,6 @@ namespace Antlr4.Runtime.Dfa { lock (this) { - if (contextEdges == null) - { - return null; - } if (invokingState == PredictionContext.EmptyFullStateKey) { invokingState = -1; @@ -238,7 +251,7 @@ namespace Antlr4.Runtime.Dfa { lock (this) { - if (contextEdges == null) + if (!IsContextSensitive) { throw new InvalidOperationException("The state is not context sensitive."); } @@ -254,10 +267,6 @@ namespace Antlr4.Runtime.Dfa { get { - if (contextEdges == null) - { - return Antlr4.Runtime.Sharpen.Collections.EmptyMap(); - } IDictionary map = contextEdges.ToMap(); if (map.ContainsKey(-1)) { @@ -327,7 +336,7 @@ namespace Antlr4.Runtime.Dfa { StringBuilder buf = new StringBuilder(); buf.Append(stateNumber).Append(":").Append(configs); - if (isAcceptState) + if (IsAcceptState) { buf.Append("=>"); if (predicates != null) @@ -336,7 +345,7 @@ namespace Antlr4.Runtime.Dfa } else { - buf.Append(prediction); + buf.Append(Prediction); } } return buf.ToString(); diff --git a/runtime/CSharp/Antlr4.Runtime/Dfa/EmptyEdgeMap`1.cs b/runtime/CSharp/Antlr4.Runtime/Dfa/EmptyEdgeMap`1.cs new file mode 100644 index 000000000..51de26e09 --- /dev/null +++ b/runtime/CSharp/Antlr4.Runtime/Dfa/EmptyEdgeMap`1.cs @@ -0,0 +1,108 @@ +/* + * [The "BSD license"] + * Copyright (c) 2013 Terence Parr + * Copyright (c) 2013 Sam Harwell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System.Collections.Generic; +using Antlr4.Runtime.Dfa; +using Antlr4.Runtime.Sharpen; + +namespace Antlr4.Runtime.Dfa +{ + /// + /// This implementation of + /// + /// represents an empty edge map. + /// + /// Sam Harwell + public sealed class EmptyEdgeMap : AbstractEdgeMap + { + public EmptyEdgeMap(int minIndex, int maxIndex) + : base(minIndex, maxIndex) + { + } + + public override AbstractEdgeMap Put(int key, T value) + { + if (value == null || key < minIndex || key > maxIndex) + { + // remains empty + return this; + } + return new SingletonEdgeMap(minIndex, maxIndex, key, value); + } + + public override AbstractEdgeMap Clear() + { + return this; + } + + public override AbstractEdgeMap Remove(int key) + { + return this; + } + + public override int Count + { + get + { + return 0; + } + } + + public override bool IsEmpty + { + get + { + return true; + } + } + + public override bool ContainsKey(int key) + { + return false; + } + + public override T this[int key] + { + get + { + return null; + } + } + + public override IDictionary ToMap() + { + return Antlr4.Runtime.Sharpen.Collections.EmptyMap(); + } + + public override HashSet> EntrySet() + { + return Antlr4.Runtime.Sharpen.Collections.EmptyMap().EntrySet(); + } + } +} diff --git a/runtime/CSharp/Antlr4.Runtime/Dfa/LexerDFASerializer.cs b/runtime/CSharp/Antlr4.Runtime/Dfa/LexerDFASerializer.cs index 3744b7588..8b5a7030a 100644 --- a/runtime/CSharp/Antlr4.Runtime/Dfa/LexerDFASerializer.cs +++ b/runtime/CSharp/Antlr4.Runtime/Dfa/LexerDFASerializer.cs @@ -27,6 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using Antlr4.Runtime; using Antlr4.Runtime.Dfa; using Antlr4.Runtime.Misc; using Antlr4.Runtime.Sharpen; @@ -36,7 +37,7 @@ namespace Antlr4.Runtime.Dfa public class LexerDFASerializer : DFASerializer { public LexerDFASerializer(DFA dfa) - : base(dfa, (string[])null) + : base(dfa, Vocabulary.EmptyVocabulary) { } diff --git a/runtime/CSharp/Antlr4.Runtime/Dfa/SingletonEdgeMap`1.cs b/runtime/CSharp/Antlr4.Runtime/Dfa/SingletonEdgeMap`1.cs index 7fe080361..d6ab43227 100644 --- a/runtime/CSharp/Antlr4.Runtime/Dfa/SingletonEdgeMap`1.cs +++ b/runtime/CSharp/Antlr4.Runtime/Dfa/SingletonEdgeMap`1.cs @@ -34,19 +34,12 @@ using Antlr4.Runtime.Sharpen; namespace Antlr4.Runtime.Dfa { /// Sam Harwell - public class SingletonEdgeMap : AbstractEdgeMap + public sealed class SingletonEdgeMap : AbstractEdgeMap { private readonly int key; private readonly T value; - public SingletonEdgeMap(int minIndex, int maxIndex) - : base(minIndex, maxIndex) - { - this.key = 0; - this.value = null; - } - public SingletonEdgeMap(int minIndex, int maxIndex, int key, T value) : base(minIndex, maxIndex) { @@ -62,7 +55,7 @@ namespace Antlr4.Runtime.Dfa } } - public virtual int Key + public int Key { get { @@ -70,7 +63,7 @@ namespace Antlr4.Runtime.Dfa } } - public virtual T Value + public T Value { get { @@ -141,7 +134,7 @@ namespace Antlr4.Runtime.Dfa { if (key == this.key && this.value != null) { - return new Antlr4.Runtime.Dfa.SingletonEdgeMap(minIndex, maxIndex); + return new EmptyEdgeMap(minIndex, maxIndex); } return this; } @@ -150,7 +143,7 @@ namespace Antlr4.Runtime.Dfa { if (this.value != null) { - return new Antlr4.Runtime.Dfa.SingletonEdgeMap(minIndex, maxIndex); + return new EmptyEdgeMap(minIndex, maxIndex); } return this; } diff --git a/runtime/CSharp/Antlr4.Runtime/Dfa/SparseEdgeMap`1.cs b/runtime/CSharp/Antlr4.Runtime/Dfa/SparseEdgeMap`1.cs index b9631df61..8d64553a9 100644 --- a/runtime/CSharp/Antlr4.Runtime/Dfa/SparseEdgeMap`1.cs +++ b/runtime/CSharp/Antlr4.Runtime/Dfa/SparseEdgeMap`1.cs @@ -35,7 +35,7 @@ using Antlr4.Runtime.Sharpen; namespace Antlr4.Runtime.Dfa { /// Sam Harwell - public class SparseEdgeMap : AbstractEdgeMap + public sealed class SparseEdgeMap : AbstractEdgeMap { private const int DefaultMaxSize = 5; @@ -58,16 +58,19 @@ namespace Antlr4.Runtime.Dfa private SparseEdgeMap(Antlr4.Runtime.Dfa.SparseEdgeMap map, int maxSparseSize) : base(map.minIndex, map.maxIndex) { - if (maxSparseSize < map.values.Count) + lock (map) { - throw new ArgumentException(); + if (maxSparseSize < map.values.Count) + { + throw new ArgumentException(); + } + keys = Arrays.CopyOf(map.keys, maxSparseSize); + values = new List(maxSparseSize); + Sharpen.Collections.AddAll(values, map.values); } - keys = Arrays.CopyOf(map.keys, maxSparseSize); - values = new List(maxSparseSize); - Sharpen.Collections.AddAll(values, map.values); } - public virtual int[] Keys + public int[] Keys { get { @@ -75,7 +78,7 @@ namespace Antlr4.Runtime.Dfa } } - public virtual IList Values + public IList Values { get { @@ -83,7 +86,7 @@ namespace Antlr4.Runtime.Dfa } } - public virtual int MaxSparseSize + public int MaxSparseSize { get { @@ -116,6 +119,9 @@ namespace Antlr4.Runtime.Dfa { get { + // Special property of this collection: values are only even added to + // the end, else a new object is returned from put(). Therefore no lock + // is required in this method. int index = System.Array.BinarySearch(keys, 0, Count, key); if (index < 0) { @@ -135,7 +141,7 @@ namespace Antlr4.Runtime.Dfa { return ((Antlr4.Runtime.Dfa.SparseEdgeMap)Remove(key)); } - lock (values) + lock (this) { int index = System.Array.BinarySearch(keys, 0, Count, key); if (index >= 0) @@ -166,7 +172,7 @@ namespace Antlr4.Runtime.Dfa else { Antlr4.Runtime.Dfa.SparseEdgeMap resized = new Antlr4.Runtime.Dfa.SparseEdgeMap(this, desiredSize); - System.Array.Copy(resized.keys, insertIndex, resized.keys, insertIndex + 1, resized.keys.Length - insertIndex - 1); + System.Array.Copy(resized.keys, insertIndex, resized.keys, insertIndex + 1, Count - insertIndex); resized.keys[insertIndex] = key; resized.values.Add(insertIndex, value); return resized; @@ -176,20 +182,18 @@ namespace Antlr4.Runtime.Dfa public override AbstractEdgeMap Remove(int key) { - int index = System.Array.BinarySearch(keys, 0, Count, key); - if (index < 0) + lock (this) { - return this; + int index = System.Array.BinarySearch(keys, 0, Count, key); + if (index < 0) + { + return this; + } + Antlr4.Runtime.Dfa.SparseEdgeMap result = new Antlr4.Runtime.Dfa.SparseEdgeMap(this, MaxSparseSize); + System.Array.Copy(result.keys, index + 1, result.keys, index, Count - index - 1); + result.values.RemoveAt(index); + return result; } - if (index == values.Count - 1) - { - values.RemoveAt(index); - return this; - } - Antlr4.Runtime.Dfa.SparseEdgeMap result = new Antlr4.Runtime.Dfa.SparseEdgeMap(this, MaxSparseSize); - System.Array.Copy(result.keys, index + 1, result.keys, index, Count - index - 1); - result.values.RemoveAt(index); - return result; } public override AbstractEdgeMap Clear() @@ -198,9 +202,7 @@ namespace Antlr4.Runtime.Dfa { return this; } - Antlr4.Runtime.Dfa.SparseEdgeMap result = new Antlr4.Runtime.Dfa.SparseEdgeMap(this, MaxSparseSize); - result.values.Clear(); - return result; + return new EmptyEdgeMap(minIndex, maxIndex); } public override IDictionary ToMap() @@ -209,12 +211,15 @@ namespace Antlr4.Runtime.Dfa { return Antlr4.Runtime.Sharpen.Collections.EmptyMap(); } - IDictionary result = new LinkedHashMap(); - for (int i = 0; i < Count; i++) + lock (this) { - result.Put(keys[i], values[i]); + IDictionary result = new LinkedHashMap(); + for (int i = 0; i < Count; i++) + { + result.Put(keys[i], values[i]); + } + return result; } - return result; } } } diff --git a/runtime/CSharp/Antlr4.Runtime/IToken.cs b/runtime/CSharp/Antlr4.Runtime/IToken.cs index fa09681bc..b180d76f7 100644 --- a/runtime/CSharp/Antlr4.Runtime/IToken.cs +++ b/runtime/CSharp/Antlr4.Runtime/IToken.cs @@ -182,5 +182,25 @@ namespace Antlr4.Runtime /// by parser. /// public const int HiddenChannel = 1; + + /// + /// This is the minimum constant value which can be assigned to a + /// user-defined token channel. + /// + /// + /// This is the minimum constant value which can be assigned to a + /// user-defined token channel. + ///

    + /// The non-negative numbers less than + /// + /// are + /// assigned to the predefined channels + /// + /// and + /// + /// .

    + ///
    + /// + public const int MinUserChannelValue = 2; } } diff --git a/runtime/CSharp/Antlr4.Runtime/IVocabulary.cs b/runtime/CSharp/Antlr4.Runtime/IVocabulary.cs new file mode 100644 index 000000000..a4f7262aa --- /dev/null +++ b/runtime/CSharp/Antlr4.Runtime/IVocabulary.cs @@ -0,0 +1,198 @@ +/* + * [The "BSD license"] + * Copyright (c) 2013 Terence Parr + * Copyright (c) 2013 Sam Harwell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using Antlr4.Runtime; +using Antlr4.Runtime.Misc; +using Antlr4.Runtime.Sharpen; + +namespace Antlr4.Runtime +{ + /// + /// This interface provides information about the vocabulary used by a + /// recognizer. + /// + /// + /// This interface provides information about the vocabulary used by a + /// recognizer. + /// + /// + /// Sam Harwell + public interface IVocabulary + { + /// Gets the string literal associated with a token type. + /// + /// Gets the string literal associated with a token type. The string returned + /// by this method, when not + /// + /// , can be used unaltered in a parser + /// grammar to represent this token type. + ///

    The following table shows examples of lexer rules and the literal + /// names assigned to the corresponding token types.

    + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + ///
    RuleLiteral NameJava String Literal
    + /// THIS : 'this'; + /// + /// 'this' + /// + /// "'this'" + ///
    + /// SQUOTE : '\''; + /// + /// '\'' + /// + /// "'\\''" + ///
    + /// ID : [A-Z]+; + /// n/a + /// + ///
    + ///
    + /// The token type. + /// + /// The string literal associated with the specified token type, or + /// + /// if no string literal is associated with the type. + /// + [Nullable] + string GetLiteralName(int tokenType); + + /// Gets the symbolic name associated with a token type. + /// + /// Gets the symbolic name associated with a token type. The string returned + /// by this method, when not + /// + /// , can be used unaltered in a parser + /// grammar to represent this token type. + ///

    This method supports token types defined by any of the following + /// methods:

    + ///
      + ///
    • Tokens created by lexer rules.
    • + ///
    • Tokens defined in a + /// + /// tokens + /// block in a lexer or parser + /// grammar.
    • + ///
    • The implicitly defined + /// EOF + /// token, which has the token type + /// + /// .
    • + ///
    + ///

    The following table shows examples of lexer rules and the literal + /// names assigned to the corresponding token types.

    + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + ///
    RuleSymbolic Name
    + /// THIS : 'this'; + /// + /// THIS + ///
    + /// SQUOTE : '\''; + /// + /// SQUOTE + ///
    + /// ID : [A-Z]+; + /// + /// ID + ///
    + ///
    + /// The token type. + /// + /// The symbolic name associated with the specified token type, or + /// + /// if no symbolic name is associated with the type. + /// + [Nullable] + string GetSymbolicName(int tokenType); + + /// Gets the display name of a token type. + /// + /// Gets the display name of a token type. + ///

    ANTLR provides a default implementation of this method, but + /// applications are free to override the behavior in any manner which makes + /// sense for the application. The default implementation returns the first + /// result from the following list which produces a non- + /// + /// result.

    + ///
      + ///
    1. The result of + /// + ///
    2. + ///
    3. The result of + /// + ///
    4. + ///
    5. The result of + /// + ///
    6. + ///
    + ///
    + /// The token type. + /// + /// The display name of the token type, for use in error reporting or + /// other user-visible messages which reference specific token types. + /// + [NotNull] + string GetDisplayName(int tokenType); + } +} diff --git a/runtime/CSharp/Antlr4.Runtime/LexerInterpreter.cs b/runtime/CSharp/Antlr4.Runtime/LexerInterpreter.cs index 20f3acb7c..dd1d339d8 100644 --- a/runtime/CSharp/Antlr4.Runtime/LexerInterpreter.cs +++ b/runtime/CSharp/Antlr4.Runtime/LexerInterpreter.cs @@ -31,6 +31,7 @@ using System; using System.Collections.Generic; using Antlr4.Runtime; using Antlr4.Runtime.Atn; +using Antlr4.Runtime.Misc; using Antlr4.Runtime.Sharpen; namespace Antlr4.Runtime @@ -41,13 +42,23 @@ namespace Antlr4.Runtime protected internal readonly ATN atn; + [Obsolete] protected internal readonly string[] tokenNames; protected internal readonly string[] ruleNames; protected internal readonly string[] modeNames; + [NotNull] + private readonly IVocabulary vocabulary; + + [Obsolete] public LexerInterpreter(string grammarFileName, ICollection tokenNames, ICollection ruleNames, ICollection modeNames, ATN atn, ICharStream input) + : this(grammarFileName, Antlr4.Runtime.Vocabulary.FromTokenNames(Sharpen.Collections.ToArray(tokenNames, new string[tokenNames.Count])), ruleNames, modeNames, atn, input) + { + } + + public LexerInterpreter(string grammarFileName, IVocabulary vocabulary, ICollection ruleNames, ICollection modeNames, ATN atn, ICharStream input) : base(input) { if (atn.grammarType != ATNType.Lexer) @@ -56,9 +67,14 @@ namespace Antlr4.Runtime } this.grammarFileName = grammarFileName; this.atn = atn; - this.tokenNames = Sharpen.Collections.ToArray(tokenNames, new string[tokenNames.Count]); + this.tokenNames = new string[atn.maxTokenType]; + for (int i = 0; i < tokenNames.Length; i++) + { + tokenNames[i] = vocabulary.GetDisplayName(i); + } this.ruleNames = Sharpen.Collections.ToArray(ruleNames, new string[ruleNames.Count]); this.modeNames = Sharpen.Collections.ToArray(modeNames, new string[modeNames.Count]); + this.vocabulary = vocabulary; this._interp = new LexerATNSimulator(this, atn); } @@ -101,5 +117,17 @@ namespace Antlr4.Runtime return modeNames; } } + + public override IVocabulary Vocabulary + { + get + { + if (vocabulary != null) + { + return vocabulary; + } + return base.Vocabulary; + } + } } } diff --git a/runtime/CSharp/Antlr4.Runtime/Misc/IntervalSet.cs b/runtime/CSharp/Antlr4.Runtime/Misc/IntervalSet.cs index f9c421f10..9189b2126 100644 --- a/runtime/CSharp/Antlr4.Runtime/Misc/IntervalSet.cs +++ b/runtime/CSharp/Antlr4.Runtime/Misc/IntervalSet.cs @@ -703,7 +703,13 @@ namespace Antlr4.Runtime.Misc return buf.ToString(); } + [System.ObsoleteAttribute(@"Use ToString(Antlr4.Runtime.IVocabulary) instead.")] public virtual string ToString(string[] tokenNames) + { + return ToString(Vocabulary.FromTokenNames(tokenNames)); + } + + public virtual string ToString(IVocabulary vocabulary) { StringBuilder buf = new StringBuilder(); if (this.intervals == null || this.intervals.IsEmpty()) @@ -722,7 +728,7 @@ namespace Antlr4.Runtime.Misc int b = I.b; if (a == b) { - buf.Append(ElementName(tokenNames, a)); + buf.Append(ElementName(vocabulary, a)); } else { @@ -732,7 +738,7 @@ namespace Antlr4.Runtime.Misc { buf.Append(", "); } - buf.Append(ElementName(tokenNames, i)); + buf.Append(ElementName(vocabulary, i)); } } if (iter.HasNext()) @@ -747,7 +753,14 @@ namespace Antlr4.Runtime.Misc return buf.ToString(); } + [System.ObsoleteAttribute(@"Use ElementName(Antlr4.Runtime.IVocabulary, int) instead.")] protected internal virtual string ElementName(string[] tokenNames, int a) + { + return ElementName(Vocabulary.FromTokenNames(tokenNames), a); + } + + [NotNull] + protected internal virtual string ElementName(IVocabulary vocabulary, int a) { if (a == TokenConstants.Eof) { @@ -761,7 +774,7 @@ namespace Antlr4.Runtime.Misc } else { - return tokenNames[a]; + return vocabulary.GetDisplayName(a); } } } diff --git a/runtime/CSharp/Antlr4.Runtime/Misc/RuleDependencyProcessor.cs b/runtime/CSharp/Antlr4.Runtime/Misc/RuleDependencyProcessor.cs index 8b8cd8907..c9eb0e10c 100644 --- a/runtime/CSharp/Antlr4.Runtime/Misc/RuleDependencyProcessor.cs +++ b/runtime/CSharp/Antlr4.Runtime/Misc/RuleDependencyProcessor.cs @@ -36,6 +36,7 @@ using Antlr4.Runtime.Misc; using Antlr4.Runtime.Sharpen; using Antlr4.Runtime.Sharpen.Annotation; using Javax.Annotation.Processing; +using Javax.Lang.Model; using Javax.Lang.Model.Element; using Javax.Lang.Model.Type; using Javax.Tools; @@ -59,6 +60,27 @@ namespace Antlr4.Runtime.Misc { } + public override SourceVersion GetSupportedSourceVersion() + { + SourceVersion latestSupported = SourceVersion.LatestSupported(); + if ((int)(latestSupported) <= 6) + { + return SourceVersion.Release6; + } + else + { + if ((int)(latestSupported) <= 8) + { + return latestSupported; + } + else + { + // this annotation processor is tested through Java 8 + return SourceVersion.Values()[8]; + } + } + } + public override bool Process<_T0>(HashSet<_T0> annotations, IRoundEnvironment roundEnv) { if (!CheckClassNameConstants()) diff --git a/runtime/CSharp/Antlr4.Runtime/Parser.cs b/runtime/CSharp/Antlr4.Runtime/Parser.cs index 727f4ef26..53e4b6c65 100644 --- a/runtime/CSharp/Antlr4.Runtime/Parser.cs +++ b/runtime/CSharp/Antlr4.Runtime/Parser.cs @@ -1134,7 +1134,7 @@ namespace Antlr4.Runtime for (int d = 0; d < _interp.atn.decisionToDFA.Length; d++) { DFA dfa = _interp.atn.decisionToDFA[d]; - s.Add(dfa.ToString(TokenNames, RuleNames)); + s.Add(dfa.ToString(Vocabulary, RuleNames)); } return s; } @@ -1154,7 +1154,7 @@ namespace Antlr4.Runtime System.Console.Out.WriteLine(); } System.Console.Out.WriteLine("Decision " + dfa.decision + ":"); - System.Console.Out.Write(dfa.ToString(TokenNames, RuleNames)); + System.Console.Out.Write(dfa.ToString(Vocabulary, RuleNames)); seenOne = true; } } diff --git a/runtime/CSharp/Antlr4.Runtime/ParserInterpreter.cs b/runtime/CSharp/Antlr4.Runtime/ParserInterpreter.cs index d0bf0a245..c78d12af9 100644 --- a/runtime/CSharp/Antlr4.Runtime/ParserInterpreter.cs +++ b/runtime/CSharp/Antlr4.Runtime/ParserInterpreter.cs @@ -31,6 +31,7 @@ using System; using System.Collections.Generic; using Antlr4.Runtime; using Antlr4.Runtime.Atn; +using Antlr4.Runtime.Misc; using Antlr4.Runtime.Sharpen; namespace Antlr4.Runtime @@ -58,19 +59,34 @@ namespace Antlr4.Runtime protected internal readonly BitSet pushRecursionContextStates; + [Obsolete] protected internal readonly string[] tokenNames; protected internal readonly string[] ruleNames; + [NotNull] + private readonly IVocabulary vocabulary; + protected internal readonly Stack> _parentContextStack = new Stack>(); + [System.ObsoleteAttribute(@"Use ParserInterpreter(string, IVocabulary, System.Collections.Generic.ICollection{E}, Antlr4.Runtime.Atn.ATN, ITokenStream) instead.")] public ParserInterpreter(string grammarFileName, ICollection tokenNames, ICollection ruleNames, ATN atn, ITokenStream input) + : this(grammarFileName, Antlr4.Runtime.Vocabulary.FromTokenNames(Sharpen.Collections.ToArray(tokenNames, new string[tokenNames.Count])), ruleNames, atn, input) + { + } + + public ParserInterpreter(string grammarFileName, IVocabulary vocabulary, ICollection ruleNames, ATN atn, ITokenStream input) : base(input) { this.grammarFileName = grammarFileName; this.atn = atn; - this.tokenNames = Sharpen.Collections.ToArray(tokenNames, new string[tokenNames.Count]); + this.tokenNames = new string[atn.maxTokenType]; + for (int i = 0; i < tokenNames.Length; i++) + { + tokenNames[i] = vocabulary.GetDisplayName(i); + } this.ruleNames = Sharpen.Collections.ToArray(ruleNames, new string[ruleNames.Count]); + this.vocabulary = vocabulary; // identify the ATN states where pushNewRecursionContext must be called this.pushRecursionContextStates = new BitSet(atn.states.Count); foreach (ATNState state in atn.states) @@ -104,6 +120,14 @@ namespace Antlr4.Runtime } } + public override IVocabulary Vocabulary + { + get + { + return vocabulary; + } + } + public override string[] RuleNames { get diff --git a/runtime/CSharp/Antlr4.Runtime/Recognizer`2.cs b/runtime/CSharp/Antlr4.Runtime/Recognizer`2.cs index 2a2352816..018ab2068 100644 --- a/runtime/CSharp/Antlr4.Runtime/Recognizer`2.cs +++ b/runtime/CSharp/Antlr4.Runtime/Recognizer`2.cs @@ -41,13 +41,13 @@ namespace Antlr4.Runtime { public const int Eof = -1; - private static readonly IDictionary> tokenTypeMapCache = new WeakHashMap>(); + private static readonly IDictionary> tokenTypeMapCache = new WeakHashMap>(); private static readonly IDictionary> ruleIndexMapCache = new WeakHashMap>(); - private sealed class _CopyOnWriteArrayList_59 : CopyOnWriteArrayList> + private sealed class _CopyOnWriteArrayList_60 : CopyOnWriteArrayList> { - public _CopyOnWriteArrayList_59() + public _CopyOnWriteArrayList_60() { { this.Add(ConsoleErrorListener.Instance); @@ -56,7 +56,7 @@ namespace Antlr4.Runtime } [NotNull] - private IList> _listeners = new _CopyOnWriteArrayList_59(); + private IList> _listeners = new _CopyOnWriteArrayList_60(); protected internal ATNInterpreter _interp; @@ -71,6 +71,7 @@ namespace Antlr4.Runtime /// error reporting. The generated parsers implement a method /// that overrides this to point to their String[] tokenNames. /// + [System.ObsoleteAttribute(@"Use Recognizer{Symbol, ATNInterpreter}.Vocabulary() instead.")] public abstract string[] TokenNames { get; @@ -81,6 +82,22 @@ namespace Antlr4.Runtime get; } + /// Get the vocabulary used by the recognizer. + /// Get the vocabulary used by the recognizer. + /// + /// A + /// + /// instance providing information about the + /// vocabulary used by the grammar. + /// + public virtual IVocabulary Vocabulary + { + get + { + return Antlr4.Runtime.Vocabulary.FromTokenNames(TokenNames); + } + } + /// Get a map from token names to token types. /// /// Get a map from token names to token types. @@ -90,20 +107,29 @@ namespace Antlr4.Runtime { get { - string[] tokenNames = TokenNames; - if (tokenNames == null) - { - throw new NotSupportedException("The current recognizer does not provide a list of token names."); - } + IVocabulary vocabulary = Vocabulary; lock (tokenTypeMapCache) { - IDictionary result = tokenTypeMapCache.Get(tokenNames); + IDictionary result = tokenTypeMapCache.Get(vocabulary); if (result == null) { - result = Utils.ToMap(tokenNames); + result = new Dictionary(); + for (int i = 0; i < Atn.maxTokenType; i++) + { + string literalName = vocabulary.GetLiteralName(i); + if (literalName != null) + { + result.Put(literalName, i); + } + string symbolicName = vocabulary.GetSymbolicName(i); + if (symbolicName != null) + { + result.Put(symbolicName, i); + } + } result.Put("EOF", TokenConstants.Eof); result = Antlr4.Runtime.Sharpen.Collections.UnmodifiableMap(result); - tokenTypeMapCache.Put(tokenNames, result); + tokenTypeMapCache.Put(vocabulary, result); } return result; } diff --git a/runtime/CSharp/Antlr4.Runtime/TokenStreamRewriter.cs b/runtime/CSharp/Antlr4.Runtime/TokenStreamRewriter.cs index a7691b4f4..e1c675fc7 100644 --- a/runtime/CSharp/Antlr4.Runtime/TokenStreamRewriter.cs +++ b/runtime/CSharp/Antlr4.Runtime/TokenStreamRewriter.cs @@ -274,7 +274,7 @@ namespace Antlr4.Runtime /// /// Rollback the instruction stream for a program so that /// the indicated instruction (via instructionIndex) is no - /// longer in the stream. UNTESTED! + /// longer in the stream. UNTESTED! /// public virtual void Rollback(string programName, int instructionIndex) { @@ -549,8 +549,8 @@ namespace Antlr4.Runtime /// /// /// We need to combine operations and report invalid operations (like - /// overlapping replaces that are not completed nested). Inserts to - /// same index need to be combined etc... Here are the cases: + /// overlapping replaces that are not completed nested). Inserts to + /// same index need to be combined etc... Here are the cases: /// I.i.u I.j.v leave alone, nonoverlapping /// I.i.u I.i.v combine: Iivu /// R.i-j.u R.x-y.v | i-j in x-y delete first R @@ -567,7 +567,7 @@ namespace Antlr4.Runtime /// R.x-y.v I.i.u | i not in x-y leave alone, nonoverlapping /// I.i.u = insert u before op @ index i /// R.x-y.u = replace x-y indexed tokens with u - /// First we need to examine replaces. For any replace op: + /// First we need to examine replaces. For any replace op: /// 1. wipe out any insertions before op within that range. /// 2. Drop any replace op before that is contained completely within /// that range. @@ -580,7 +580,7 @@ namespace Antlr4.Runtime /// Don't actually delete; make op null in list. Easier to walk list. /// Later we can throw as we add to index → op map. /// Note that I.2 R.2-2 will wipe out I.2 even though, technically, the - /// inserted stuff would be before the replace range. But, if you + /// inserted stuff would be before the replace range. But, if you /// add tokens in front of a method body '{' and then delete the method /// body, I think the stuff before the '{' you added should disappear too. /// Return a map from token index to operation. diff --git a/runtime/CSharp/Antlr4.Runtime/Tree/Pattern/ParseTreePatternMatcher.cs b/runtime/CSharp/Antlr4.Runtime/Tree/Pattern/ParseTreePatternMatcher.cs index 1a89a1775..cfe6ff571 100644 --- a/runtime/CSharp/Antlr4.Runtime/Tree/Pattern/ParseTreePatternMatcher.cs +++ b/runtime/CSharp/Antlr4.Runtime/Tree/Pattern/ParseTreePatternMatcher.cs @@ -326,7 +326,7 @@ namespace Antlr4.Runtime.Tree.Pattern IList tokenList = Tokenize(pattern); ListTokenSource tokenSrc = new ListTokenSource(tokenList); CommonTokenStream tokens = new CommonTokenStream(tokenSrc); - ParserInterpreter parserInterp = new ParserInterpreter(parser.GrammarFileName, Arrays.AsList(parser.TokenNames), Arrays.AsList(parser.RuleNames), parser.GetATNWithBypassAlts(), tokens); + ParserInterpreter parserInterp = new ParserInterpreter(parser.GrammarFileName, parser.Vocabulary, Arrays.AsList(parser.RuleNames), parser.GetATNWithBypassAlts(), tokens); IParseTree tree = null; try { diff --git a/runtime/CSharp/Antlr4.Runtime/UnbufferedCharStream.cs b/runtime/CSharp/Antlr4.Runtime/UnbufferedCharStream.cs index 00468ceef..c806c03fe 100644 --- a/runtime/CSharp/Antlr4.Runtime/UnbufferedCharStream.cs +++ b/runtime/CSharp/Antlr4.Runtime/UnbufferedCharStream.cs @@ -411,6 +411,10 @@ namespace Antlr4.Runtime { get { + if (name == null || name.IsEmpty()) + { + return IntStreamConstants.UnknownSourceName; + } return name; } } diff --git a/runtime/CSharp/Antlr4.Runtime/Vocabulary.cs b/runtime/CSharp/Antlr4.Runtime/Vocabulary.cs new file mode 100644 index 000000000..0e740a0bb --- /dev/null +++ b/runtime/CSharp/Antlr4.Runtime/Vocabulary.cs @@ -0,0 +1,250 @@ +/* + * [The "BSD license"] + * Copyright (c) 2013 Terence Parr + * Copyright (c) 2013 Sam Harwell + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using Antlr4.Runtime; +using Antlr4.Runtime.Misc; +using Antlr4.Runtime.Sharpen; + +namespace Antlr4.Runtime +{ + /// + /// This class provides a default implementation of the + /// + /// interface. + /// + /// Sam Harwell + public class Vocabulary : IVocabulary + { + private static readonly string[] EmptyNames = new string[0]; + + /// + /// Gets an empty + /// + /// instance. + ///

    + /// No literal or symbol names are assigned to token types, so + /// + /// returns the numeric value for all tokens + /// except + /// + /// .

    + ///
    + [NotNull] + public static readonly Vocabulary EmptyVocabulary = new Vocabulary(EmptyNames, EmptyNames, EmptyNames); + + [NotNull] + private readonly string[] literalNames; + + [NotNull] + private readonly string[] symbolicNames; + + [NotNull] + private readonly string[] displayNames; + + /// + /// Constructs a new instance of + /// + /// from the specified + /// literal and symbolic token names. + /// + /// + /// The literal names assigned to tokens, or + /// + /// if no literal names are assigned. + /// + /// + /// The symbolic names assigned to tokens, or + /// + /// if no symbolic names are assigned. + /// + /// + /// + public Vocabulary(string[] literalNames, string[] symbolicNames) + : this(literalNames, symbolicNames, null) + { + } + + /// + /// Constructs a new instance of + /// + /// from the specified + /// literal, symbolic, and display token names. + /// + /// + /// The literal names assigned to tokens, or + /// + /// if no literal names are assigned. + /// + /// + /// The symbolic names assigned to tokens, or + /// + /// if no symbolic names are assigned. + /// + /// + /// The display names assigned to tokens, or + /// + /// to use the values in + /// + /// and + /// + /// as + /// the source of display names, as described in + /// + /// . + /// + /// + /// + /// + public Vocabulary(string[] literalNames, string[] symbolicNames, string[] displayNames) + { + this.literalNames = literalNames != null ? literalNames : EmptyNames; + this.symbolicNames = symbolicNames != null ? symbolicNames : EmptyNames; + this.displayNames = displayNames != null ? displayNames : EmptyNames; + } + + /// + /// Returns a + /// + /// instance from the specified set of token + /// names. This method acts as a compatibility layer for the single + /// + /// array generated by previous releases of ANTLR. + ///

    The resulting vocabulary instance returns + /// + /// for + /// + /// and + /// + /// , and the + /// value from + /// + /// for the display names.

    + ///
    + /// + /// The token names, or + /// + /// if no token names are + /// available. + /// + /// + /// A + /// + /// instance which uses + /// + /// for + /// the display names of tokens. + /// + public static IVocabulary FromTokenNames(string[] tokenNames) + { + if (tokenNames == null || tokenNames.Length == 0) + { + return EmptyVocabulary; + } + string[] literalNames = Arrays.CopyOf(tokenNames, tokenNames.Length); + string[] symbolicNames = Arrays.CopyOf(tokenNames, tokenNames.Length); + for (int i = 0; i < tokenNames.Length; i++) + { + string tokenName = tokenNames[i]; + if (tokenName == null) + { + continue; + } + if (!tokenName.IsEmpty()) + { + char firstChar = tokenName[0]; + if (firstChar == '\'') + { + symbolicNames[i] = null; + continue; + } + else + { + if (System.Char.IsUpper(firstChar)) + { + literalNames[i] = null; + continue; + } + } + } + // wasn't a literal or symbolic name + literalNames[i] = null; + symbolicNames[i] = null; + } + return new Vocabulary(literalNames, symbolicNames, tokenNames); + } + + [Nullable] + public virtual string GetLiteralName(int tokenType) + { + if (tokenType >= 0 && tokenType < literalNames.Length) + { + return literalNames[tokenType]; + } + return null; + } + + [Nullable] + public virtual string GetSymbolicName(int tokenType) + { + if (tokenType >= 0 && tokenType < symbolicNames.Length) + { + return symbolicNames[tokenType]; + } + if (tokenType == TokenConstants.Eof) + { + return "EOF"; + } + return null; + } + + [NotNull] + public virtual string GetDisplayName(int tokenType) + { + if (tokenType >= 0 && tokenType < displayNames.Length) + { + string displayName = displayNames[tokenType]; + if (displayName != null) + { + return displayName; + } + } + string literalName = GetLiteralName(tokenType); + if (literalName != null) + { + return literalName; + } + string symbolicName = GetSymbolicName(tokenType); + if (symbolicName != null) + { + return symbolicName; + } + return Antlr4.Runtime.Sharpen.Extensions.ToString(tokenType); + } + } +}