2012-11-29 4 views
7

私はAntlr 3を使用してASTツリーを使用して複雑な文法を開発しました。 ANTLRはLexerとParserを生成します。問題は、例えば、ユーザーが有効でない構文を入力すると、文法が ';'を予期していることです。ユーザーがこれを入力しない場合、私のEclipse IDEに私は次の例外を取得:私はこの例外をキャッチしようとするためAntlr例外の処理

line 1:24 mismatched input '<EOF>' expecting ';' 

どのようにこの例外を処理することができますが、例外がcatchedされていません。これは例外ですか?なぜこの例外がキャッチされていないのか分かりません。私は見つけようとしましたが、Antlrのウェブサイトは今のところダウンしているようです。

ANTLR exception handling with "$", Javaを見て、その例に従いましたが、LexerがRuntimeException()を追加してコードを生成すると、到達不能なコードが取得されます。

私は何をすべきかわかりません。

私は、パーサーから構文エラーの数を取得しようとすると、それは0

EDIT表示されます場合は、しかし、ANTLR not throwing errors on invalid input

:私はを見ることで機能するソリューションを見つけた

を私は、例外メッセージを取得しようとすると、それはnullです。すべてを正しく設定しましたか?

grammar i; 

options { 
output=AST; 
} 

@header { 
package com.data; 
} 

@rulecatch { 
    catch(RecognitionException e) { 
     throw e; 
    } 
} 

// by having these below it makes no difference 
/**@parser::members { 
    @Override 
    public void reportError(RecognitionException e) { 
     throw new RuntimeException("Exception : " + " " + e.getMessage()); 
    } 
} 

@lexer::members { 
    @Override 
    public void reportError(RecognitionException e) { 
     throw new RuntimeException("Exception : " + " " + e.getMessage()); 
    } 
}*/ 

はEDIT:

私がこれまで持っているものを見てください:

grammar i; 

options { 
output=AST; 
} 

@header { 
package com.data; 
} 

@rulecatch { 
    // ANTLR does not generate its normal rule try/catch 
    catch(RecognitionException e) { 
     throw e; 
    } 
} 

@parser::members { 
    @Override 
    public void displayRecognitionError(String[] tokenNames, RecognitionException e) { 
     String hdr = getErrorHeader(e); 
     String msg = getErrorMessage(e, tokenNames); 
     throw new RuntimeException(hdr + ":" + msg); 
    } 
} 

@lexer::members { 
    @Override 
    public void displayRecognitionError(String[] tokenNames, RecognitionException e) { 
     String hdr = getErrorHeader(e); 
     String msg = getErrorMessage(e, tokenNames); 
     throw new RuntimeException(hdr + ":" + msg); 
    } 
} 

operatorLogic : 'AND' | 'OR'; 
value  : STRING; 
query  : (select)*; 
select  : 'SELECT'^ functions 'FROM table' filters?';'; 
operator : '=' | '!=' | '<' | '>' | '<=' | '>='; 
filters : 'WHERE'^ conditions; 
members : STRING operator value; 
conditions : (members (operatorLogic members)*); 
functions : '*'; 
STRING : ('a'..'z'|'A'..'Z')+; 
WS  : (' '|'\t'|'\f'|'\n'|'\r')+ {skip();}; // handle white space between keywords 

public class Processor { 

public Processor() { 

} 

/** 
* This method builds the MQL Parser. 
* @param args the args. 
* @return the built IParser. 
*/ 
private IParser buildMQLParser(String query) { 
    CharStream cs = new ANTLRStringStream(query); 
    // the input needs to be lexed 
    ILexer lexer = new ILexer(cs); 
      CommonTokenStream tokens = new CommonTokenStream(); 
    IParser parser = new IParser(tokens); 
    tokens.setTokenSource(lexer); 
    // use the ASTTreeAdaptor so that the grammar is aware to build tree in AST format 
    parser.setTreeAdaptor((TreeAdaptor) new ASTTreeAdaptor().getASTTreeAdaptor()); 
return parser; 
} 

/** 
* This method parses the MQL query. 
* @param query the query. 
*/ 
public void parseMQL(String query) { 
    IParser parser = buildMQLParser(query); 
    CommonTree commonTree = null; 
    try { 
        commonTree = (CommonTree) parser.query().getTree(); 
        } 
    catch(Exception e) { 
     System.out.println("Exception :" + " " + e.getMessage()); 
    } 
} 
} 

public class ASTTreeAdaptor { 

public ASTTreeAdaptor() { 

} 

/** 
* This method is used to create a TreeAdaptor. 
* @return a treeAdaptor. 
*/ 
public Object getASTTreeAdaptor() { 
    TreeAdaptor treeAdaptor = new CommonTreeAdaptor() { 
     public Object create(Token payload) { 
     return new CommonTree(payload); 
     } 
    }; 
    return treeAdaptor; 
} 
} 

だから私は、次を入力したとき: SELECT *テーブル

FROMなしサンプル文法を参照してください。 a ';'私がしようとすると

catch(Exception e) { 
    System.out.println("Exception : " + " " e); 
} 

:私はMismatchedTokenExceptionを取得

e.getMessage(); 

それはnullを返します。

答えて

5

代わりdisplayRecognitionErrorをオーバーライドしてみてください。

@parser::members { 
    ... 

    @Override  
    public void displayRecognitionError(String[] tokenNames, RecognitionException e) { 
     String hdr = getErrorHeader(e); 
     String msg = getErrorMessage(e, tokenNames); 
     throw new RuntimeException(hdr + ":" + msg); 
    } 
    ... 
} 
//same code in @lexer::members 

あなたがエラーを追跡ではなく、中止したい場合は、あなたがそれらを追跡するために、ハンドラ・インタフェースを作成することができます。

@parser::members { 
    ... 
    private YourErrorTrackerInterface errorTracker; 

    //getter/setter for errorTracker here   

    @Override  
    public void displayRecognitionError(String[] tokenNames, RecognitionException e) { 
     String hdr = getErrorHeader(e); 
     String msg = getErrorMessage(e, tokenNames); 
     if (errorTracker != null){ 
      errorTracker.addError(e, tokenNames, hdr, msg); 
     } 
    } 
    ... 
} 
//same code in @lexer::members 

エラートラッカーが、その後かどうかを決めることができました例外をスローするか、続行します。


上記のコードでは、あなたは、「回復可能」エラー、ANTLRはスキップすることができますエラーを追跡することができます。 SELECT * FROM table(末尾に;なし)などの回復不能なエラーが発生するシナリオはまだあります。その場合は、parseMQLまたはその周辺の例外をキャッチする必要があります。 (あなた自身のリカバリコードを書こうとすることもできますが、私はそうしないことをお勧めします)

ここには2種類の解析エラーを示す修正済みparseMQLがあります。いないすべての例外は、RecognitionExceptionのオフ派生でそれを埋めるために、私はgetMessageへの呼び出しを削除したことに注意してください

public void parseMQL(String query) { 
    iParser parser = buildMQLParser(query); 
    CommonTree commonTree = null; 
    try { 
     commonTree = (CommonTree) parser.query().getTree(); 
    } catch (MismatchedTokenException e){ 
     //not production-quality code, just forming a useful message 
     String expected = e.expecting == -1 ? "<EOF>" : iParser.tokenNames[e.expecting]; 
     String found = e.getUnexpectedType() == -1 ? "<EOF>" : iParser.tokenNames[e.getUnexpectedType()]; 

     System.out.println("Fatal mismatched token exception: expected " + expected + " but was " + found); 

    } catch (RecognitionException e) { 
     System.out.println("Fatal recognition exception " + e.getClass().getName() 
       + " : " + e); 

    } catch (Exception e) { 
     System.out.println("Other exception : " + e.getMessage()); 
    } 
} 

入力SELECT * FROM tableは「致命的な不一致のトークン例外メッセージを生成します。予想 『;』 <EOF> "でした。この例外はANTLRによって直接生成されたものです。

入力SELECT FROM table;は、「他の例外:行1:7: 'FROMテーブル'に「*」がありません」というメッセージを生成します。この例外は上記のコードによって生成されました。

+0

これも機能しません。メッセージを取り戻そうとすると、いつものようにヌルに戻ります。 – user1646481

+0

私が今持っているもので上記の編集をご覧ください。たぶん私はここで何か間違っています。私は例外を追跡するのではなく、実際にそれらを印刷したいと思います。 – user1646481

+0

これが役立つかどうかわからない場合:http://stackoverflow.com/questions/4627244/catching-errors-in-antlr-and-finding-parent – user1646481

1

正しく理解していれば、言語の構文エラーを処理したいと思っています。これは私のプロジェクトでこの設定をする方法です。ここで

/** 
* Adapter need for ANTL to recognize our custom nodes 
* 
* @author Greg 
*/ 
public class PhantomTreeAdaptor extends CommonTreeAdaptor{ 

    @Override 
    public Object create(Token payload){ 
     return new ASTNode(payload); 
    } 

    @Override 
    public Object dupNode(Object old){ 
     return (old == null) ? null : ((ASTNode) old).dupNode(); 
    } 

    @Override 
    public Object errorNode(TokenStream input, Token start, Token stop, RecognitionException e){ 
     return new ASTErrorNode(input, start, stop, e); 
    } 
} 

は、エラー・ノード

/** 
* This is our custom Error node used by the adapter. 
* 
* @author Greg 
*/ 
public class ASTErrorNode extends ASTNode { 

    org.antlr.runtime.tree.CommonErrorNode delegate; 

    public ASTErrorNode(TokenStream input, Token start, Token stop, RecognitionException e) { 

     delegate = new CommonErrorNode(input, start, stop, e); 

    } 

    public boolean isNil() { 
     return delegate.isNil(); 
    } 

    public int getType() { 
     return delegate.getType(); 
    } 

    public String getText() { 
     return delegate.getText(); 
    } 

    public String toString() { 

     return delegate.toString(); 
    } 

} 

であり、これは、これはすべて一緒に接着する方法です。

final PhantomSQLLexer lex = new PhantomSQLLexer(input); 

     final CommonTokenStream tokens = new CommonTokenStream(lex); 
     final PhantomSQLParser g = new PhantomSQLParser(tokens); 
     g.setTreeAdaptor(new PhantomTreeAdaptor()); 
     final start_rule_return r = g.start_rule(); 
     if (g.getNumberOfSyntaxErrors() == 0) { 
      if (LOGGER.isDebugEnabled()) { 
       LOGGER.debug("tree=" + ((Tree) r.tree).toStringTree()); 
       LOGGER.debug("-------------------------------------------"); 
      } 
      final ASTNode root = r.tree; 
      exec(root);    
     } 
     else { 
      LOGGER.debug("Error parsing input"); 
     } 

私たちは単にレクサーとパーサーを作成し、カスタムツリーアダプター(PhantomTreeAdaptor)でパーサーをセットアップしました。そこから、カスタムコードにエラーがあるかどうかを確認できます。

+0

また、カスタムTreeAdaptorをセットアップして、ツリーからデータを取得することもできます。上記の私の編集では、例外のタイプは取得できますが、メッセージの詳細は返されません。 – user1646481

+0

この回答は、問題に答えるようではありません。私はExceptionクラスの名前を得ることができますが、メッセージの詳細を返すことができないので、何をすべきかわかりません。 – user1646481

+0

「ASTErrorNode」を見ると、RecognitionException Type/Text/ExceptionTypeに関するすべての情報がそこにあります。 – Greg