我想解析包含and
和or
关键字的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_0
为OR
关键字时,它将成为异常的正常到达点。所以它不会抛出异常。
答案 0 :(得分:2)
答案 1 :(得分:1)
好的,我可以在第一时间确认你的问题,但经过一点点诀窍后就可以了。
我更改了3件事:
玩得开心,继续问^^
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