扩展简单的 ANTLR 语法以支持输入变量 [英] Extending simple ANTLR grammar to support input variables
问题描述
我还在 我对一种非常简单的语言的追求,现在我知道没有.所以我正在使用 ANTLR3 自己写一个.
I'm still on my quest for a really simple language and I know now that there are none. So I'm writing one myself using ANTLR3.
我在这个答案中找到了一个非常好的例子:
I found a really great example in this answer:
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<String, Double> input) throws RecognitionException {
ANTLRStringStream in = new ANTLRStringStream(string);
ExpLexer lexer = new ExpLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
return new ExpParser(tokens).eval();
}
使用这个 ANTLR 语法我可以评估表达式
Using this ANTLR grammer I can evaluate expressions like
(12+14)/2
结果是 13.
现在我的用例唯一缺少的是一种向其中注入简单双变量的方法,以便我可以通过提供 {"A": 12.0, "B":14.0} 作为输入映射来评估以下内容:
Now the only thing missing for my use-case is a way to inject simple double variables into this, so that I can evaluate the following by supplying {"A": 12.0, "B":14.0} as the input map:
(A+B)/2
有什么想法吗?
推荐答案
您可以创建一个 Map
并在语法中引入 Identifier
:
You could create a Map<String, Double> memory
in your parser and introduce a Identifier
in your grammar:
Identifier
: ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*
;
那么您的 atomExp
解析器规则将如下所示:
Then your atomExp
parser rule would look like this:
atomExp returns [double value]
: n=Number {$value = Double.parseDouble($n.text);}
| i=Identifier {$value = memory.get($i.text);} // <- added!
| '(' exp=additionExp ')' {$value = $exp.value;}
;
这是一个小的(完整的)演示:
Here's a small (complete) demo:
grammar Exp;
@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;}
;
Identifier
: ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*
;
Number
: ('0'..'9')+ ('.' ('0'..'9')+)?
;
WS
: (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;}
;
现在不需要自己实例化解析器/词法分析器,你可以简单地做:
And now theres no need to instantiate the parser/lexer yourself, you can simply do:
import org.antlr.runtime.*;
import java.util.*;
public class ANTLRDemo {
public static void main(String[] args) throws Exception {
Map<String, Double> vars = new HashMap<String, Double>();
vars.put("two", 2.0);
vars.put("pi", Math.PI);
System.out.println(ExpParser.eval("two * pi", vars));
}
}
将产生:
6.283185307179586
祝你好运!
这篇关于扩展简单的 ANTLR 语法以支持输入变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!