扩展简单的ANTLR语法以支持输入变量

我仍然在寻找一种非常简单的语言 ,现在我知道没有。 所以我自己用ANTLR3写一个。

我在这个答案中找到了一个很好的例子:

Exp.g:

grammar Exp; eval 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);} | '(' exp=additionExp ')' {$value = $exp.value;} ; Number : ('0'..'9')+ ('.' ('0'..'9')+)? ; WS : (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;} ; 

Java代码:

 public Double evaluate(String string, Map input) throws RecognitionException { ANTLRStringStream in = new ANTLRStringStream(string); ExpLexer lexer = new ExpLexer(in); CommonTokenStream tokens = new CommonTokenStream(lexer); return new ExpParser(tokens).eval(); } 

使用这个ANTLR语法我可以评估表达式

 (12+14)/2 

并得到13作为结果。

现在我的用例中唯一缺少的是将简单的双变量注入其中的方法,以便我可以通过提供{“A”:12.0,“B”:14.0}作为输入映射来评估以下内容:

 (A+B)/2 

有任何想法吗?

您可以在解析器中创建Map memory ,并在语法中引入Identifier

 Identifier : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')* ; 

然后你的atomExp解析器规则如下所示:

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

这是一个小型(完整)演示:

 grammar Exp; @parser::members { private java.util.HashMap memory = new java.util.HashMap(); public static Double eval(String expression) throws Exception { return eval(expression, new java.util.HashMap()); } public static Double eval(String expression, java.util.Map 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;} ; Identifier : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')* ; Number : ('0'..'9')+ ('.' ('0'..'9')+)? ; WS : (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;} ; 

现在不需要自己实例化解析器/词法分析器,你可以简单地做:

 import org.antlr.runtime.*; import java.util.*; public class ANTLRDemo { public static void main(String[] args) throws Exception { Map vars = new HashMap(); vars.put("two", 2.0); vars.put("pi", Math.PI); System.out.println(ExpParser.eval("two * pi", vars)); } } 

这将产生:

 6.283185307179586 

祝你好运!

Bah,花时间实现这个,所以不妨发布它,即使我被打败了:)

在下面的语法中,我已经实现了你想要做的变量赋值的格式。

 grammar Exp; eval returns [double value] scope { java.util.Hashtable varMap; } @init { $eval::varMap = new java.util.Hashtable(); } : exp=additionExp {$value = $exp.value;} | varList ; 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);} | v=ID {$value = $eval::varMap.get($v);} | '(' exp=additionExp ')' {$value = $exp.value;} ; varList : OPEN_BRACE assignVar (COMMA assignVar)+ CLOSE_BRACE ; assignVar :QUOTE var=ID n=Number QUOTE COLON { $eval::varMap.put($var, $n); } ; Number : ('0'..'9')+ ('.' ('0'..'9')+)? ; WS : (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;} ; fragment LETTER: LOWER | UPPER; fragment LOWER: 'a'..'z'; fragment UPPER: 'A'..'Z'; OPEN_BRACE : '{' ; CLOSE_BRACE : '}' ; COLON : ';'; COMMA : ','; QUOTE : '"'; ID : LETTER*;