public RuleClosureTransition( Rule rule, NFAState ruleStart, NFAState followState ) : base(Label.EPSILON, ruleStart) { this.rule = rule; this.followState = followState; }
/** From list of lookahead sets (one per alt in decision), create * an LL(1) DFA. One edge per set. * * s0-{alt1}->:o=>1 * | \ * | -{alt2}->:o=>2 * | * ... */ public LL1DFA( int decisionNumber, NFAState decisionStartState, LookaheadSet[] altLook ) : base(decisionNumber, decisionStartState) { DFAState s0 = NewState(); StartState = s0; UnreachableAlts.Clear(); for ( int alt = 1; alt < altLook.Length; alt++ ) { DFAState acceptAltState = NewState(); acceptAltState.IsAcceptState = true; SetAcceptState( alt, acceptAltState ); acceptAltState.LookaheadDepth = 1; acceptAltState.CachedUniquelyPredicatedAlt = alt; Label e = GetLabelForSet( altLook[alt].TokenTypeSet ); s0.AddTransition( acceptAltState, e ); } }
/** From list of lookahead sets (one per alt in decision), create * an LL(1) DFA. One edge per set. * * s0-{alt1}->:o=>1 * | \ * | -{alt2}->:o=>2 * | * ... */ public LL1DFA( int decisionNumber, NFAState decisionStartState, LookaheadSet[] altLook ) { DFAState s0 = NewState(); startState = s0; nfa = decisionStartState.nfa; NumberOfAlts = nfa.grammar.GetNumberOfAltsForDecisionNFA( decisionStartState ); this.decisionNumber = decisionNumber; this.NFADecisionStartState = decisionStartState; InitAltRelatedInfo(); UnreachableAlts = null; for ( int alt = 1; alt < altLook.Length; alt++ ) { DFAState acceptAltState = NewState(); acceptAltState.acceptState = true; SetAcceptState( alt, acceptAltState ); acceptAltState.LookaheadDepth = 1; acceptAltState.cachedUniquelyPredicatedAlt = alt; Label e = GetLabelForSet( altLook[alt].tokenTypeSet ); s0.AddTransition( acceptAltState, e ); } }
private void TransitionBetweenStates( NFAState a, NFAState b, int label ) { Transition e = new Transition( label, b ); a.AddTransition( e ); }
public virtual NFAState NewState() { NFAState n = new NFAState( _nfa ); int state = _nfa.GetNewNFAStateNumber(); n.StateNumber = state; _nfa.AddState( n ); n.enclosingRule = _currentRule; return n; }
public static DFA CreateFromNfa(int decisionNumber, NFAState decisionStartState) { DFA dfa = new DFA(decisionNumber, decisionStartState); //long start = JSystem.currentTimeMillis(); NFAToDFAConverter nfaConverter = new NFAToDFAConverter( dfa ); try { nfaConverter.Convert(); // figure out if there are problems with decision dfa.Verify(); if ( !dfa.Probe.IsDeterministic || dfa.Probe.AnalysisOverflowed ) { dfa.Probe.IssueWarnings(); } // must be after verify as it computes cyclic, needed by this routine // should be after warnings because early termination or something // will not allow the reset to operate properly in some cases. dfa.ResetStateNumbersToBeContiguous(); //long stop = JSystem.currentTimeMillis(); //[email protected]("verify cost: "+(int)(stop-start)+" ms"); } catch ( NonLLStarDecisionException /*nonLL*/ ) { dfa.Probe.ReportNonLLStarDecision( dfa ); // >1 alt recurses, k=* and no auto backtrack nor manual sem/syn if ( !dfa.OkToRetryWithK1 ) { dfa.Probe.IssueWarnings(); } } return dfa; }
public virtual NFAConfiguration AddNFAConfiguration( NFAState state, int alt, NFAContext context, SemanticContext semanticContext ) { NFAConfiguration c = new NFAConfiguration( state.stateNumber, alt, context, semanticContext ); AddNFAConfiguration( state, c ); return c; }
public virtual void SetDecisionNFA( int decision, NFAState state ) { Decision d = CreateDecision( decision ); d.startState = state; }
/** Decisions are linked together with transition(1). Count how * many there are. This is here rather than in NFAState because * a grammar decides how NFAs are put together to form a decision. */ public virtual int GetNumberOfAltsForDecisionNFA( NFAState decisionState ) { if ( decisionState == null ) { return 0; } int n = 1; NFAState p = decisionState; while ( p.transition[1] != null ) { n++; p = (NFAState)p.transition[1].Target; } return n; }
public virtual LookaheadSet First( NFAState s ) { return ll1Analyzer.First( s ); }
/** Fill a list of all NFA states visited during the parse */ protected virtual void ParseEngine( String startRule, NFAState start, NFAState stop, IIntStream input, Stack<object> ruleInvocationStack, IDebugEventListener actions, IList visitedStates ) { NFAState s = start; if ( actions != null ) { actions.EnterRule( s.nfa.grammar.FileName, start.enclosingRule.Name ); } int t = input.LA( 1 ); while ( s != stop ) { if ( visitedStates != null ) { visitedStates.Add( s ); } //Console.Out.WriteLine( "parse state " + s.stateNumber + " input=" + s.nfa.grammar.getTokenDisplayName( t ) ); // CASE 1: decision state if ( s.DecisionNumber > 0 && s.nfa.grammar.GetNumberOfAltsForDecisionNFA( s ) > 1 ) { // decision point, must predict and jump to alt DFA dfa = s.nfa.grammar.GetLookaheadDFA( s.DecisionNumber ); //if ( s.nfa.grammar.type != GrammarType.Lexer ) //{ // Console.Out.WriteLine( "decision: " + // dfa.getNFADecisionStartState().Description + // " input=" + s.nfa.grammar.getTokenDisplayName( t ) ); //} int m = input.Mark(); int predictedAlt = Predict( dfa ); if ( predictedAlt == NFA.INVALID_ALT_NUMBER ) { String description = dfa.NFADecisionStartState.Description; NoViableAltException nvae = new NoViableAltException( description, dfa.DecisionNumber, s.stateNumber, input ); if ( actions != null ) { actions.RecognitionException( nvae ); } input.Consume(); // recover throw nvae; } input.Rewind( m ); int parseAlt = s.TranslateDisplayAltToWalkAlt( predictedAlt ); //if ( s.nfa.grammar.type != GrammarType.Lexer ) //{ // Console.Out.WriteLine( "predicted alt " + predictedAlt + ", parseAlt " + parseAlt ); //} NFAState alt; if ( parseAlt > s.nfa.grammar.GetNumberOfAltsForDecisionNFA( s ) ) { // implied branch of loop etc... alt = s.nfa.grammar.nfa.GetState( s.endOfBlockStateNumber ); } else { alt = s.nfa.grammar.GetNFAStateForAltOfDecision( s, parseAlt ); } s = (NFAState)alt.transition[0].target; continue; } // CASE 2: finished matching a rule if ( s.IsAcceptState ) { // end of rule node if ( actions != null ) { actions.ExitRule( s.nfa.grammar.FileName, s.enclosingRule.Name ); } if ( ruleInvocationStack.Count == 0 ) { // done parsing. Hit the start state. //Console.Out.WriteLine( "stack empty in stop state for " + s.enclosingRule ); break; } // pop invoking state off the stack to know where to return to NFAState invokingState = (NFAState)ruleInvocationStack.Pop(); RuleClosureTransition invokingTransition = (RuleClosureTransition)invokingState.transition[0]; // move to node after state that invoked this rule s = invokingTransition.followState; continue; } Transition trans = s.transition[0]; Label label = trans.label; if ( label.IsSemanticPredicate ) { FailedPredicateException fpe = new FailedPredicateException( input, s.enclosingRule.Name, "can't deal with predicates yet" ); if ( actions != null ) { actions.RecognitionException( fpe ); } } // CASE 3: epsilon transition if ( label.IsEpsilon ) { // CASE 3a: rule invocation state if ( trans is RuleClosureTransition ) { ruleInvocationStack.Push( s ); s = (NFAState)trans.target; //Console.Out.WriteLine( "call " + s.enclosingRule.name + " from " + s.nfa.grammar.getFileName() ); if ( actions != null ) { actions.EnterRule( s.nfa.grammar.FileName, s.enclosingRule.Name ); } // could be jumping to new grammar, make sure DFA created if ( !s.nfa.grammar.AllDecisionDFAHaveBeenCreated ) { s.nfa.grammar.CreateLookaheadDFAs(); } } // CASE 3b: plain old epsilon transition, just move else { s = (NFAState)trans.target; } } // CASE 4: match label on transition else if ( label.Matches( t ) ) { if ( actions != null ) { if ( s.nfa.grammar.type == GrammarType.Parser || s.nfa.grammar.type == GrammarType.Combined ) { actions.ConsumeToken( ( (ITokenStream)input ).LT( 1 ) ); } } s = (NFAState)s.transition[0].target; input.Consume(); t = input.LA( 1 ); } // CASE 5: error condition; label is inconsistent with input else { if ( label.IsAtom ) { MismatchedTokenException mte = new MismatchedTokenException( label.Atom, input ); if ( actions != null ) { actions.RecognitionException( mte ); } input.Consume(); // recover throw mte; } else if ( label.IsSet ) { MismatchedSetException mse = new MismatchedSetException( ( (IntervalSet)label.Set ).ToRuntimeBitSet(), input ); if ( actions != null ) { actions.RecognitionException( mse ); } input.Consume(); // recover throw mse; } else if ( label.IsSemanticPredicate ) { FailedPredicateException fpe = new FailedPredicateException( input, s.enclosingRule.Name, label.SemanticContext.ToString() ); if ( actions != null ) { actions.RecognitionException( fpe ); } input.Consume(); // recover throw fpe; } else { throw new RecognitionException( input ); // unknown error } } } //Console.Out.WriteLine( "hit stop state for " + stop.enclosingRule ); if ( actions != null ) { actions.ExitRule( s.nfa.grammar.FileName, stop.enclosingRule.Name ); } }
protected virtual SemanticContext GetPredicatesCore( NFAState s, NFAState altStartState ) { //[email protected]("_getPredicates("+s+")"); if ( s.IsAcceptState ) { return null; } // avoid infinite loops from (..)* etc... if ( _lookBusy.Contains( s ) ) { return null; } _lookBusy.Add( s ); Transition transition0 = s.transition[0]; // no transitions if ( transition0 == null ) { return null; } // not a predicate and not even an epsilon if ( !( transition0.label.IsSemanticPredicate || transition0.label.IsEpsilon ) ) { return null; } SemanticContext p = null; SemanticContext p0 = null; SemanticContext p1 = null; if ( transition0.label.IsSemanticPredicate ) { //[email protected]("pred "+transition0.label); p = transition0.label.SemanticContext; // ignore backtracking preds not on left edge for this decision if ( ( (SemanticContext.Predicate)p ).predicateAST.Type == ANTLRParser.BACKTRACK_SEMPRED && s == altStartState.transition[0].target ) { p = null; // don't count } } // get preds from beyond this state p0 = GetPredicatesCore( (NFAState)transition0.target, altStartState ); // get preds from other transition Transition transition1 = s.transition[1]; if ( transition1 != null ) { p1 = GetPredicatesCore( (NFAState)transition1.target, altStartState ); } // join this&following-right|following-down return SemanticContext.And( p, SemanticContext.Or( p0, p1 ) ); }
protected virtual LookaheadSet FirstCore( NFAState s, bool chaseFollowTransitions ) { /* [email protected]("_LOOK("+s+") in rule "+s.enclosingRule); if ( s.transition[0] instanceof RuleClosureTransition ) { [email protected]("go to rule "+((NFAState)s.transition[0].target).enclosingRule); } */ if ( !chaseFollowTransitions && s.IsAcceptState ) { if ( _grammar.type == GrammarType.Lexer ) { // FOLLOW makes no sense (at the moment!) for lexical rules. // assume all char can follow return new LookaheadSet( IntervalSet.COMPLETE_SET ); } return new LookaheadSet( Label.EOR_TOKEN_TYPE ); } if ( _lookBusy.Contains( s ) ) { // return a copy of an empty set; we may modify set inline return new LookaheadSet(); } _lookBusy.Add( s ); Transition transition0 = s.transition[0]; if ( transition0 == null ) { return null; } if ( transition0.label.IsAtom ) { int atom = transition0.label.Atom; return new LookaheadSet( atom ); } if ( transition0.label.IsSet ) { IIntSet sl = transition0.label.Set; return new LookaheadSet( sl ); } // compute FIRST of transition 0 LookaheadSet tset = null; // if transition 0 is a rule call and we don't want FOLLOW, check cache if ( !chaseFollowTransitions && transition0 is RuleClosureTransition ) { LookaheadSet prev = _firstCache.get( (NFAState)transition0.target ); if ( prev != null ) { tset = new LookaheadSet( prev ); } } // if not in cache, must compute if ( tset == null ) { tset = FirstCore( (NFAState)transition0.target, chaseFollowTransitions ); // save FIRST cache for transition 0 if rule call if ( !chaseFollowTransitions && transition0 is RuleClosureTransition ) { _firstCache[(NFAState)transition0.target] = tset; } } // did we fall off the end? if ( _grammar.type != GrammarType.Lexer && tset.Member( Label.EOR_TOKEN_TYPE ) ) { if ( transition0 is RuleClosureTransition ) { // we called a rule that found the end of the rule. // That means the rule is nullable and we need to // keep looking at what follows the rule ref. E.g., // a : b A ; where b is nullable means that LOOK(a) // should include A. RuleClosureTransition ruleInvocationTrans = (RuleClosureTransition)transition0; // remove the EOR and get what follows //tset.remove(Label.EOR_TOKEN_TYPE); NFAState following = (NFAState)ruleInvocationTrans.followState; LookaheadSet fset = FirstCore( following, chaseFollowTransitions ); fset.OrInPlace( tset ); // tset cached; or into new set fset.Remove( Label.EOR_TOKEN_TYPE ); tset = fset; } } Transition transition1 = s.transition[1]; if ( transition1 != null ) { LookaheadSet tset1 = FirstCore( (NFAState)transition1.target, chaseFollowTransitions ); tset1.OrInPlace( tset ); // tset cached; or into new set tset = tset1; } return tset; }
protected virtual int DetectConfoundingPredicatesCore( NFAState s, Rule enclosingRule, bool chaseFollowTransitions ) { //[email protected]("_detectNonAutobacktrackPredicates("+s+")"); if ( !chaseFollowTransitions && s.IsAcceptState ) { if ( _grammar.type == GrammarType.Lexer ) { // FOLLOW makes no sense (at the moment!) for lexical rules. // assume all char can follow return DETECT_PRED_NOT_FOUND; } return DETECT_PRED_EOR; } if ( _lookBusy.Contains( s ) ) { // return a copy of an empty set; we may modify set inline return DETECT_PRED_NOT_FOUND; } _lookBusy.Add( s ); Transition transition0 = s.transition[0]; if ( transition0 == null ) { return DETECT_PRED_NOT_FOUND; } if ( !( transition0.label.IsSemanticPredicate || transition0.label.IsEpsilon ) ) { return DETECT_PRED_NOT_FOUND; } if ( transition0.label.IsSemanticPredicate ) { //[email protected]("pred "+transition0.label); SemanticContext ctx = transition0.label.SemanticContext; SemanticContext.Predicate p = (SemanticContext.Predicate)ctx; if ( p.predicateAST.Type != ANTLRParser.BACKTRACK_SEMPRED ) { return DETECT_PRED_FOUND; } } /* if ( transition0.label.isSemanticPredicate() ) { [email protected]("pred "+transition0.label); SemanticContext ctx = transition0.label.getSemanticContext(); SemanticContext.Predicate p = (SemanticContext.Predicate)ctx; // if a non-syn-pred found not in enclosingRule, say we found one if ( p.predicateAST.getType() != ANTLRParser.BACKTRACK_SEMPRED && !p.predicateAST.enclosingRuleName.equals(enclosingRule.name) ) { [email protected]("found pred "+p+" not in "+enclosingRule.name); return DETECT_PRED_FOUND; } } */ int result = DetectConfoundingPredicatesCore( (NFAState)transition0.target, enclosingRule, chaseFollowTransitions ); if ( result == DETECT_PRED_FOUND ) { return DETECT_PRED_FOUND; } if ( result == DETECT_PRED_EOR ) { if ( transition0 is RuleClosureTransition ) { // we called a rule that found the end of the rule. // That means the rule is nullable and we need to // keep looking at what follows the rule ref. E.g., // a : b A ; where b is nullable means that LOOK(a) // should include A. RuleClosureTransition ruleInvocationTrans = (RuleClosureTransition)transition0; NFAState following = (NFAState)ruleInvocationTrans.followState; int afterRuleResult = DetectConfoundingPredicatesCore( following, enclosingRule, chaseFollowTransitions ); if ( afterRuleResult == DETECT_PRED_FOUND ) { return DETECT_PRED_FOUND; } } } Transition transition1 = s.transition[1]; if ( transition1 != null ) { int t1Result = DetectConfoundingPredicatesCore( (NFAState)transition1.target, enclosingRule, chaseFollowTransitions ); if ( t1Result == DETECT_PRED_FOUND ) { return DETECT_PRED_FOUND; } } return DETECT_PRED_NOT_FOUND; }
public LookaheadSet Look( NFAState s ) { if ( NFAToDFAConverter.debug ) { Console.Out.WriteLine( "> LOOK(" + s + ")" ); } _lookBusy.Clear(); LookaheadSet look = FirstCore( s, true ); // FOLLOW makes no sense (at the moment!) for lexical rules. if ( _grammar.type != GrammarType.Lexer && look.Member( Label.EOR_TOKEN_TYPE ) ) { // avoid altering FIRST reset as it is cached LookaheadSet f = Follow( s.enclosingRule ); f.OrInPlace( look ); f.Remove( Label.EOR_TOKEN_TYPE ); look = f; //look.orInPlace(FOLLOW(s.enclosingRule)); } else if ( _grammar.type == GrammarType.Lexer && look.Member( Label.EOT ) ) { // if this has EOT, lookahead is all char (all char can follow rule) //look = new LookaheadSet(Label.EOT); look = new LookaheadSet( IntervalSet.COMPLETE_SET ); } if ( NFAToDFAConverter.debug ) { Console.Out.WriteLine( "< LOOK(" + s + ")=" + look.ToString( _grammar ) ); } return look; }
/** Return predicate expression found via epsilon edges from s. Do * not look into other rules for now. Do something simple. Include * backtracking synpreds. */ public SemanticContext GetPredicates( NFAState altStartState ) { _lookBusy.Clear(); return GetPredicatesCore( altStartState, altStartState ); }
/** From an NFA state, s, find the set of all labels reachable from s. * Used to compute follow sets for error recovery. Never computes * a FOLLOW operation. FIRST stops at end of rules, returning EOR, unless * invoked from another rule. I.e., routine properly handles * * a : b A ; * * where b is nullable. * * We record with EOR_TOKEN_TYPE if we hit the end of a rule so we can * know at runtime (when these sets are used) to start walking up the * follow chain to compute the real, correct follow set (as opposed to * the FOLLOW, which is a superset). * * This routine will only be used on parser and tree parser grammars. */ public LookaheadSet First( NFAState s ) { //[email protected]("> FIRST("+s.enclosingRule.name+") in rule "+s.enclosingRule); _lookBusy.Clear(); LookaheadSet look = FirstCore( s, false ); //[email protected]("< FIRST("+s.enclosingRule.name+") in rule "+s.enclosingRule+"="+look.toString(this.grammar)); return look; }
public virtual int AssignDecisionNumber( NFAState state ) { decisionCount++; state.DecisionNumber = decisionCount; return decisionCount; }
public void AddState(NFAState state) { grammar.composite.AddState(state); }
/** Get the ith alternative (1..n) from a decision; return null when * an invalid alt is requested. I must count in to find the right * alternative number. For (A|B), you get NFA structure (roughly): * * o->o-A->o * | * o->o-B->o * * This routine returns the leftmost state for each alt. So alt=1, returns * the upperleft most state in this structure. */ public virtual NFAState GetNFAStateForAltOfDecision( NFAState decisionState, int alt ) { if ( decisionState == null || alt <= 0 ) { return null; } int n = 1; NFAState p = decisionState; while ( p != null ) { if ( n == alt ) { return p; } n++; Transition next = p.transition[1]; p = null; if ( next != null ) { p = (NFAState)next.Target; } } return null; }
// output list of NFA states /** Given a sample input sequence, you usually would like to know the * path taken through the NFA. Return the list of NFA states visited * while matching a list of labels. This cannot use the usual * interpreter, which does a deterministic walk. We need to be able to * take paths that are turned off during nondeterminism resolution. So, * just do a depth-first walk traversing edges labeled with the current * label. Return true if a path was found emanating from state s. */ protected virtual bool GetNFAPath( NFAState s, // starting where? int labelIndex, // 0..labels.size()-1 IList<Label> labels, // input sequence IList<NFAState> path ) { // track a visit to state s at input index labelIndex if not seen string thisStateKey = GetStateLabelIndexKey( s.StateNumber, labelIndex ); if ( _statesVisitedAtInputDepth.Contains( thisStateKey ) ) { /* [email protected]("### already visited "+s.stateNumber+" previously at index "+ labelIndex); */ return false; } _statesVisitedAtInputDepth.Add( thisStateKey ); /* [email protected]("enter state "+s.stateNumber+" visited states: "+ statesVisitedAtInputDepth); */ // pick the first edge whose target is in states and whose // label is labels[labelIndex] for ( int i = 0; i < s.NumberOfTransitions; i++ ) { Transition t = s.transition[i]; NFAState edgeTarget = (NFAState)t.Target; Label label = (Label)labels[labelIndex]; /* [email protected](s.stateNumber+"-"+ t.label.toString(dfa.nfa.Grammar)+"->"+ edgeTarget.stateNumber+" =="+ label.toString(dfa.nfa.Grammar)+"?"); */ if ( t.Label.IsEpsilon || t.Label.IsSemanticPredicate ) { // nondeterministically backtrack down epsilon edges path.Add( edgeTarget ); bool found = GetNFAPath( edgeTarget, labelIndex, labels, path ); if ( found ) { _statesVisitedAtInputDepth.Remove( thisStateKey ); return true; // return to "calling" state } path.RemoveAt( path.Count - 1 ); // remove; didn't work out continue; // look at the next edge } if ( t.Label.Matches( label ) ) { path.Add( edgeTarget ); /* [email protected]("found label "+ t.label.toString(dfa.nfa.Grammar)+ " at state "+s.stateNumber+"; labelIndex="+labelIndex); */ if ( labelIndex == labels.Count - 1 ) { // found last label; done! _statesVisitedAtInputDepth.Remove( thisStateKey ); return true; } // otherwise try to match remaining input bool found = GetNFAPath( edgeTarget, labelIndex + 1, labels, path ); if ( found ) { _statesVisitedAtInputDepth.Remove( thisStateKey ); return true; } /* [email protected]("backtrack; path from "+s.stateNumber+"->"+ t.label.toString(dfa.nfa.Grammar)+" didn't work"); */ path.RemoveAt( path.Count - 1 ); // remove; didn't work out continue; // keep looking for a path for labels } } //[email protected]("no epsilon or matching edge; removing "+thisStateKey); // no edge was found matching label; is ok, some state will have it _statesVisitedAtInputDepth.Remove( thisStateKey ); return false; }
public virtual LookaheadSet Look( NFAState s ) { return ll1Analyzer.Look( s ); }
public NFAContext( NFAContext parent, NFAState invokingState ) { this.parent = parent; this.invokingState = invokingState; if ( invokingState != null ) { this._cachedHashCode = invokingState.stateNumber; } if ( parent != null ) { this._cachedHashCode += parent._cachedHashCode; } }
/** Add an NFA configuration to this DFA node. Add uniquely * an NFA state/alt/syntactic&semantic context (chain of invoking state(s) * and semantic predicate contexts). * * I don't see how there could be two configurations with same * state|alt|synCtx and different semantic contexts because the * semantic contexts are computed along the path to a particular state * so those two configurations would have to have the same predicate. * Nonetheless, the addition of configurations is unique on all * configuration info. I guess I'm saying that syntactic context * implies semantic context as the latter is computed according to the * former. * * As we add configurations to this DFA state, track the set of all possible * transition labels so we can simply walk it later rather than doing a * loop over all possible labels in the NFA. */ public virtual void AddNFAConfiguration( NFAState state, NFAConfiguration c ) { if ( nfaConfigurations.Contains( c ) ) { return; } nfaConfigurations.Add( c ); // track min alt rather than compute later if ( c.alt < minAltInConfigurations ) { minAltInConfigurations = c.alt; } if ( c.semanticContext != SemanticContext.EmptySemanticContext ) { _atLeastOneConfigurationHasAPredicate = true; } // update hashCode; for some reason using context.hashCode() also // makes the GC take like 70% of the CPU and is slow! _cachedHashCode += c.state + c.alt; // update reachableLabels // We're adding an NFA state; check to see if it has a non-epsilon edge if ( state.transition[0] != null ) { Label label = state.transition[0].label; if ( !( label.IsEpsilon || label.IsSemanticPredicate ) ) { // this NFA state has a non-epsilon edge, track for fast // walking later when we do reach on this DFA state we're // building. configurationsWithLabeledEdges.Add( c ); if ( state.transition[1] == null ) { // later we can check this to ignore o-A->o states in closure c.singleAtomTransitionEmanating = true; } AddReachableLabel( label ); } } }
private static bool HasOneOrMoreEpsilonTransitionOnly(NFAState state) { for (int t = 0; t < state.NumberOfTransitions; t++) { Transition transition = state.transition[t]; if (!transition.IsEpsilon) return false; } return state.NumberOfTransitions > 0; }
protected DFA( int decisionNumber, NFAState decisionStartState ) { this._probe = new DecisionProbe(this); this._decisionNumber = decisionNumber; this._decisionNFAStartState = decisionStartState; this._nfa = decisionStartState.nfa; this._numberOfAlts = Nfa.Grammar.GetNumberOfAltsForDecisionNFA( decisionStartState ); //setOptions( nfa.grammar.getDecisionOptions(getDecisionNumber()) ); this._altToAcceptState = new DFAState[NumberOfAlts + 1]; this._unreachableAlts = new List<int>(Enumerable.Range(1, NumberOfAlts)); }
private int NumberOfIncomingTransition(NFAState state) { return _links.Count(i => i.Key.Value.Target == state); }
/** For reference to rule r, build * * o-e->(r) o * * where (r) is the start of rule r and the trailing o is not linked * to from rule ref state directly (it's done thru the transition(0) * RuleClosureTransition. * * If the rule r is just a list of tokens, it's block will be just * a set on an edge o->o->o-set->o->o->o, could inline it rather than doing * the rule reference, but i'm not doing this yet as I'm not sure * it would help much in the NFA->DFA construction. * * TODO add to codegen: collapse alt blks that are sets into single matchSet */ public virtual StateCluster BuildRuleRef( Rule refDef, NFAState ruleStart ) { //System.Console.Out.WriteLine( "building ref to rule " + nfa.grammar.name + "." + refDef.name ); NFAState left = NewState(); //left.Description = "ref to " + ruleStart.Description; NFAState right = NewState(); //right.Description = "NFAState following ref to " + ruleStart.Description; Transition e = new RuleClosureTransition( refDef, ruleStart, right ); left.AddTransition( e ); StateCluster g = new StateCluster( left, right ); return g; }
/** Given a sample input sequence, you usually would like to know the * path taken through the NFA. Return the list of NFA states visited * while matching a list of labels. This cannot use the usual * interpreter, which does a deterministic walk. We need to be able to * take paths that are turned off during nondeterminism resolution. So, * just do a depth-first walk traversing edges labeled with the current * label. Return true if a path was found emanating from state s. */ protected virtual bool GetNFAPath(NFAState s, // starting where? int labelIndex, // 0..labels.size()-1 IList <Label> labels, // input sequence IList <NFAState> path) // output list of NFA states { // track a visit to state s at input index labelIndex if not seen string thisStateKey = GetStateLabelIndexKey(s.StateNumber, labelIndex); if (_statesVisitedAtInputDepth.Contains(thisStateKey)) { /* * [email protected]("### already visited "+s.stateNumber+" previously at index "+ * labelIndex); */ return(false); } _statesVisitedAtInputDepth.Add(thisStateKey); /* * [email protected]("enter state "+s.stateNumber+" visited states: "+ * statesVisitedAtInputDepth); */ // pick the first edge whose target is in states and whose // label is labels[labelIndex] for (int i = 0; i < s.NumberOfTransitions; i++) { Transition t = s.transition[i]; NFAState edgeTarget = (NFAState)t.Target; Label label = (Label)labels[labelIndex]; /* * [email protected](s.stateNumber+"-"+ * t.label.toString(dfa.nfa.Grammar)+"->"+ * edgeTarget.stateNumber+" =="+ * label.toString(dfa.nfa.Grammar)+"?"); */ if (t.Label.IsEpsilon || t.Label.IsSemanticPredicate) { // nondeterministically backtrack down epsilon edges path.Add(edgeTarget); bool found = GetNFAPath(edgeTarget, labelIndex, labels, path); if (found) { _statesVisitedAtInputDepth.Remove(thisStateKey); return(true); // return to "calling" state } path.RemoveAt(path.Count - 1); // remove; didn't work out continue; // look at the next edge } if (t.Label.Matches(label)) { path.Add(edgeTarget); /* * [email protected]("found label "+ * t.label.toString(dfa.nfa.Grammar)+ * " at state "+s.stateNumber+"; labelIndex="+labelIndex); */ if (labelIndex == labels.Count - 1) { // found last label; done! _statesVisitedAtInputDepth.Remove(thisStateKey); return(true); } // otherwise try to match remaining input bool found = GetNFAPath(edgeTarget, labelIndex + 1, labels, path); if (found) { _statesVisitedAtInputDepth.Remove(thisStateKey); return(true); } /* * [email protected]("backtrack; path from "+s.stateNumber+"->"+ * t.label.toString(dfa.nfa.Grammar)+" didn't work"); */ path.RemoveAt(path.Count - 1); // remove; didn't work out continue; // keep looking for a path for labels } } //[email protected]("no epsilon or matching edge; removing "+thisStateKey); // no edge was found matching label; is ok, some state will have it _statesVisitedAtInputDepth.Remove(thisStateKey); return(false); }
/** set up an NFA NFAState that will yield eof tokens or, * in the case of a lexer grammar, an EOT token when the conversion * hits the end of a rule. */ private void BuildEofState( NFAState endNFAState ) { NFAState end = NewState(); int label = Label.EOF; if ( _nfa.Grammar.type == GrammarType.Lexer ) { label = Label.EOT; end.IsEOTTargetState = true; } //System.Console.Out.WriteLine( "build " + nfa.grammar.getTokenDisplayName( label ) + // " loop on end of state " + endNFAState.Description + // " to state " + end.stateNumber ); Transition toEnd = new Transition( label, end ); endNFAState.AddTransition( toEnd ); }
/** From a set of edgeset->list-of-alts mappings, create a DFA * that uses syn preds for all |list-of-alts|>1. */ public LL1DFA(int decisionNumber, NFAState decisionStartState, MultiMap <IntervalSet, int> edgeMap) : base(decisionNumber, decisionStartState) { DFAState s0 = NewState(); StartState = s0; UnreachableAlts.Clear(); foreach (var edgeVar in edgeMap) { IntervalSet edge = edgeVar.Key; IList <int> alts = edgeVar.Value; alts = alts.OrderBy(i => i).ToList(); //Collections.sort( alts ); // make sure alts are attempted in order //[email protected](edge+" -> "+alts); DFAState s = NewState(); s.LookaheadDepth = 1; Label e = GetLabelForSet(edge); s0.AddTransition(s, e); if (alts.Count == 1) { s.IsAcceptState = true; int alt = alts[0]; SetAcceptState(alt, s); s.CachedUniquelyPredicatedAlt = alt; } else { // resolve with syntactic predicates. Add edges from // state s that test predicates. s.IsResolvedWithPredicates = true; for (int i = 0; i < alts.Count; i++) { int alt = (int)alts[i]; s.CachedUniquelyPredicatedAlt = NFA.INVALID_ALT_NUMBER; DFAState predDFATarget = GetAcceptState(alt); if (predDFATarget == null) { predDFATarget = NewState(); // create if not there. predDFATarget.IsAcceptState = true; predDFATarget.CachedUniquelyPredicatedAlt = alt; SetAcceptState(alt, predDFATarget); } // add a transition to pred target from d /* * int walkAlt = * decisionStartState.translateDisplayAltToWalkAlt(alt); * NFAState altLeftEdge = nfa.grammar.getNFAStateForAltOfDecision(decisionStartState, walkAlt); * NFAState altStartState = (NFAState)altLeftEdge.transition[0].target; * SemanticContext ctx = nfa.grammar.ll1Analyzer.getPredicates(altStartState); * [email protected]("sem ctx = "+ctx); * if ( ctx == null ) { * ctx = new SemanticContext.TruePredicate(); * } * s.addTransition(predDFATarget, new Label(ctx)); */ SemanticContext.Predicate synpred = GetSynPredForAlt(decisionStartState, alt); if (synpred == null) { synpred = new SemanticContext.TruePredicate(); } s.AddTransition(predDFATarget, new PredicateLabel(synpred)); } } } //[email protected]("dfa for preds=\n"+this); }
public void AddState( NFAState state ) { grammar.composite.AddState( state ); }
protected virtual void AddFollowTransition( string ruleName, NFAState following ) { //System.Console.Out.WriteLine( "adding follow link to rule " + ruleName ); // find last link in FOLLOW chain emanating from rule Rule r = grammar.GetRule( ruleName ); NFAState end = r.StopState; while ( end.GetTransition( 1 ) != null ) { end = (NFAState)end.GetTransition( 1 ).Target; } if ( end.GetTransition( 0 ) != null ) { // already points to a following node // gotta add another node to keep edges to a max of 2 NFAState n = factory.NewState(); Transition e = new Transition( Label.EPSILON, n ); end.AddTransition( e ); end = n; } Transition followEdge = new Transition( Label.EPSILON, following ); end.AddTransition( followEdge ); }