【问题标题】:ANTLR/Grammar issue: calculator languageANTLR/语法问题:计算器语言
【发布时间】:2011-03-01 12:39:48
【问题描述】:

我正在尝试为个人项目创建布尔表达式语言/语法。用户将能够以类似 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 很陌生):我的评估是否正确?或者我应该让语法定义结构并使用另一种方法来确定语句是真还是假?

【问题讨论】:

    标签: java antlr grammar lex antlrworks


    【解决方案1】:

    你的语法:

    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();
        }
    }
    

    所以,一切似乎都很好。

    几点说明:

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

    【讨论】:

    • 嗯。这将教会我信任自动化测试工具。不知道发生了什么,但它在 Java 中有效,但在 ANTLRworks 中无效。
    • @Trasvi,ANTLRWorks 是一个很棒的工具,可以可视化和编辑你的语法,但这是我唯一使用它的目的:从不用于测试目的(不幸的是,问题太多,不支持谓词) .
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多