public LookaheadSet LOOK(NFAState s) { if (NFAToDFAConverter.debug) { System.out.println("> LOOK(" + s + ")"); } lookBusy.clear(); LookaheadSet look = _FIRST(s, true); // FOLLOW makes no sense (at the moment!) for lexical rules. if (grammar.type != Grammar.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 == Grammar.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) { System.out.println("< LOOK(" + s + ")=" + look.toString(grammar)); } return look; }
protected LookaheadSet _FIRST(NFAState s, boolean chaseFollowTransitions) { /* System.out.println("_LOOK("+s+") in rule "+s.enclosingRule); if ( s.transition[0] instanceof RuleClosureTransition ) { System.out.println("go to rule "+((NFAState)s.transition[0].target).enclosingRule); } */ if (!chaseFollowTransitions && s.isAcceptState()) { if (grammar.type == Grammar.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.getAtom(); return new LookaheadSet(atom); } if (transition0.label.isSet()) { IntSet sl = transition0.label.getSet(); 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 instanceof 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 = _FIRST((NFAState) transition0.target, chaseFollowTransitions); // save FIRST cache for transition 0 if rule call if (!chaseFollowTransitions && transition0 instanceof RuleClosureTransition) { FIRSTCache.put((NFAState) transition0.target, tset); } } // did we fall off the end? if (grammar.type != Grammar.LEXER && tset.member(Label.EOR_TOKEN_TYPE)) { if (transition0 instanceof 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 = _FIRST(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 = _FIRST((NFAState) transition1.target, chaseFollowTransitions); tset1.orInPlace(tset); // tset cached; or into new set tset = tset1; } return tset; }