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

标签 java antlr antlr3

我还在 my quest for a really simple language我现在知道没有了。所以我正在用 ANTLR3 自己写一个。

我在 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。

现在我的用例唯一缺少的是一种向其中注入(inject)简单双变量的方法,这样我就可以通过提供 {"A": 12.0, "B":14.0} 作为输入映射来评估以下内容:

(A+B)/2

有什么想法吗?

最佳答案

您可以创建一个 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

祝你好运!

关于java - 扩展简单的 ANTLR 语法以支持输入变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2042353/

相关文章:

java - 从 Python 程序访问 Java RMI API

java - 创建对象并调用方法时出错,: cannot find symbol错误

ANTLRv3 不读取选项

java - 即使输入有额外的标记,ANTLR 3.5.2 也会匹配规则

netbeans - ANTLR netbeans 配置找不到或加载主类 org.antlr.Tool

ANTLR3语法引用?

java - Android Socket 未被实例化

java - 使用 spring 3.1 不返回 json 响应

algorithm - LL(*) 解析器如何工作?

java - 是否可以将 ANTLR 语法配置为使用具有相同结构的两个标记?