ANTLR:有一个简单的例子吗?

2023-12-25

我想开始使用 ANTLR,但是在花了几个小时查看了示例之后antlr.org http://www.antlr.org/网站上,我仍然无法清楚地了解Java的语法过程。

有没有一些简单的例子,比如用 ANTLR 实现的四操作计算器,遍历解析器定义并一直到 Java 源代码?


Note: 这个答案是为了ANTLR3!如果您正在寻找ANTLR4例如,那么这个演示如何创建一个简单的表达式解析器和评估器ANTLR4.


您首先创建一个语法。下面是一个小语法,您可以使用它来计算使用 4 个基本数学运算符构建的表达式:+、-、* 和 /。您还可以使用括号对表达式进行分组。

请注意,此语法只是一个非常基本的语法:它不处理一元运算符(-1+9 中的减号)或像 0.99 这样的小数(没有前导数字),仅举两个缺点。这只是一个示例,您可以自己操作。

这是语法文件的内容Exp.g:

grammar Exp;

/* This will be the entry point of our parser. */
eval
    :    additionExp
    ;

/* Addition and subtraction have the lowest precedence. */
additionExp
    :    multiplyExp 
         ( '+' multiplyExp 
         | '-' multiplyExp
         )* 
    ;

/* Multiplication and division have a higher precedence. */
multiplyExp
    :    atomExp
         ( '*' atomExp 
         | '/' atomExp
         )* 
    ;

/* An expression atom is the smallest part of an expression: a number. Or 
   when we encounter parenthesis, we're making a recursive call back to the
   rule 'additionExp'. As you can see, an 'atomExp' has the highest precedence. */
atomExp
    :    Number
    |    '(' additionExp ')'
    ;

/* A number: can be an integer value, or a decimal value */
Number
    :    ('0'..'9')+ ('.' ('0'..'9')+)?
    ;

/* We're going to ignore all white space characters */
WS  
    :   (' ' | '\t' | '\r'| '\n') {$channel=HIDDEN;}
    ;

(解析器规则以小写字母开头,词法分析器规则以大写字母开头)

创建语法后,您需要从中生成解析器和词法分析器。下载ANTLR罐子 http://www.antlr.org/download/antlr-3.2.jar并将其存储在与语法文件相同的目录中。

在 shell/命令提示符下执行以下命令:

java -cp antlr-3.2.jar org.antlr.Tool Exp.g

它不应该产生任何错误消息,并且文件ExpLexer.java, ExpParser.java and 经验代币现在应该已生成。

要查看是否一切正常,请创建此测试类:

import org.antlr.runtime.*;

public class ANTLRDemo {
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream("12*(5-6)");
        ExpLexer lexer = new ExpLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        ExpParser parser = new ExpParser(tokens);
        parser.eval();
    }
}

并编译它:

// *nix/MacOS
javac -cp .:antlr-3.2.jar ANTLRDemo.java

// Windows
javac -cp .;antlr-3.2.jar ANTLRDemo.java

然后运行它:

// *nix/MacOS
java -cp .:antlr-3.2.jar ANTLRDemo

// Windows
java -cp .;antlr-3.2.jar ANTLRDemo

如果一切顺利,控制台上不会打印任何内容。这意味着解析器没有发现任何错误。当你改变时"12*(5-6)" into "12*(5-6"然后重新编译并运行它,应该打印以下内容:

line 0:-1 mismatched input '<EOF>' expecting ')'

好的,现在我们想在语法中添加一些 Java 代码,以便解析器真正执行一些有用的操作。添加代码可以通过放置来完成{ and }在你的语法里面有一些简单的Java代码。

但首先:语法文件中的所有解析器规则都应返回原始双精度值。您可以通过添加来做到这一点returns [double value]每条规则之后:

grammar Exp;

eval returns [double value]
    :    additionExp
    ;

additionExp returns [double value]
    :    multiplyExp 
         ( '+' multiplyExp 
         | '-' multiplyExp
         )* 
    ;

// ...

这几乎不需要解释:每个规则都应该返回一个双精度值。现在与返回值“交互”double value(它不在纯 Java 代码块内{...})从代码块内部,您需要在前面添加一个美元符号value:

grammar Exp;

/* This will be the entry point of our parser. */
eval returns [double value]                                                  
    :    additionExp { /* plain code block! */ System.out.println("value equals: "+$value); }
    ;

// ...

这是语法,但现在添加了 Java 代码:

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;}
    ;

自从我们的eval规则现在返回一个双精度值,将 ANTLRDemo.java 更改为:

import org.antlr.runtime.*;

public class ANTLRDemo {
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream("12*(5-6)");
        ExpLexer lexer = new ExpLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        ExpParser parser = new ExpParser(tokens);
        System.out.println(parser.eval()); // print the value
    }
}

再次(重新)从语法生成新的词法分析器和解析器 (1),编译所有类 (2) 并运行 ANTLRDemo (3):

// *nix/MacOS
java -cp antlr-3.2.jar org.antlr.Tool Exp.g   // 1
javac -cp .:antlr-3.2.jar ANTLRDemo.java      // 2
java -cp .:antlr-3.2.jar ANTLRDemo            // 3

// Windows
java -cp antlr-3.2.jar org.antlr.Tool Exp.g   // 1
javac -cp .;antlr-3.2.jar ANTLRDemo.java      // 2
java -cp .;antlr-3.2.jar ANTLRDemo            // 3

现在您将看到表达式的结果12*(5-6)打印到你的控制台!

再次强调:这是一个非常简短的解释。我鼓励您浏览ANTLR 维基 http://www.antlr.org/wiki/display/ANTLR3/ANTLR+3+Wiki+Home并阅读一些教程和/或玩一下我刚刚发布的内容。

祝你好运!

EDIT:

这个帖子 https://stackoverflow.com/questions/2042353/extending-simple-antlr-grammer-to-support-input-variables展示了如何扩展上面的示例,以便Map<String, Double>可以提供在所提供的表达式中保存变量。

为了让此代码与当前版本的 Antlr(2014 年 6 月)一起使用,我需要进行一些更改。ANTLRStringStream需要成为ANTLRInputStream,返回值需要更改为parser.eval() to parser.eval().value,我需要删除WS子句放在最后,因为属性值如$channel不再允许出现在词法分析器操作中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ANTLR:有一个简单的例子吗? 的相关文章

随机推荐

  • 合并两个数组而不使用额外空间

    我有 2 个已排序的数组 a1 and a2 长度l1 and l2 分别 数组a2长度末尾有空格l1 所以它可以容纳所有元素a1除了它本身的元素之外 现在我想合并a1 into a2以便a2将包含以下所有元素a1 and a2按排序顺序
  • 命令行 Jasypt 客户端加密“无法操作”

    我正在使用 Jasypt 以非明文格式将数据库密码存储在休眠配置文件中 例如代替
  • C++ 模板和 ODR 规则

    为什么以下工作在C 我想ODR规则将出现在以下代码中 typedef char int8 class Sample public template
  • 当用户创建挂载点时如何收到通知?

    首先 这是限制 必须在XP上运行 必须通知驱动器盘符分配以及将卷安装到文件夹 如果驱动器正在睡眠 则不得 唤醒 该驱动器 我真的不想轮询驱动器 我尝试过的 Google 我查看了 WMI 和 Win32 LogicalDisk 类 我可以确
  • Linux 上的 Docker - 清空已安装的卷

    我正在尝试让我的 docker 设置在我的 Linux 机器上运行 它在 OSX 上运行良好 我一生都无法将卷正确安装到 Linux 机器上 我使用的是 Elementary OS 0 4 Loki 64 位 码头工人版本 Client V
  • 如何在 OpenCV 中校正裁剪后的立体图像?

    我有一对水平对齐的立体相机 它们是使用图像的全尺寸进行校准的 我通过调用 cv2 initUn DistorifyMap 来获取每个摄像机的地图进行纠正 然后调用 cv2 remap 使用全尺寸图像时 如下所示 map1 map2 cv2
  • 如何在select2框架中使用占位符作为默认值

    获得a的选定值select2我在用着 var x select select2 data var select choice x text 问题是 如果未选择值 则会引发错误 我想知道如果未选择任何选项 是否有任何方法使其返回占位符 您必须
  • 使用 Mathnet 数字库进行 Svd 重组似乎是错误的

    我正在寻找 Mathnet Iridium 和 Mathnet Numerics 之间的非回归 这是我的代码 使用 Mathnet Numerics double symJaggedArray new double 5 symJaggedA
  • Java方法性能中使用final关键字? [复制]

    这个问题在这里已经有答案了 是否使用final在方法参数中允许编译器或运行时环境更快地工作 例如 如果您有一个变量要传递给一个您知道不会被修改并按原样使用的方法 那么声明它是否更有效final 例子 第一种方法应该比第二种方法更快 publ
  • javascript 函数返回不起作用

    我在函数中返回变量时遇到问题 以下脚本工作正常 function sessionStatus document ready function getJSON scriptRoot sessionStatus php function sta
  • k8s - livenessProbe 与 readinessProbe

    考虑一个通过 http 端点进行健康检查设置的 pod health在端口 80 上 需要近 60 秒才能真正准备好并为流量提供服务 readinessProbe httpGet path health port 80 initialDel
  • Excel VBA - 日期格式自动更改

    我试图通过在 Sheets Sheet1 Cells 17 3 Value 中的日期添加一个月来输入日期值 该值是 01 10 2011 但格式为 Oct 11 然后返回 Sheets Sheet1 Cells 17 4 Value LDa
  • 如何根据分辨率调整控件大小?

    在 WinForms 应用程序中 处理调整控件大小以匹配基于屏幕分辨率以及最大化和调整窗口大小的最佳方法是什么 我有 3 列是这样设置的 每列中的标签文本框 您可以将其算作 6 列 我尝试过锚定到右侧 但问题是第 1 列中的文本框将与接下来
  • 带参数的本地化字符串在参数周围添加换行符和括号

    我正在尝试显示包含参数的本地化字符串 结果不是将嵌入参数的字符串显示在一行中 而是显示一个损坏的 3 行字符串 预期结果 The price is 9 99 year Result The price is 9 99 year 可本地化的字
  • boost::与 boost::asio 结合在一起。 boost::bind 不起作用,从示例复制

    有人能告诉我为什么这不能编译吗 我基本上是从 Kholkoff 的一个例子中复制过来的 http lists boost org Archives boost 2007 04 120339 php http lists boost org
  • 使用matlab求级数求和

    当我在 matlab 中写这个时 syms x f x 3 cos x g diff f 它给出的输出为 g 3 x 2 正弦 x Now I want to generate summation series as 我搜索并找到 syms
  • 如何解码编码字字符串?

    请注意 这个问题与this https stackoverflow com questions 15098452 how can i decode a quotedprintable encoded string以前未回答的问题 它也同样是
  • pyplot:更改图例中的 ncol

    我正在 pyplot 中绘制一个大数据集和一些回归 数据根据附加值着色 我决定将图例中的列数设置为 2 数据点看起来不错 但对于回归 我想回到 ncols 1 有可能在一个图例中做到这一点吗 我知道 我可以宣布两个传奇 但我想避免这种情况
  • 如何安装JDBC以及如何使用它连接mysql?

    我正在尝试安装 JDBC 但我不知道如何 当你只有 jar 文件时 我将其复制到我的 java ext 文件夹 但它一直给我一个错误 任何人都可以告诉我如何完成驱动程序的安装并使用它吗 下面是我使用的代码 import java sql p
  • ANTLR:有一个简单的例子吗?

    我想开始使用 ANTLR 但是在花了几个小时查看了示例之后antlr org http www antlr org 网站上 我仍然无法清楚地了解Java的语法过程 有没有一些简单的例子 比如用 ANTLR 实现的四操作计算器 遍历解析器定义