ANTLR/Grammar issue: calculator language

旧街凉风 提交于 2019-12-11 05:07:46

问题


I'm attempting to create a boolean expression language/grammar for a personal project. The user will be able to write a string in a Java-like syntax, with provision for variables, which will be evaluated at a later time when the variables have been initialised. Rain For example, a user might enter the string

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

Later, when the variable FOO is initialised and equal to 6, and BAR is equal to 1, the expression evaluates to 13>24 and thus returns false.

I'm using ANTLRworks to generate the grammar and whilst it LOOKS fine, it doesn't correctly interpret negative signs. The input in the ANTLRworks is (for some reason) changed: "(8-3)>6" is read as "(8>6" (which fails to run as it is missing the closing bracket). I haven't implemented the variable lookups yet, but here is the grammar so far for just integers:

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'+
;

It is working correctly for everything except the '-' sign. Does anyone know a way to fix this?

Also (I'm very new to ANTLR): am I doing the evaluation correctly? Or should I just let the grammar define the structure and use another method to determine if the statement is true/false?


回答1:


Your grammar:

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'+
  ;

(note that I did not change anything else than reformat it a bit, and added an extra println for debugging!)

produced the following output:

$ 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

using the test class:

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

So, all seems to go fine.

A couple of remarks:

  • you're comparing doubles using == and !=. Be careful with that: rounding errors will result in unexpected behavior (from a user's perspective...);
  • using the modulo operator in your grammar actions can be done by escaping it with a backslash: \%.


来源:https://stackoverflow.com/questions/5154628/antlr-grammar-issue-calculator-language

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!