ANTLR /语法问题:计算器语言

时间:2011-03-01 12:39:49

标签: java antlr grammar lex antlrworks

我正在尝试为个人项目创建一个布尔表达式语言/语法。用户将能够以类似Java的语法编写字符串,并提供变量,这些变量将在以后初始化变量时进行评估。 雨 例如,用户可能会输入字符串

@FOO+7 > 4*(5+@BAR);

稍后,当变量FOO初始化并且等于6,并且BAR等于1时,表达式的计算结果为13> 24,因此返回false。

我正在使用ANTLRworks生成语法,虽然看起来不错,但它并没有正确解释负面符号。 ANTLRworks中的输入(由于某种原因)改变了:“(8-3)> 6”被读作“(8> 6”(由于缺少结束括号而无法运行)。我还没有实现了变量查找,但这里只是整数的语法:

grammar BooleanCalculator;

@header {
package test;
}

prog    : rule+
;

rule    : boolean_expr ';' NEWLINE {System.out.println($boolean_expr.b);}
| NEWLINE
;

boolean_expr returns [boolean b]
: v1=num_statement 
('<'  v2=num_statement {$b = $v1.d <  $v2.d;}
|'<=' v2=num_statement {$b = $v1.d <= $v2.d;}
|'='  v2=num_statement {$b = $v1.d == $v2.d;}
|'!=' v2=num_statement {$b = !($v1.d == $v2.d);}
|'>=' v2=num_statement {$b = $v1.d >= $v2.d;}
|'>'  v2=num_statement {$b = $v1.d >  $v2.d;})
;

num_statement returns [double d]
: v1=mult_statement {$d = $v1.d;}
('+' v2=mult_statement {$d += $v2.d;}
|'-' v2=mult_statement {$d -= $v2.d;})* //HERE IS THE OFFENDING LINE
;

mult_statement returns [double d]
: v1=var {$d = $v1.d;}
('*' v2=var {$d *= $v2.d;}
|'/' v2=var {$d /= $v2.d;}
|'%' v2=var {$d = $d/100*$v2.d;})*
;

var returns [double d]
: NUMBER {$d = Double.parseDouble($NUMBER.text);}
| '(' v1=num_statement ')' {$d = $v1.d;}
;

NUMBER  : '0'..'9'+
;

除了“ - ”符号外,它正常工作。有谁知道解决这个问题的方法?

另外(我对ANTLR很新):我正在进行正确的评估吗?或者我应该让语法定义结构并使用另一种方法来确定语句是否为true / false?

1 个答案:

答案 0 :(得分:3)

你的语法:

grammar BooleanCalculator;

prog    
  :  rule+
  ;

rule
  :  boolean_expr {System.out.println($boolean_expr.b);}
  ;

boolean_expr returns [boolean b]
  : v1=num_statement ( '<'  v2=num_statement {$b = $v1.d < $v2.d;}
                     | '<=' v2=num_statement {$b = $v1.d <= $v2.d;}
                     | '='  v2=num_statement {$b = $v1.d == $v2.d;}
                     | '!=' v2=num_statement {$b = !($v1.d == $v2.d);}
                     | '>=' v2=num_statement {$b = $v1.d >= $v2.d;}
                     | '>'  v2=num_statement {$b = $v1.d > $v2.d;}  {System.out.println("v1=" + $v1.d + ", v2=" + $v2.d);}
                     )
  ;

num_statement returns [double d]
  :  v1=mult_statement {$d = $v1.d;} ( '+' v2=mult_statement {$d += $v2.d;}
                                     | '-' v2=mult_statement {$d -= $v2.d;}
                                     )* 
  ;

mult_statement returns [double d]
: v1=var {$d = $v1.d;} ( '*' v2=var {$d *= $v2.d;}
                       | '/' v2=var {$d /= $v2.d;}
                       | '%' v2=var {$d = $d/100*$v2.d;}
                       )*
;

var returns [double d]
  : NUMBER {$d = Double.parseDouble($NUMBER.text);}
  | '(' v1=num_statement ')' {$d = $v1.d;}
  ;

NUMBER  
  :  '0'..'9'+
  ;

(请注意,我做了更改除了重新格式化之外的任何内容,并为调试添加了额外的println!)

产生了以下输出:

$ java -cp antlr-3.2.jar org.antlr.Tool BooleanCalculator.g 
$ javac -cp antlr-3.2.jar *.java
$ java -cp .:antlr-3.2.jar Main

v1=5.0, v2=6.0
false

使用测试类:

import org.antlr.runtime.*;

public class Main {
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream("(8-3)>6");
        BooleanCalculatorLexer lexer = new BooleanCalculatorLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        BooleanCalculatorParser parser = new BooleanCalculatorParser(tokens);
        parser.prog();
    }
}

所以,一切似乎都没问题。

几句话:

  • 您正在使用double==!=进行比较。请注意:舍入错误将导致意外行为(从用户的角度来看......);
  • 在语法操作中使用modulo运算符可以通过使用反斜杠转义它来完成:\%
相关问题