ANTLR / Грамматический выпуск: язык калькулятора - PullRequest
1 голос
/ 01 марта 2011

Я пытаюсь создать язык / грамматику булевых выражений для личного проекта.Пользователь сможет написать строку в 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): правильно ли я выполняю оценку? Или я должен просто позволить грамматике определить структуру и использовать другой метод, чтобы определить, является ли утверждение истинным / ложным?

1 Ответ

3 голосов
/ 01 марта 2011

Ваша грамматика:

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 в ваших действиях по грамматике может быть выполнено путем экранирования с обратной косой чертой: \%.
...