当前位置: 首页 > 面试题库 >

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

羊舌墨一
2023-03-14
问题内容

我仍在寻求一种非常简单的语言,现在我知道没有任何语言。所以我是用ANTLR3自己写的。

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

克:

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

现在,我的用例唯一缺少的是一种向其中注入简单的double变量的方法,因此我可以通过提供{“ 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

祝好运!



 类似资料:
  • 本文向大家介绍ANTLR语言支持,包括了ANTLR语言支持的使用技巧和注意事项,需要的朋友参考一下 示例 ANTLR能够为多种编程语言生成解析器: C#目标 Python目标 JavaScript目标 Java目标 默认情况下,ANTLR将使用Java编程语言从命令行生成解析器: 要更改目标语言,可以从OS终端/命令行运行以下命令: 不必每次都在命令行/终端上使用“ -Dlanguage”参数来为

  • Electron 支持 Chrome 扩展API的子集, 主要是支持 DevTools 扩展和 Chromium-internal 扩展,但它同时也支持一些其他扩展能。 注意:Electron 不支持商店中的任意 Chrome 扩展,Electron 项目的目标不是与 Chrome 的扩展实现完全兼容。 加载扩展 Electron 只支持加载未打包的扩展 (即不能使用 .crx 文件)。 插件会被

  • 问题内容: 问题的答案 是否可以在JavaScript中创建自定义运算符? 是 没有的,但@Benjamin建议,这将有可能使用添加一个新的运营商 的第三方工具 : 可以使用sweet.js之类的第三方工具来添加自定义运算符,尽管这需要额外的编译步骤。 我将采用相同的示例,就像上一个问题一样: (ℝ,∘),x y = x + 2y 对于任何两个实数 x 和 y : x y 是 x + 2y ,这也

  • 我尝试扩展ISOSTS XSD方案以支持SVG图像标记。我找到了用于SVG的XSD方案,并将其放在附近。现在我尝试扩展: 但是我在尝试加载方案时出错: 怎么啦?

  • 在过去的几周里,我一直在编写一些浏览器扩展,直到今天,我认为Firefox的WebExtension应该在Chrome中自动运行。所以我试着根据Mozilla的示例编写代码。 但是今天我意识到在Chrome扩展的API文档中没有提到承诺。 我在所有扩展的代码中都严格地使用了承诺。 所以现在我的问题是,我的代码能在Chrome中工作吗?或者,如果我在顶部添加一个声明,它会起作用吗? 或者,Chrom

  • 包含 RTL 文件 如需启用 RTL 功能,则要包含 'easyui-rtl.css' 和 'easyui-rtl.js' 文件。 <link rel="stylesheet" type="text/css" href="themes/default/easyui.css"> <link rel="stylesheet" type="text/css" href="easyui-rtl.cs