使用ANTLR嵌套的布尔表达式解析器

时间:2015-06-22 09:53:49

标签: java parsing antlr antlr4 antlr3

我正在尝试解析嵌套的布尔表达式并分别获取表达式中的各个条件。例如,如果输入字符串是:

(A = a OR B = b OR C = c AND((D = d AND E = e)OR(F = f AND G = g)))

我想以正确的顺序获得条件。即,

D = d和E = e 要么 F = f AND G = g 和 A = a OR B = b OR C = c

我正在使用ANTLR 4来解析输入文本,这是我的语法:

grammar SimpleBoolean;

rule_set : nestedCondition* EOF;

AND : 'AND' ;
OR  : 'OR' ;
NOT : 'NOT';

TRUE  : 'TRUE' ;
FALSE : 'FALSE' ;

GT : '>' ;
GE : '>=' ;
LT : '<' ;
LE : '<=' ;
EQ : '=' ;

LPAREN : '(' ;
RPAREN : ')' ;

DECIMAL : '-'?[0-9]+('.'[0-9]+)? ;

IDENTIFIER : [a-zA-Z_][a-zA-Z_0-9]* ;

WS : [ \r\t\u000C\n]+ -> skip;

nestedCondition : LPAREN condition+ RPAREN (binary nestedCondition)*;
condition: predicate (binary predicate)*
            | predicate (binary component)*;
component: predicate | multiAttrComp;
multiAttrComp : LPAREN predicate (and predicate)+ RPAREN;
predicate : IDENTIFIER comparator IDENTIFIER;
comparator : GT | GE | LT | LE | EQ ;
binary: AND | OR ;
unary: NOT;
and: AND;

这是我用来解析它的Java代码:

ANTLRInputStream inputStr = new ANTLRInputStream(input);
SimpleBooleanLexer lexer = new SimpleBooleanLexer(inputStr);
TokenStream tokens = new CommonTokenStream(lexer);
SimpleBooleanParser parser = new SimpleBooleanParser(tokens);
parser.getBuildParseTree();
ParseTree tree = parser.rule_set();
System.out.println(tree.toStringTree(parser));

输出结果为:

(rule_set (nestedCondition ( (condition (predicate A (comparator =) a) (binary OR) (component (predicate B (comparator =) b)) (binary OR) (component (predicate C (comparator =) c)) (binary AND) (component (multiAttrComp ( (predicate ( D (comparator =) d) (and AND) (predicate E (comparator =) e) ))) (binary OR) (component (multiAttrComp ( (predicate F (comparator =) f) (and AND) (predicate G (comparator =) g) )))) ) )) <EOF>)

我正在寻找有关如何解析此树以获得正确顺序条件的帮助?在ANTLR 3中,我们可以指定^和!决定如何构建树(请参阅此thread),但我了解到ANTLR 4不支持这种情况。

有人可以建议我如何使用ANTLR创建的ParseTree以正确的顺序解析String吗?

1 个答案:

答案 0 :(得分:22)

我只是将所有表达式包装到单个expression规则中。确保在 comparator表达式替代之前定义binary表达式替代,以确保comparator运算符比OR和{{1}更紧密地绑定}}:

AND

要测试上面的语法,请使用以下快速和肮脏的测试类:

grammar SimpleBoolean;

parse
 : expression EOF
 ;

expression
 : LPAREN expression RPAREN                       #parenExpression
 | NOT expression                                 #notExpression
 | left=expression op=comparator right=expression #comparatorExpression
 | left=expression op=binary right=expression     #binaryExpression
 | bool                                           #boolExpression
 | IDENTIFIER                                     #identifierExpression
 | DECIMAL                                        #decimalExpression
 ;

comparator
 : GT | GE | LT | LE | EQ
 ;

binary
 : AND | OR
 ;

bool
 : TRUE | FALSE
 ;

AND        : 'AND' ;
OR         : 'OR' ;
NOT        : 'NOT';
TRUE       : 'TRUE' ;
FALSE      : 'FALSE' ;
GT         : '>' ;
GE         : '>=' ;
LT         : '<' ;
LE         : '<=' ;
EQ         : '=' ;
LPAREN     : '(' ;
RPAREN     : ')' ;
DECIMAL    : '-'? [0-9]+ ( '.' [0-9]+ )? ;
IDENTIFIER : [a-zA-Z_] [a-zA-Z_0-9]* ;
WS         : [ \r\t\u000C\n]+ -> skip;

运行public class Main { public static void main(String[] args) throws Exception { Map<String, Object> variables = new HashMap<String, Object>() {{ put("A", true); put("a", true); put("B", false); put("b", false); put("C", 42.0); put("c", 42.0); put("D", -999.0); put("d", -1999.0); put("E", 42.001); put("e", 142.001); put("F", 42.001); put("f", 42.001); put("G", -1.0); put("g", -1.0); }}; String[] expressions = { "1 > 2", "1 >= 1.0", "TRUE = FALSE", "FALSE = FALSE", "A OR B", "B", "A = B", "c = C", "E > D", "B OR (c = B OR (A = A AND c = C AND E > D))", "(A = a OR B = b OR C = c AND ((D = d AND E = e) OR (F = f AND G = g)))" }; for (String expression : expressions) { SimpleBooleanLexer lexer = new SimpleBooleanLexer(new ANTLRInputStream(expression)); SimpleBooleanParser parser = new SimpleBooleanParser(new CommonTokenStream(lexer)); Object result = new EvalVisitor(variables).visit(parser.parse()); System.out.printf("%-70s -> %s\n", expression, result); } } } class EvalVisitor extends SimpleBooleanBaseVisitor<Object> { private final Map<String, Object> variables; public EvalVisitor(Map<String, Object> variables) { this.variables = variables; } @Override public Object visitParse(SimpleBooleanParser.ParseContext ctx) { return super.visit(ctx.expression()); } @Override public Object visitDecimalExpression(SimpleBooleanParser.DecimalExpressionContext ctx) { return Double.valueOf(ctx.DECIMAL().getText()); } @Override public Object visitIdentifierExpression(SimpleBooleanParser.IdentifierExpressionContext ctx) { return variables.get(ctx.IDENTIFIER().getText()); } @Override public Object visitNotExpression(SimpleBooleanParser.NotExpressionContext ctx) { return !((Boolean)this.visit(ctx.expression())); } @Override public Object visitParenExpression(SimpleBooleanParser.ParenExpressionContext ctx) { return super.visit(ctx.expression()); } @Override public Object visitComparatorExpression(SimpleBooleanParser.ComparatorExpressionContext ctx) { if (ctx.op.EQ() != null) { return this.visit(ctx.left).equals(this.visit(ctx.right)); } else if (ctx.op.LE() != null) { return asDouble(ctx.left) <= asDouble(ctx.right); } else if (ctx.op.GE() != null) { return asDouble(ctx.left) >= asDouble(ctx.right); } else if (ctx.op.LT() != null) { return asDouble(ctx.left) < asDouble(ctx.right); } else if (ctx.op.GT() != null) { return asDouble(ctx.left) > asDouble(ctx.right); } throw new RuntimeException("not implemented: comparator operator " + ctx.op.getText()); } @Override public Object visitBinaryExpression(SimpleBooleanParser.BinaryExpressionContext ctx) { if (ctx.op.AND() != null) { return asBoolean(ctx.left) && asBoolean(ctx.right); } else if (ctx.op.OR() != null) { return asBoolean(ctx.left) || asBoolean(ctx.right); } throw new RuntimeException("not implemented: binary operator " + ctx.op.getText()); } @Override public Object visitBoolExpression(SimpleBooleanParser.BoolExpressionContext ctx) { return Boolean.valueOf(ctx.getText()); } private boolean asBoolean(SimpleBooleanParser.ExpressionContext ctx) { return (boolean)visit(ctx); } private double asDouble(SimpleBooleanParser.ExpressionContext ctx) { return (double)visit(ctx); } } 类将产生以下输出:

Main