2010-01-11 52 views
12

我仍然在my quest for a really simple language,我现在知道没有。所以我正在使用ANTLR3自己编写一个。扩展简单的ANTLR语法来支持输入变量

我发现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语法,我可以计算表达式像

(12+14)/2 

并得到13结果。

现在唯一缺少的用例是一种向此注入简单双变量的方法,以便通过提供{“A”:12.0,“B”:14.0}作为输入来评估以下内容地图:

(A+B)/2 

任何想法?

回答

19

你可以创建你的解析器Map<String, Double> 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<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;} 
    ; 

而且现在世界上没有必要自己实例化语法/词法分析器,你可以简单地做:

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 

祝你好运!

+0

再次感谢!!! – arturh 2010-01-11 14:49:32

+0

没问题,再次! :) – 2010-01-11 14:50:17

8

呸,花时间来实现这个那么不妨将它张贴,即使我打冲:)

在语法下面我已经实现变量的格式分配你正在寻找做。

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*; 
+0

对不起Darien :)。那么,我写的语法arturh张贴在第一位,所以我有一个开始。尽管如此,我还是+1! – 2010-01-11 15:04:18

+0

不用担心,这是造成这种危险的一部分:) – 2010-01-11 15:06:59