使用Java Math

时间:2017-11-05 02:59:52

标签: java antlr

我试图扩展以下link

中给出的语法

我想评估像Height* @cos(x+y)这样的表达式 这里@cos是我的项目功能。我想添加许多其他系统功能

在我的语法中添加了

CosExp return [double value]
: exp=additionExp {$value = Math.cos($exp.value);}
;

完整语法(编辑工作语法)如下:

grammar Exp;
@header {
    package antlr.output;
    import java.util.HashMap;
}
@parser::members {

  private java.util.HashMap<String, Double> memory = new java.util.HashMap<String, Double>();

  public static Double eval(String expression) throws Exception {
    return eval(expression, new java.util.HashMap<String, Double>()); 
  }

  public static Double eval(String expression, java.util.Map<String, Double> vars) throws Exception {
    ANTLRStringStream in = new ANTLRStringStream(expression);
    ExpLexer lexer = new ExpLexer(in);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    ExpParser parser = new ExpParser(tokens);
    parser.memory.putAll(vars);
    return parser.parse(); 
  }
}

parse returns [double value]
    :    exp=additionExp {$value = $exp.value;}
    ;

additionExp returns [double value]
    :    m1=multiplyExp      {$value =  $m1.value;} 
        ( '+' m2=multiplyExp {$value += $m2.value;} 
        | '-' m2=multiplyExp {$value -= $m2.value;}
        )*  
    ;

multiplyExp returns [double value]
    :   a1=atomExp       {$value =  $a1.value;}
        ( '*' a2=atomExp {$value *= $a2.value;} 
        | '/' a2=atomExp {$value /= $a2.value;}
        )*  
    ;

atomExp returns [double value]
    :    n=Number                {$value = Double.parseDouble($n.text);}
    |    i=Identifier            {$value = memory.get($i.text);}
    |    '(' exp=additionExp ')' {$value = $exp.value;}
    ;

CosExp return [double value]  // I have added these lines
: exp=additionExp {$value = Math.cos($exp.value);} // I have added these lines
;
Identifier
    :    ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*
    ;

Number
    :    ('0'..'9')+ ('.' ('0'..'9')+)?
    ;

WS  
    :   (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;}
    ;

在我的Java代码中

Map<String, Double> vars = new HashMap<String, Double>();
vars.put("Height", 12.0);
vars.put("x", 2.0);
vars.put("y", 2.0);
System.out.println(ExpParser.eval("Height* @cos(x+y)", vars));

当我运行代码时我得到java.lang.NullPointerException我知道语法有错误但是无法弄明白。

1 个答案:

答案 0 :(得分:0)

您的语法无法解析字符串@cos中的"Height* @cos(x+y)"。很可能你有一个令牌识别错误,cos变成Identifier,它不在内存Map中,因此声明memory.get中的NullPointerException。

$ java test_exp
Found ID=<Height>
Found Height=12.0
line 1:9 token recognition error at: '@'
Found ID=<cos>
Exception in thread "main" java.lang.NullPointerException
    at ExpParser.atomExp(ExpParser.java:391)
    at ExpParser.multiplyExp(ExpParser.java:312)
    at ExpParser.additionExp(ExpParser.java:216)
    at ExpParser.expression(ExpParser.java:170)
    at ExpParser.parse(ExpParser.java:130)
    at ExpParser.eval(ExpParser.java:97)
    at test_exp.main(test_exp.java:9)

以下语法适用于v4.6。

档案Exp.g4

grammar Exp;

@header {
//    package antlr.output;
  import java.util.HashMap;
}

@parser::members {

  private HashMap<String, Double> memory = new java.util.HashMap<String, Double>();

  public static Double eval(String expression) throws Exception {
    return eval(expression, new java.util.HashMap<String, Double>()); 
  }

  public static Double eval(String expression, java.util.Map<String, Double> vars) throws Exception {
    ANTLRInputStream in = new ANTLRInputStream(expression);
    ExpLexer lexer = new ExpLexer(in);
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    ExpParser parser = new ExpParser(tokens);
    parser.memory.putAll(vars);
    ParseContext ctx = parser.parse();
    return ctx.expression().value;
  }
}

parse
@init {System.out.println("Exp last update 1843");}
    :   expression
        {System.out.println("Expression " + $expression.text + "=" + $expression.value);}
    ;

expression returns [double value]
    :   e1=expression            {$value =  $e1.value;}
        (   op='*' e2=expression {$value *= $e2.value;} 
          | op='/' e2=expression {$value /= $e2.value;}
        )
        {System.out.println("Mult " + $e1.text + ($op.text != null ? $op.text + $e2.text + "=" + $value : ""));}
    |   e1=expression            {$value =  $e1.value;} 
        (   op='+' e2=expression {$value += $e2.value;} 
          | op='-' e2=expression {$value -= $e2.value;}
        )
        {System.out.println("Add " + $e1.text + ($op.text != null ? $op.text + $e2.text + "=" + $value : ""));}
    |   '(' expression ')'       {$value = $expression.value;}
    |   function                 {$value = $function.value;
                                  System.out.println("Function " + $function.text + "=" + $value);
                                 }
    |   atom                     {$value = $atom.value;}
    ;

function returns [double value]
    :   '@' 'cos' expression {$value = Math.cos($expression.value);}
    |   '@' 'sin' expression {$value = Math.sin($expression.value);}
    ;

atom returns [double value]
    :   NUMBER                {$value = Double.parseDouble($NUMBER.text);}
    |   IDENTIFIER            {System.out.println("Found ID=<" + $IDENTIFIER.text + ">");
                               $value = memory.get($IDENTIFIER.text);
                               System.out.println("Found " + $IDENTIFIER.text + "=" + $value);
                              }
    ;

IDENTIFIER
    :    ( LETTER | '_' ) ( LETTER | '_' | DIGIT )*
    ;

NUMBER
    :    DIGIT+ ( '.' DIGIT+ )?
    ;


WS      : [ \t\r\n] -> channel(HIDDEN) ;

fragment LETTER : [a-zA-Z] ;
fragment DIGIT  : [0-9] ;

请注意,我仅为跟踪输出引入了op=。 另请注意,加法和乘法不能为*,如

:    m1=multiplyExp      {$value =  $m1.value;} 
    (   op='+' m2=multiplyExp {$value += $m2.value;} 
      | op='-' m2=multiplyExp {$value -= $m2.value;}
    )* 

它会产生错误:

error(148): Exp.g4:32:0: left recursive rule expression contains a left recursive
alternative which can be followed by the empty string

档案test_exp.java

import java.util.*;

public class test_exp {
    public static void main(String[] args) throws Exception {
        Map<String, Double> vars = new HashMap<String, Double>();
        vars.put("Height", 12.0);
        vars.put("x", 2.0);
        vars.put("y", 2.0);
        System.out.println("Result=" + ExpParser.eval("Height * @cos(x + y)", vars));
    }
}

执行:

$ export CLASSPATH=".:/usr/local/lib/antlr-4.6-complete.jar"
$ alias
alias a4='java -jar /usr/local/lib/antlr-4.6-complete.jar'
$ a4 Exp.g4 
$ javac E*.java
$ javac test_exp.java 
$ java test_exp
Exp last update 1843
Found ID=<Height>
Found Height=12.0
Found ID=<x>
Found x=2.0
Found ID=<y>
Found y=2.0
Add x+y=4.0
Function @cos(x + y)=-0.6536436208636119
Mult Height*@cos(x + y)=-7.843723450363344
Expression Height * @cos(x + y)=-7.843723450363344
Result=-7.843723450363344