Package org.antlr.tool

Source Code of org.antlr.tool.Interpreter$LexerActionGetTokenType

/*
* [The "BSD license"]
*  Copyright (c) 2010 Terence Parr
*  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.
*/
package org.antlr.tool;

import org.antlr.analysis.DFA;
import org.antlr.analysis.*;
import org.antlr.misc.IntervalSet;
import org.antlr.runtime.*;
import org.antlr.runtime.debug.BlankDebugEventListener;
import org.antlr.runtime.debug.DebugEventListener;
import org.antlr.runtime.debug.ParseTreeBuilder;
import org.antlr.runtime.tree.ParseTree;

import java.util.List;
import java.util.Stack;

/** The recognition interpreter/engine for grammars.  Separated
*  out of Grammar as it's related, but technically not a Grammar function.
*  You create an interpreter for a grammar and an input stream.  This object
*  can act as a TokenSource so that you can hook up two grammars (via
*  a CommonTokenStream) to lex/parse.  Being a token source only makes sense
*  for a lexer grammar of course.
*/
public class Interpreter implements TokenSource {
  protected Grammar grammar;
  protected IntStream input;

  /** A lexer listener that just creates token objects as they
   *  are matched.  scan() use this listener to get a single object.
   *  To get a stream of tokens, you must call scan() multiple times,
   *  recording the token object result after each call.
   */
  class LexerActionGetTokenType extends BlankDebugEventListener {
    public CommonToken token;
    Grammar g;
    public LexerActionGetTokenType(Grammar g) {
      this.g = g;
    }

    @Override
    public void exitRule(String grammarFileName, String ruleName) {
      if ( !ruleName.equals(Grammar.ARTIFICIAL_TOKENS_RULENAME) ){
        int type = g.getTokenType(ruleName);
        int channel = Token.DEFAULT_CHANNEL;
        token = new CommonToken((CharStream)input,type,channel,0,0);
      }
    }
  }

  public Interpreter(Grammar grammar, IntStream input) {
    this.grammar = grammar;
    this.input = input;
  }

  @Override
  public Token nextToken() {
    if ( grammar.type!=Grammar.LEXER ) {
      return null;
    }
    if ( input.LA(1)==CharStream.EOF ) {
            return new CommonToken((CharStream)input,Token.EOF,Token.DEFAULT_CHANNEL,input.index(),input.index());
    }
    int start = input.index();
    int charPos = ((CharStream)input).getCharPositionInLine();
    CommonToken token = null;
    loop:
    while (input.LA(1)!=CharStream.EOF) {
      try {
        token = scan(Grammar.ARTIFICIAL_TOKENS_RULENAME, null);
        break;
      }
      catch (RecognitionException re) {
        // report a problem and try for another
        reportScanError(re);
        continue loop;
      }
    }
    // the scan can only set type
    // we must set the line, and other junk here to make it a complete token
    int stop = input.index()-1;
    if ( token==null ) {
            return new CommonToken((CharStream)input,Token.EOF,Token.DEFAULT_CHANNEL,start,start);
    }
    token.setLine(((CharStream)input).getLine());
    token.setStartIndex(start);
    token.setStopIndex(stop);
    token.setCharPositionInLine(charPos);
    return token;
  }

  /** For a given input char stream, try to match against the NFA
   *  starting at startRule.  This is a deterministic parse even though
   *  it is using an NFA because it uses DFAs at each decision point to
   *  predict which alternative will succeed.  This is exactly what the
   *  generated parser will do.
   *
   *  This only does lexer grammars.
   *
   *  Return the token type associated with the final rule end state.
   */
  public void scan(String startRule,
           DebugEventListener actions,
           List<NFAState> visitedStates)
    throws RecognitionException
  {
    if ( grammar.type!=Grammar.LEXER ) {
      return;
    }

    //System.out.println("scan("+startRule+",'"+in.substring(in.index(),in.size()-1)+"')");
    // Build NFAs/DFAs from the grammar AST if NFAs haven't been built yet
    if ( grammar.getRuleStartState(startRule)==null ) {
      grammar.buildNFA();
    }

    if ( !grammar.allDecisionDFAHaveBeenCreated() ) {
      // Create the DFA predictors for each decision
      grammar.createLookaheadDFAs();
    }

    // do the parse
    Stack<NFAState> ruleInvocationStack = new Stack<NFAState>();
    NFAState start = grammar.getRuleStartState(startRule);
    NFAState stop = grammar.getRuleStopState(startRule);
    parseEngine(startRule, start, stop, input, ruleInvocationStack,
          actions, visitedStates);
  }

  public CommonToken scan(String startRule)
    throws RecognitionException
  {
    return scan(startRule, null);
  }

  public CommonToken scan(String startRule,
              List<NFAState> visitedStates)
    throws RecognitionException
  {
    LexerActionGetTokenType actions = new LexerActionGetTokenType(grammar);
    scan(startRule, actions, visitedStates);
    return actions.token;
  }

  public void parse(String startRule,
            DebugEventListener actions,
            List<NFAState> visitedStates)
    throws RecognitionException
  {
    //System.out.println("parse("+startRule+")");
    // Build NFAs/DFAs from the grammar AST if NFAs haven't been built yet
    if ( grammar.getRuleStartState(startRule)==null ) {
      grammar.buildNFA();
    }
    if ( !grammar.allDecisionDFAHaveBeenCreated() ) {
      // Create the DFA predictors for each decision
      grammar.createLookaheadDFAs();
    }
    // do the parse
    Stack<NFAState> ruleInvocationStack = new Stack<NFAState>();
    NFAState start = grammar.getRuleStartState(startRule);
    NFAState stop = grammar.getRuleStopState(startRule);
    parseEngine(startRule, start, stop, input, ruleInvocationStack,
          actions, visitedStates);
  }

  public ParseTree parse(String startRule)
    throws RecognitionException
  {
    return parse(startRule, null);
  }

  public ParseTree parse(String startRule, List<NFAState> visitedStates)
    throws RecognitionException
  {
    ParseTreeBuilder actions = new ParseTreeBuilder(grammar.name);
    try {
      parse(startRule, actions, visitedStates);
    }
    catch (RecognitionException re) {
      // Errors are tracked via the ANTLRDebugInterface
      // Exceptions are used just to blast out of the parse engine
      // The error will be in the parse tree.
    }
    return actions.getTree();
  }

  /** Fill a list of all NFA states visited during the parse */
  protected void parseEngine(String startRule,
                 NFAState start,
                 NFAState stop,
                 IntStream input,
                 Stack<NFAState> ruleInvocationStack,
                 DebugEventListener actions,
                 List<NFAState> visitedStates)
    throws RecognitionException
  {
    NFAState s = start;
    if ( actions!=null ) {
      actions.enterRule(s.nfa.grammar.getFileName(), start.enclosingRule.name);
    }
    int t = input.LA(1);
    while ( s!=stop ) {
      if ( visitedStates!=null ) {
        visitedStates.add(s);
      }
      /*
      System.out.println("parse state "+s.stateNumber+" input="+
        s.nfa.grammar.getTokenDisplayName(t));
        */
      // CASE 1: decision state
      if ( s.getDecisionNumber()>0 && s.nfa.grammar.getNumberOfAltsForDecisionNFA(s)>1 ) {
        // decision point, must predict and jump to alt
        DFA dfa = s.nfa.grammar.getLookaheadDFA(s.getDecisionNumber());
        /*
        if ( s.nfa.grammar.type!=Grammar.LEXER ) {
          System.out.println("decision: "+
                   dfa.getNFADecisionStartState().getDescription()+
                   " input="+s.nfa.grammar.getTokenDisplayName(t));
        }
        */
        int m = input.mark();
        int predictedAlt = predict(dfa);
        if ( predictedAlt == NFA.INVALID_ALT_NUMBER ) {
          String description = dfa.getNFADecisionStartState().getDescription();
          NoViableAltException nvae =
            new NoViableAltException(description,
                            dfa.getDecisionNumber(),
                            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!=Grammar.LEXER ) {
          System.out.println("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.getFileName(), s.enclosingRule.name);
        }
        if ( ruleInvocationStack.empty() ) {
          // done parsing.  Hit the start state.
          //System.out.println("stack empty in stop state for "+s.getEnclosingRule());
          break;
        }
        // pop invoking state off the stack to know where to return to
        NFAState invokingState = 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 instanceof RuleClosureTransition ) {
          ruleInvocationStack.push(s);
          s = (NFAState)trans.target;
          //System.out.println("call "+s.enclosingRule.name+" from "+s.nfa.grammar.getFileName());
          if ( actions!=null ) {
            actions.enterRule(s.nfa.grammar.getFileName(), 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 == Grammar.PARSER ||
             s.nfa.grammar.type == Grammar.COMBINED )
          {
            actions.consumeToken(((TokenStream)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.getAtom(), input);
          if ( actions!=null ) {
            actions.recognitionException(mte);
          }
          input.consume(); // recover
          throw mte;
        }
        else if ( label.isSet() ) {
          MismatchedSetException mse =
            new MismatchedSetException(((IntervalSet)label.getSet()).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.getSemanticContext().toString());
          if ( actions!=null ) {
            actions.recognitionException(fpe);
          }
          input.consume(); // recover
          throw fpe;
        }
        else {
          throw new RecognitionException(input); // unknown error
        }
      }
    }
    //System.out.println("hit stop state for "+stop.getEnclosingRule());
    if ( actions!=null ) {
      actions.exitRule(s.nfa.grammar.getFileName(), stop.enclosingRule.name);
    }
  }

  /** Given an input stream, return the unique alternative predicted by
   *  matching the input.  Upon error, return NFA.INVALID_ALT_NUMBER
   *  The first symbol of lookahead is presumed to be primed; that is,
   *  input.lookahead(1) must point at the input symbol you want to start
   *  predicting with.
   */
  public int predict(DFA dfa) {
    DFAState s = dfa.startState;
    int c = input.LA(1);
    Transition eotTransition = null;
  dfaLoop:
    while ( !s.isAcceptState() ) {
      /*
      System.out.println("DFA.predict("+s.getStateNumber()+", "+
          dfa.getNFA().getGrammar().getTokenName(c)+")");
      */
      // for each edge of s, look for intersection with current char
      for (int i=0; i<s.getNumberOfTransitions(); i++) {
        Transition t = s.transition(i);
        // special case: EOT matches any char
        if ( t.label.matches(c) ) {
          // take transition i
          s = (DFAState)t.target;
          input.consume();
          c = input.LA(1);
          continue dfaLoop;
        }
        if ( t.label.getAtom()==Label.EOT ) {
          eotTransition = t;
        }
      }
      if ( eotTransition!=null ) {
        s = (DFAState)eotTransition.target;
        continue dfaLoop;
      }
      /*
      ErrorManager.error(ErrorManager.MSG_NO_VIABLE_DFA_ALT,
                 s,
                 dfa.nfa.grammar.getTokenName(c));
      */
      return NFA.INVALID_ALT_NUMBER;
    }
    // woohoo!  We know which alt to predict
    // nothing emanates from a stop state; must terminate anyway
    /*
    System.out.println("DFA stop state "+s.getStateNumber()+" predicts "+
        s.getUniquelyPredictedAlt());
    */
    return s.getUniquelyPredictedAlt();
  }

  public void reportScanError(RecognitionException re) {
    CharStream cs = (CharStream)input;
    // print as good of a message as we can, given that we do not have
    // a Lexer object and, hence, cannot call the routine to get a
    // decent error message.
    System.err.println("problem matching token at "+
      cs.getLine()+":"+cs.getCharPositionInLine()+" "+re);
  }

  @Override
  public String getSourceName() {
    return input.getSourceName();
  }

}
TOP

Related Classes of org.antlr.tool.Interpreter$LexerActionGetTokenType

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.