修改表达式,由 Antlr 生成?

2024-01-01

我想用 Antlr4 读取表达式并对它们执行一些修改。

例如,如果语法是算术,我会修改表达式,表示

2 * (3 + 1)

with

2 * 4

然后与

8

这就是“计算”或“简化”。为了执行此操作,我将创建一些树结构,第一个想法是使用由 Antlr 创建的完全相同的树。

不幸的是,我没有看到任何儿童设置器。

如何实现?我真的应该用我自己的树复制 Antlr 树来表达表达式的逻辑吗?


Solution

您不应复制或修改 ANTRL 树。你应该USE通过利用树访问者和侦听器模式来实现它们。

语法

首先,我们将为算术表达式准备简单的语法。

grammar expr;

WS : [ \t\r\n] -> skip;
INT : [0-9]+;

program
    : expr # baseExpr
    ;

expr
    : '(' expr ')'              # exprParentheses
    | left=expr '*' right=expr  # exprMul
    | left=expr '+' right=expr  # exprAdd
    | INT                       # exprINT
    ;

评估表达

为了计算表达式,我们将遍历解析树来执行计算或收集结果。

public class EvaluateExpr extends exprBaseVisitor<Integer> {
    @Override
    public Integer visitExprINT(exprParser.ExprINTContext ctx) {
        return Integer.valueOf(ctx.INT().getText());
    }

    @Override
    public Integer visitExprMul(exprParser.ExprMulContext ctx) {
        Integer left = visit(ctx.left);
        Integer right = visit(ctx.right);
        return left * right;
    }

    @Override
    public Integer visitExprAdd(exprParser.ExprAddContext ctx) {
        Integer left = visit(ctx.left);
        Integer right = visit(ctx.right);
        return left + right;
    }

    @Override
    public Integer visitExprParentheses(exprParser.ExprParenthesesContext ctx) {
        return visit(ctx.expr());
    }
}

替换表达式

为了用其计算形式替换表达式,我们将使用TokenStreamRewriter班级。该工具可以轻松替换代币。

public class ReplaceExpr extends exprBaseListener {
    private TokenStreamRewriter rewriter;

    public ReplaceExpr(CommonTokenStream tokens) {
        rewriter = new TokenStreamRewriter(tokens);
    }

    @Override
    public void enterBaseExpr(exprParser.BaseExprContext ctx) {
        rewriter.replace(ctx.start, ctx.stop, new EvaluateExpr().visit(ctx));
    }

    public String getReplacedCode() {
        return rewriter.getText();
    }
}

运行示例

现在我们需要执行表达式的求值和替换。

exprLexer lexer = new exprLexer(new ANTLRInputStream("2 * (3 + 1)"));
CommonTokenStream tokens = new CommonTokenStream(lexer);
exprParser parser = new exprParser(tokens);
ReplaceExpr replaceExpr = new ReplaceExpr(tokens);
ParseTreeWalker.DEFAULT.walk(replaceExpr, parser.program());
System.out.println("Replaced code: " + replaceExpr.getReplacedCode());

解析树或 AST(抽象语法树)

如果您仍然需要修改后的解析树,您可以再次解析更改后的代码。 如果您想修改树结构,请将解析树转换为AST https://www.wikiwand.com/en/Abstract_syntax_tree(抽象语法树),并致力于AST https://www.wikiwand.com/en/Abstract_syntax_tree从头开始。

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

修改表达式,由 Antlr 生成? 的相关文章

  • Junit:如何测试从属性文件读取属性的方法

    嗨 我有课ReadProperty其中有一个方法ReadPropertyFile返回类型的Myclass从属性文件读取参数值并返回Myclass目的 我需要帮助来测试ReadPropertyFile方法与JUnit 如果可能的话使用模拟文件
  • 为 java 游戏创建交互式 GUI

    大家好 我正在创建一个类似于 java 中的 farmville 的游戏 我只是想知道如何实现用户通常单击以与游戏客户端交互的交互式对象 按钮 我不想使用 swing 库 通用 Windows 看起来像对象 我想为我的按钮导入自定义图像 并
  • 如何使用assertEquals 和 Epsilon 在 JUnit 中断言两个双精度数?

    不推荐使用双打的assertEquals 我发现应该使用带有Epsilon的形式 这是因为双打不可能100 严格 但无论如何我需要比较两个双打 预期结果和实际结果 但我不知道该怎么做 目前我的测试如下 Test public void te
  • 如何在 Spring 中禁用使用 @Component 注释创建 bean?

    我的项目中有一些用于重构逻辑的通用接口 它看起来大约是这样的 public interface RefactorAwareEntryPoint default boolean doRefactor if EventLogService wa
  • 如何获取之前的URL?

    我需要调用我的网络应用程序的 URL 例如 如果有一个从 stackoverflow com 到我的网站 foo com 的链接 我需要 Web 应用程序 托管 bean 中的 stackoverflow 链接 感谢所有帮助 谢谢 并不总是
  • jQuery AJAX 调用 Java 方法

    使用 jQuery AJAX 我们可以调用特定的 JAVA 方法 例如从 Action 类 该 Java 方法返回的数据将用于填充一些 HTML 代码 请告诉我是否可以使用 jQuery 轻松完成此操作 就像在 DWR 中一样 此外 对于
  • 没有 Spring 的自定义 Prometheus 指标

    我需要为 Web 应用程序提供自定义指标 问题是我不能使用 Spring 但我必须使用 jax rs 端点 要求非常简单 想象一下 您有一个包含键值对的映射 其中键是指标名称 值是一个简单的整数 它是一个计数器 代码会是这样的 public
  • 将流转换为 IntStream

    我有一种感觉 我在这里错过了一些东西 我发现自己做了以下事情 private static int getHighestValue Map
  • 检测并缩短字符串中的所有网址

    假设我有一条字符串消息 您应该将 file zip 上传到http google com extremelylonglink zip http google com extremelylonglink zip not https stack
  • java.lang.IllegalStateException:提交响应后无法调用 sendRedirect()

    这两天我一直在尝试找出问题所在 我在这里读到我应该在代码中添加一个返回 我做到了 但我仍然得到 java lang IllegalStateException Cannot call sendRedirect after the respo
  • Eclipse Maven Spring 项目 - 错误

    I need help with an error which make me crazy I started to study Java EE and I am going through tutorial on youtube Ever
  • jdbc mysql loginTimeout 不起作用

    有人可以解释一下为什么下面的程序在 3 秒后超时 因为我将其设置为在 3 秒后超时 12秒 我特意关闭了mysql服务器来测试mysql服务器无法访问的这种场景 import java sql Connection import java
  • 获取文件的总大小(以字节为单位)[重复]

    这个问题在这里已经有答案了 可能的重复 java 高效获取文件大小 https stackoverflow com questions 116574 java get file size efficiently 我有一个名为 filenam
  • 专门针对 JSP 的测试驱动开发

    在理解 TDD 到底是什么之前 我就已经开始编写测试驱动的代码了 在没有实现的情况下调用函数和类可以帮助我以更快 更有效的方式理解和构建我的应用程序 所以我非常习惯编写代码 gt 编译它 gt 看到它失败 gt 通过构建其实现来修复它的过程
  • Eclipse 启动时崩溃;退出代码=13

    I am trying to work with Eclipse Helios on my x64 machine Im pretty sure now that this problem could occur with any ecli
  • 我如何在java中读取二进制数据文件

    因此 我正在为学校做一个项目 我需要读取二进制数据文件并使用它来生成角色的统计数据 例如力量和智慧 它的设置是让前 8 位组成一个统计数据 我想知道执行此操作的实际语法是什么 是不是就像读文本文件一样 这样 File file new Fi
  • 干净构建 Java 命令行

    我正在使用命令行编译使用 eclipse 编写的项目 如下所示 javac file java 然后运行 java file args here 我将如何运行干净的构建或编译 每当我重新编译时 除非删除所有内容 否则更改不会受到影响 cla
  • 找不到符号 NOTIFICATION_SERVICE?

    package com test app import android app Notification import android app NotificationManager import android app PendingIn
  • 包 javax.el 不存在

    我正在使用 jre6 eclipse 并导入 javax el 错误 包 javax el 不存在 javac 导入 javax el 过来 这不应该是java的一部分吗 谁能告诉我为什么会这样 谢谢 米 EL 统一表达语言 是 Java
  • Java中super关键字的范围和使用

    为什么无法使用 super 关键字访问父类变量 使用以下代码 输出为 feline cougar c c class Feline public String type f public Feline System out print fe

随机推荐