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); }
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) { _firstCache.TryGetValue((NFAState)transition0.Target, out tset); } // 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; } } LookaheadSet tsetCached = tset; // tset is stored in cache. We can't return the same instance // 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); 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; } // never return a cached set; clone return(tset == tsetCached ? new LookaheadSet(tset) : tset); }