2011-03-01 61 views
1

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

@FOO+7 > 4*([email protected]); 

以后,当变量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非常陌生):我是否正确地进行评估?或者我应该让语法定义结构并使用另一种方法来确定该语句是否为真/假?

回答

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小号
  • 。小心:舍入错误会导致意外的行为(从用户的角度来看......);
  • 在语法操作中使用模运算符可以通过使用反斜杠进行转义来完成:\%
+0

嗯。这将教会我相信自动化测试工具。不知道发生了什么,但它在Java中工作,但不在ANTLRworks中。 – Trasvi 2011-03-01 15:09:37

+0

@Trasvi,ANTLRWorks是一个很好的工具,可以将您的语法形象化并对其进行编辑,但这是我唯一曾经使用过的语言:从不用于测试目的(不幸的是,太麻烦了,不支持谓词)。 – 2011-03-01 15:15:47