我试图扩展以下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
我知道语法有错误但是无法弄明白。
答案 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