对于ANTLR3异常,antlrworks可以工作,但生成的java代码无法正常工作

时间:2016-01-25 13:36:04

标签: java antlr antlr3

我想解析包含andor关键字的SQL表达式。问题是Antlrwork可以为错误语法抛出异常,但生成的java代码不能抛出异常。同时,我发现生成的java代码是错误的,只能生成 AST 的一半并且没有错误信息,执行路径无法达到异常点。

这是我的dot g文件:

 grammar ContainsExpr;

    options {
      language = Java;
      output=AST;
      ASTLabelType=CommonTree;
    }

    tokens {
        DIVIDE = '/' ;
        PLUS = '+' ;
        MINUS = '-' ;
        STAR = '*' ;
        MOD = '%' ;

        AMPERSAND = '&' ;
        TILDE = '~' ;
        BITWISEOR = '|' ;
        COMMA = ',';
        DOT = '.';
        LPAREN = '(' ;
        RPAREN = ')' ;

        EQUAL = '=';
        NOTEQUAL = '!=';
        LESSTHANOREQUALTO = '<=';
        LESSTHAN = '<';
        GREATERTHANOREQUALTO = '>=';
        GREATERTHAN = '>';

        AND = 'AND';
        OR = 'OR' ;
        TRUE = 'TRUE';
        FALSE = 'FALSE';
        KW_NEAR = 'NEAR';
        DOUBLE_QUOTE = '\"';
        SINGLE_QUOTE = '\'';

        TOK_NEAR;
        TOK_ITEMS;
        TOK_PARAMETER;
        TOK_WILDCARDS;
    }

    @header {
    package test1;
    }

    @members {

       //override method
      public void reportError(RecognitionException e) {
        displayRecognitionError(this.getTokenNames(), e);
      }

     @Override
      public void emitErrorMessage(String message) {
        throw new RuntimeException(message);
      }
    }

    @lexer::header {
    package test1;
    }

    @lexer::members {

       //override method
      public void reportError(RecognitionException e) {
        displayRecognitionError(this.getTokenNames(), e);
      }
    }

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

    // LITERALS
    fragment
    Letter
        : 'a'..'z' | 'A'..'Z'
        ;

    fragment
    Digit
        :
        '0'..'9'
        ;

    fragment
    Exponent
        :
        ('e' | 'E') ( PLUS|MINUS )? (Digit)+
        ;

    Number
        :
        (Digit)+ ( DOT (Digit)* (Exponent)? | Exponent)?
        ;

    fragment
    UnquotedString
        :  
          ( ~(SINGLE_QUOTE|DOUBLE_QUOTE|' '|'\t'|'\n'|LPAREN|RPAREN|COMMA))+
        ;

    fragment
    QuotedLiteral
        :
        DOUBLE_QUOTE ( ~(DOUBLE_QUOTE|'\\') | ('\\' .) )* DOUBLE_QUOTE 
        ;

    Parameter
        :
        UnquotedString | QuotedLiteral
        ;

    WS  :  (' '|'\r'|'\t'|'\n'|'\u000C')* {$channel=HIDDEN;}
        ;

    eval
        :
        searchCondition 
        ;

    //AND has precedence over OR    
    searchCondition
        :
        andExpr (precedenceOrOperator^ andExpr)*
        ;

    andExpr
        :
        subCondition (precedenceAndOperator^ subCondition)*
        ;

    precedenceAndOperator
        :
        AND | AMPERSAND
        ;

    precedenceOrOperator
        :
        OR | BITWISEOR
        ;

    subCondition 
        : 
          atom
        | LPAREN searchCondition RPAREN
        ;

    atom 
        :
        subEressixpon      
        ;

    subEressixpon  
        :
          Parameter -> ^(TOK_PARAMETER Parameter) 
        ;

输入错误的表达式expr1 epxr2(跳过 AND )时,java代码的执行结果为“expr1”。

生成的 searchCondition 规则的java代码不正确:

try {
            //  ( andExpr ( precedenceOrOperator ^ andExpr )* )
            //  andExpr ( precedenceOrOperator ^ andExpr )*
            {
            root_0 = (CommonTree)adaptor.nil();


            pushFollow(FOLLOW_andExpr_in_searchCondition714);
            andExpr2=andExpr();
            state._fsp--;

            adaptor.addChild(root_0, andExpr2.getTree());

            // ( precedenceOrOperator ^ andExpr )*
            loop1:
            while (true) {
                int alt1=2;
                int LA1_0 = input.LA(1);
                if ( (LA1_0==BITWISEOR||LA1_0==OR) ) {
                    alt1=1;
                }

                switch (alt1) {
                case 1 :
                    // precedenceOrOperator ^ andExpr
                    {
                    pushFollow(FOLLOW_precedenceOrOperator_in_searchCondition717);
                    precedenceOrOperator3=precedenceOrOperator();
                    state._fsp--;

                    root_0 = (CommonTree)adaptor.becomeRoot(precedenceOrOperator3.getTree(), root_0);
                    pushFollow(FOLLOW_andExpr_in_searchCondition720);
                    andExpr4=andExpr();
                    state._fsp--;

                    adaptor.addChild(root_0, andExpr4.getTree());

                    }
                    break;

                default :
                    break loop1;
                }
            }

            }

            retval.stop = input.LT(-1);

            retval.tree = (CommonTree)adaptor.rulePostProcessing(root_0);
            adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop);

        }

            catch (RecognitionException e) {
              reportError(e);
              throw e;
            }

        finally {
            // do for sure before leaving
        }

while循环中,当LA1_0OR关键字时,它将成为异常的正常到达点。所以它不会抛出异常。

2 个答案:

答案 0 :(得分:2)

自从我使用antlr以来已经有一段时间了,但你可以看看这里。

How Get error messages of antlr parsing?

您可以从解析器中获取错误消息。

希望这会有所帮助。干杯

答案 1 :(得分:1)

好的,我可以在第一时间确认你的问题,但经过一点点诀窍后就可以了。

我更改了3件事:

  1. 在解析器规则之后放置词法规则
  2. 在您的顶级解析器规则
  3. 中添加了EOF符号
  4. 仅覆盖所需的两种方法&#34; reportError&#34;在解析器和词法分析器
  5. 玩得开心,继续问^^

    grammar ContainsExpr;
    
        options {
          language = Java;
          output=AST;
          ASTLabelType=CommonTree;
        }
    
        tokens {
            DIVIDE = '/' ;
            PLUS = '+' ;
            MINUS = '-' ;
            STAR = '*' ;
            MOD = '%' ;
    
            AMPERSAND = '&' ;
            TILDE = '~' ;
            BITWISEOR = '|' ;
            COMMA = ',';
            DOT = '.';
            LPAREN = '(' ;
            RPAREN = ')' ;
    
            EQUAL = '=';
            NOTEQUAL = '!=';
            LESSTHANOREQUALTO = '<=';
            LESSTHAN = '<';
            GREATERTHANOREQUALTO = '>=';
            GREATERTHAN = '>';
    
            AND = 'AND';
            OR = 'OR' ;
            TRUE = 'TRUE';
            FALSE = 'FALSE';
            KW_NEAR = 'NEAR';
            DOUBLE_QUOTE = '\"';
            SINGLE_QUOTE = '\'';
    
            TOK_NEAR;
            TOK_ITEMS;
            TOK_PARAMETER;
            TOK_WILDCARDS;
        }
    
        @header {
        package test1;
        }
    
        @lexer::header {
        package test1;
        }
    
        @parser::members {
          @Override
          public void reportError(RecognitionException e) {
            throw new RuntimeException("I quit!\n" + e.getMessage()); 
          }
        }
    
        @lexer::members {
          @Override
          public void reportError(RecognitionException e) {
            throw new RuntimeException("I quit!\n" + e.getMessage()); 
          }
        }
    
        eval
            :
            searchCondition EOF
            ;
    
        //AND has precedence over OR    
        searchCondition
            :
            andExpr (precedenceOrOperator^ andExpr)*
            ;
    
        andExpr
            :
            subCondition (precedenceAndOperator^ subCondition)*
            ;
    
        precedenceAndOperator
            :
            AND | AMPERSAND
            ;
    
        precedenceOrOperator
            :
            OR | BITWISEOR
            ;
    
        subCondition 
            : 
              atom
            | LPAREN searchCondition RPAREN
            ;
    
        atom 
            :
            subEressixpon      
            ;
    
        subEressixpon  
            :
              Parameter -> ^(TOK_PARAMETER Parameter) 
            ;
    
        // LITERALS
        fragment
        Letter
            : 'a'..'z' | 'A'..'Z'
            ;
    
        fragment
        Digit
            :
            '0'..'9'
            ;
    
        fragment
        Exponent
            :
            ('e' | 'E') ( PLUS|MINUS )? (Digit)+
            ;
    
        Number
            :
            (Digit)+ ( DOT (Digit)* (Exponent)? | Exponent)?
            ;
    
        fragment
        UnquotedString
            :  
              ( ~(SINGLE_QUOTE|DOUBLE_QUOTE|' '|'\t'|'\n'|LPAREN|RPAREN|COMMA))+
            ;
    
        fragment
        QuotedLiteral
            :
            DOUBLE_QUOTE ( ~(DOUBLE_QUOTE|'\\') | ('\\' .) )* DOUBLE_QUOTE 
            ;
    
        Parameter
            :
            UnquotedString | QuotedLiteral
            ;
    
        WS  :  (' '|'\r'|'\t'|'\n'|'\u000C')* {$channel=HIDDEN;}
            ;
    

    这是我的小测试案例

    package test1;
    
    import junit.framework.TestCase;
    
    import org.antlr.runtime.ANTLRStringStream;
    import org.antlr.runtime.CommonTokenStream;
    import org.antlr.runtime.TokenStream;
    import org.junit.Assert;
    
    public class Test extends TestCase {
    
        public void test() {
            String test = "expr1 epxr2"; // AND missing
    
            ANTLRStringStream input = new ANTLRStringStream(test);
            TokenStream tokens = new CommonTokenStream(new ContainsExprLexer(input));
            ContainsExprParser parser = new ContainsExprParser(tokens);
    
            try {
                parser.eval();
                Assert.fail("Should throw Exception");
            } catch (Exception e) {
                //jippi
                System.out.println(e);
            }
        }
    }
    

    结果

    java.lang.RuntimeException: I quit!
    null
    

    <强>更新

    我发现自己是我答案的一部分 ANTLR not throwing errors on invalid input