修改表达式,由 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 生成? 的相关文章

  • 如何从 AccountManager.getAccounts() 获取与特定帐户关联的图标

    每个帐户的帐户设置中都会显示一个图标 对于 Google 帐户有一个图标 对于 Facebook 帐户有另一个图标 有没有办法从应用程序的代码中获取该图标 最后我解决了 private Drawable getIconForAccount
  • 在 Windows 7 中,不从命令行强制终止 JVM

    我在 JVM 中运行了 Cobertura 仪器化 jar 当我在运行应用程序的 Windows 控制台中按 Ctrl C 时 JVM 结束并Cobertura 结果已成功刷新到 cobertura ser 文件 但我需要使用命令 工具 不
  • 哪个 new 首先执行——在构造函数中还是在构造函数外?

    如果我定义一个类如下 public class myClass private x new anotherClass private y public myClass y new anotherClass 哪个变量会更早获得实例 x 或 y
  • android-透明RelativeLayout

    我想要制作一个具有可绘制渐变作为背景的活动 并将在其背景顶部显示 4 个面板 相对布局 现在我想让 4 个面板透明 例如 50 以便也可以看到渐变背景 我搜索了谷歌 但我发现只能通过活动而不是布局来做到这一点 如何做我想做的事 您可以创建一
  • 将对象列表传递给 Freemarker 然后循环

    我已经熟悉了 FreeMarker 一个 Java 模板引擎 我已经能够通过哈希映射将对象传递给模板引擎了 这样就可以了 但是 一旦我尝试将任何类型的多个对象集传递给 FreeMarker 它就会给我一个 freemarker templa
  • 将图像缩略图上传到服务器,而不上传整个图像

    据我所知 我在这里问的是不可能的 但我想无论如何我都会问 以防我遗漏了什么 假设您想让用户上传 JPG 图像 并且这些图像被缩放为较小的图标 并且原始图像始终被丢弃并且不再需要 有没有什么方法可以在大多数现代浏览器中普遍使用 让用户选择硬盘
  • Android 背景 + 文本 + 按钮图标

    我想要一个图像设置为文本的背景 并在文本的左侧设置一个图标 在iPhone中非常简单 但不知道如何在Android上做到这一点 调整按钮的大小并保持图标 文本的位置和距离正确 iPhone 安卓我有这个 xml代码是
  • 使用java在mysql中插入带有\\的文件路径

    我正在使用java制作一个独立的应用程序 并且我需要插入用户从文件选择器中选择的图像的路径 我正在获取文件的路径 但是当我将其存储在数据库 mysql 中时 它不会存储 所以当我检索该路径时 该文件不会显示 如何存储文件的路径 这样就可以使
  • 在 Eclipse 中导航 Java 调用堆栈

    在调试器中像GDB http sources redhat com gdb 当您在断点处停止时 您可以轻松地向上移动调用堆栈并检查相关的源和堆栈帧数据 在 Eclipse 中如何做到这一点 In the 调试视角 http www ibm
  • 如何更改tomcat jmx密码的文件权限

    我正在尝试保护 Windows 平台上托管的本地 tomcat 实例上的 JMX 访问 我已经创建了访问权限和密码文件 并使用以下 VM 参数插入这些文件 Dcom sun management jmxremote password fil
  • 如何告诉 Java SAX 解析器忽略无效字符引用?

    当尝试使用字符引用解析不正确的 XML 时 例如 x1 Java 的 SAX 解析器因致命错误而惨死 例如 org xml sax SAXParseException Character reference x1 is an invalid
  • 获取运行时生成的类的字节

    我正在使用一个 Java 框架 该框架使用自定义类加载器在运行时生成一些 代理 类 我想为任何这样的类获取自定义 ClassLoader 从 loadClass 返回的与该类对应的原始字节数组 这可能吗 我知道 如果一个类作为资源存在 那么
  • Spring @Configuration如何缓存对bean的引用

    使用基于 Java 的配置时 Spring 如何防止再次调用 bar 我想知道编译时注释处理或通过代理方法 Configuration public class AppConfig Bean public Foo foo return ne
  • Java 通用问题

    下面的代码可以编译 但如果我取消注释行 它不会编译 我很困惑为什么 HashMap 确实扩展了 AbstractMap 并且声明映射的第一行可以正常编译 import java util AbstractMap import java ut
  • 如何根据服务器/环境动态加载服务器配置?

    目前 我设置了 Maven 配置文件 以便能够为不同的环境 开发 演示 暂存 生产等 部署我的项目 并且它工作得很好 但问题是 对于我拥有的每个模块 Web 应用程序 我需要复制 粘贴此配置文件 它们都是属性文件 当我需要更改环境 服务器配
  • Hive NVL 不适用于列的日期类型 - NullpointerException

    我正在使用 HDFS 上的 MapR Hive 发行版并面临以下问题 如果表的列类型是 日期 类型 则NVL https cwiki apache org confluence display Hive LanguageManual UDF
  • 如果可能,将 jFrame 输出到第二台显示器

    我在 Java 中的 Swing 上有一个 jFrame 我希望它输出到第二个监视器 如果该监视器存在 我尝试过这个 通过this http download oracle com javase 6 docs api java awt Gr
  • 确保对象实现 Comparable

    我有一个小问题 想知道如何解决它 我有一个通用类Tuple
  • 使用反射 API 填充 Proto 中的地图字段

    我正在尝试编写一个模块 该模块将获取 Message Builder 和从字段名称到值的映射 并将用值填充构建器 一切正常 直到我遇到地图字段 使用 Proto3 我收到一条特定消息 我知道我可以执行该消息的字段 builder b put
  • 在私有 guice 模块中公开 Map

    我在 guice 中有一个 PrivateModule 我想从该模块公开一个 Map public class TestInjectionModule extends PrivateModule expose Map class annoa

随机推荐