如何使用Antlr实现函数调用,以便在定义之前就可以调用它?

2024-01-27

一旦构建了 AST,实现树遍历器以便可以按任意顺序定义和调用函数的最佳方法是什么?

例如,这在 PHP 中是有效的:

<?php
f(); // function called before it’s defined
function f() {
  print 3;
}
?>

我猜想一定有第二遍,或者树转换,但我在这个主题上找不到任何有趣的东西。这个问题可能不是 Antlr 特有的问题,但如果你能给我一个 Antlr 示例来说明如何完成此操作,那就更好了!


是的,你是对的:这是通过多次 AST 完成的。

首先创建一个语法来构建源的 AST,然后创建一个树语法,用于迭代树并发现所有定义的函数。然后,您可以使用另一个树语法来评估脚本,该语法从先前的树语法中获取发现的函数。

A demo.

取源码:

<?php
f(); // function called before it’s defined
function f() {
  g();
}
function g() {}
?>

它被解析为以下 AST:

使用(组合)语法:

grammar PHPMin;

options { 
  output=AST; 
}

tokens {
  SCRIPT; F_CALL; F_DECL; F_BODY;
}

parse
  :  script EOF -> script
  ;

script
  :  '<?php' atom* '?>' -> ^(SCRIPT atom*)
  ;

atom
  :  functionCall
  |  functionDecl
  ;

functionCall
  :  Identifier '(' ')' ';' -> ^(F_CALL Identifier)
  ;

functionDecl
  :  'function' Identifier '(' ')' '{' functionBody '}' -> ^(F_DECL Identifier functionBody)
  ;

functionBody
  :  functionCall* -> ^(F_BODY functionCall*)
  ;

Identifier  : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')* ;
LineComment : '//' ~('\r' | '\n')* ('\r'? '\n' | EOF){skip();} ;
Space       : (' ' | '\t' | '\r' | '\n'){skip();} ;

然后使用从以下树语法生成的“tree-walker”发现声明的函数:

tree grammar PHPMinFunctionWalker;

options {
    tokenVocab=PHPMin;
    ASTLabelType=CommonTree;
}

@members {
    java.util.Set<String> declared = new java.util.HashSet<String>();
}

discover
  :  script
  ;

script
  :  ^(SCRIPT atom*)
  ;

atom
  :  functionCall
  |  functionDecl
  ;

functionCall
  :  ^(F_CALL Identifier)
  ;

functionDecl
  :  ^(F_DECL Identifier functionBody) {declared.add($Identifier.text);}
  ;

functionBody
  :  ^(F_BODY functionCall*)
  ;

为了测试这一切,创建一个词法分析器和解析器 (A),生成“tree-walker”(B),编译所有源文件 (C):

// A
java -cp antlr-3.2.jar org.antlr.Tool PHPMin.g

// B 
java -cp antlr-3.2.jar org.antlr.Tool PHPMinFunctionWalker.g

// C
javac -cp antlr-3.2.jar *.java

// D     
java -cp .:antlr-3.2.jar Main    // *nix 
java -cp .;antlr-3.2.jar Main    // Windows

并运行以下主类(D):

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;

public class Main {

    public static void main(String[] args) throws Exception {

        String source = "<?php                                          \n" + 
                        "f(); // function called before it’s defined    \n" + 
                        "function f() {                                 \n" + 
                        "  g();                                         \n" + 
                        "}                                              \n" + 
                        "function g() {}                                \n" + 
                        "?>                                             \n";

        // create a lexer and parser for the source
        ANTLRStringStream in = new ANTLRStringStream(source);
        PHPMinLexer lexer = new PHPMinLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        PHPMinParser parser = new PHPMinParser(tokens);
        PHPMinParser.parse_return returnValue = parser.parse();
        CommonTree tree = (CommonTree)returnValue.getTree();

        // create a tree walker to discover all declared functions
        CommonTreeNodeStream nodes = new CommonTreeNodeStream(tree);
        nodes.setTokenStream(tokens);
        PHPMinFunctionWalker functions = new PHPMinFunctionWalker(nodes);
        functions.discover();
        System.out.println("Declared functions: "+functions.declared);
    }
}

产生以下输出:

Declared functions: [f, g]

当然,这只是如何实现它的一个示例,而不是如何最好地完成它的示例。我可以想象(当使用 Java 解释脚本时),您不会将声明的函数作为简单的字符串存储在Set<String>,而是作为Map<String, CommonTree>轻松获取函数的根并在调用时对其求值。

进一步阅读:http://www.antlr.org/wiki/display/ANTLR3/Simple+tree-based+interpeter http://www.antlr.org/wiki/display/ANTLR3/Simple+tree-based+interpeter

祝你好运!

EDIT

然后,秒数传递可以检查是否使用之前的树遍历器在其之前定义了所有函数:

tree grammar PHPMinValidateWalker;

options {
    tokenVocab=PHPMin;
    ASTLabelType=CommonTree;
}

@members {
    java.util.Set<String> declared = new java.util.HashSet<String>();
}

validate
  :  script
  ;

script
  :  ^(SCRIPT atom*)
  ;

atom
  :  functionCall
  |  functionDecl
  ;

functionCall
  :  ^(F_CALL Identifier) 
     {
       if(!declared.contains($Identifier.text)) {
         throw new RuntimeException("no such function: " +  $Identifier.text);
       }
     }
  ;

functionDecl
  :  ^(F_DECL Identifier functionBody)
  ;

functionBody
  :  ^(F_BODY functionCall*)
  ;

使用测试:

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;

public class Main {

    public static void main(String[] args) throws Exception {

        String source = "<?php                                          \n" + 
                        "f(); // function called before it’s defined    \n" + 
                        "function f() {                                 \n" + 
                        "  g();                                         \n" + 
                        "  x();                                         \n" + 
                        "}                                              \n" + 
                        "function g() {}                                \n" + 
                        "?>                                             \n";

        // create a lexer and parser for the source
        ANTLRStringStream in = new ANTLRStringStream(source);
        PHPMinLexer lexer = new PHPMinLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        PHPMinParser parser = new PHPMinParser(tokens);
        PHPMinParser.parse_return returnValue = parser.parse();
        CommonTree tree = (CommonTree)returnValue.getTree();

        // create a tree walker to discover all declared functions
        CommonTreeNodeStream nodes = new CommonTreeNodeStream(tree);
        nodes.setTokenStream(tokens);
        PHPMinFunctionWalker functions = new PHPMinFunctionWalker(nodes);
        functions.discover();
        System.out.println("Declared functions: "+functions.declared);

        // PHPMinValidateWalker
        nodes = new CommonTreeNodeStream(tree);
        nodes.setTokenStream(tokens);
        PHPMinValidateWalker validator = new PHPMinValidateWalker(nodes);
        validator.declared = functions.declared;
        validator.validate();
    }
}

产生异常,因为x()没有在任何地方定义。从源中删除它将导致树遍历器不会产生异常。

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

如何使用Antlr实现函数调用,以便在定义之前就可以调用它? 的相关文章

  • ANTLR语法互左递归

    我确实知道这个问题已经被问过很多次了 我正在尝试使用 ANTLR 构建语法 Predicate LOWERCASE Predicate VarChars VarChars LOWERCASE UPPERCASE fragment LOWER
  • xtext 中的终端/数据类型/解析器规则

    我正在使用 xtext 2 4 我想做的是类似 SQL 的语法 让我困惑的是我不确定哪些东西应该被视为终端 数据类型 解析器规则 到目前为止我的语法相关MyTerm is Model terms MyTerm MyTerm constant
  • 使用 ANTLR 解析循环

    我想使用 ANTLR 解析一个简单的类似 matlab 的 for 循环 循环就像 for i 1 8 y i a i i end 我想解析循环并解析8次y i a i i语句 以便对每个语句执行一些操作 我的规则如下 操作在 C 中描述
  • 如何使用 Clang 从 C++ 字符串生成 AST?

    我正在尝试使用 Clang 操作 C 源代码 但在发现 API 时遇到问题 我想获取一串 C 源代码并从中生成 AST 就像是 auto myAst clang parse auto x 1 1 有一个最小的工作示例吗 您可以尝试下一个代码
  • 从 Python AST 生成 .pyc?

    如何从 Python AST 生成 pyc 文件以便可以从 Python 导入该文件 我用过compile创建一个代码对象 然后编写co code属性到文件 但是当我尝试从 Python 导入文件时 我得到一个ImportError Bad
  • 将 xtext 编辑器支持与外部 ANTLR 解析器链接起来

    我当前的项目 将其命名为 IoTSuite 采用高级规范 解析它们 并生成 Java 和 Android 代码 在这个项目中 我编写了 ANTLR 语法来解析高级规范 并使用 StringTemplate 作为代码生成器 然而 由于良好的编
  • PHP 中正则表达式的解析器?

    我需要将正则表达式解析为 PHP 中的组件 我创建或执行正则表达式没有问题 但我想显示有关正则表达式的信息 例如列出捕获组 将重复字符附加到其目标 整个项目是一个 WordPress 插件 它提供了有关重写规则的信息 这些规则是具有替换模式
  • JavaScript,执行函数

    我有下一个功能 var hideAll function code return 我在另一个函数中像回调一样使用这个函数 当我像这样使用它时 function params hideAll 一切正常 但是当我使用时 function par
  • API 来比较 AST? [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 是否有一个开源java api允许比较java源代码的两个抽象语法树 我想看看两个语法树之间的差异 类
  • Antlr 语法生成无效的 C# 代码

    我正在尝试使用 ANTLR 和 StringTemplate 库开发一个 C 代码生成器 AntlrWorks 可以生成 C 解析器和词法分析器文件 而不会报告任何错误 但是 c 解析器代码无效 无法在 Visual Studio 中编译
  • ANTLR @header、@parser、superClass 选项和基本文件 io (Java)

    我想将解析器操作与基本文件 io Java 一起使用 例如 G ANTLR 语法中的 PrintWriter 我必须使用 superClass 选项还是可以使用 header 在这两种情况下 我如何声明 PrintWriter 对象以及如何
  • 为什么 Python 中的函数/方法调用成本昂贵?

    In 这个帖子 https web archive org web 20180919031245 https plus google com 115212051037621986145 posts HajXHPGN752 Guido van
  • 即使不匹配,ANTLR 词法分析器规则也会消耗字符吗?

    我有一个 antlr 词法分析器规则的奇怪副作用 并且我创建了一个 几乎 最小的工作示例来演示它 在这个例子中我想匹配字符串 0 1 例如 但是当我调试语法时 到达解析器的令牌流仅包含 1 第一个整数 无论 它包含多少位数字 总是会被消耗
  • 如何获取 Kotlin AST?

    我有一个包含 Kotlin 源代码的字符串 如何在运行时编译它并获取抽象语法树和类型信息进行分析 我对 Kotlin 编译器进行了一些调查 一些获得 AST 的概念证明可以在我的网站上看到GitHub 仓库 https github com
  • clang:自定义属性在 AST 中不可见

    我按照官方手册中的描述在 clang 中实现了一个自定义属性 http clang llvm org docs InternalsManual html how to add an attribute http clang llvm org
  • ANTLR“无法启动调试器。等待连接到远程解析器超时。”

    我在 AntlrWorks 中运行的 ANTLR 语法之一抛出 无法启动调试器 等待连接到远程解析器超时 过去 此消息通常会消失 但此消息会持续存在 在搜索 ANTLR 列表时 例如http www antlr org pipermail
  • Spirit qi 解析为嵌套函数的抽象语法树

    我正在尝试使用 boost 的spirit qi 解析器创建一个解析器 它正在解析包含三种类型值的字符串 常量 变量或函数 这些函数可以相互嵌套 测试字符串是f a b f g z x g x h x c where a e是常数 f r是
  • 使用 neo4j 建模有序树

    我刚刚开始使用 neo4j 并且了解图形和关系的原理 但是我在想要建模的某些结构方面遇到了一些麻烦 我想在编程语言项目中使用它 并存储已解析源文件的 AST 从那里 我计划向节点添加大量额外的数据和关系 以帮助分析和工具 但基本的 AST
  • 用 C++ 生成 AST

    我正在用 C 制作一个解释器 到目前为止我已经有了词法分析器来生成标记 问题是我不确定如何生成 行走 解析树 我正在考虑使用数组数组来制作解析树 但我不确定如何以正确的顺序将标记实际插入到解析树中 我不确定是自上而下 左右还是自下而上 左右
  • 使用 ANTLR 验证 LL(1) 语法

    我知道 ANTLR 可以接受 LL 语法 但是 有什么方法可以使用 ANTLR 检查语法是否是 LL 1 吗 options k 1 如果你的语法不在 LL 1 中 它会发出警告

随机推荐

  • 当“pop”元素同时“for”循环列表时发生了什么[重复]

    这个问题在这里已经有答案了 Code arr i for i in xrange 10 for i in arr if i in arr print i arr pop 0 print arr 和输出 python2 7 ts py 0 2
  • Android通知大图标,有没有办法去掉右下角的小图标?

    我有一条显示大图标的通知 有什么方法可以从此视图中删除蜂窝及以上设备中的较小图标 显然还是保留了顶部状态栏的小图标 NotificationCompat Builder builder new NotificationCompat Buil
  • 如何格式化Swagger 2.0文本描述?

    我想格式化我的 Swagger API 描述 以便它们不是简单的文本段落 最好 我想添加一张小桌子 我在 Swagger 描述中没有找到有关文本格式的在线参考 如果我启动招摇编辑器 http editor swagger io 然后打开 I
  • 如何创建动态过滤器?

    我有一张装有设备的桌子 每个设备都有维护级别的日期 用户可以选择维护级别 因此 我应该针对所选维护级别的每个组合调整我的 SQLAlchemy 例如 SELECT WHERE equipment IN AND m level1 DATE A
  • 如何解决“资源要求请求启用 CORS…资源已被阻止,因为无法强制执行完整性”错误

    我在项目中使用引导图标 这给了我错误 子资源完整性 资源 http maxcdn bootstrapcdn com bootstrap 3 3 6 css bootstrap min css http maxcdn bootstrapcdn
  • 生成加起来等于某个数字的所有唯一数字组合

    我正在编写一个程序来尝试解决数学问题 我需要生成一个唯一的列表 其中包含所有与另一个数字相加的数字 例如 所有 4 个数字加起来为 5 的唯一组合是 5 0 0 0 4 1 0 0 3 2 0 0 3 1 1 0 2 2 1 0 2 1 1
  • 程序控制流程未按预期工作

    这是一个问题C 程序控制流程不符合预期 它要求输入字符 in 但未能要求输入字符 x int foo int main int argc const char argv foo return 0 int foo char in char x
  • 如何覆盖odoo new api中字段的默认函数

    我有一个调用函数来获取默认值的字段 在模块project forecast中 def default user id self return self env user if default user id not in self env
  • 如何从Python中的十六进制字符串中删除'\x'?

    我正在读一本wavPython 中的音频文件使用wave模块 这readframe 该库中的函数以十六进制字符串形式返回帧 我想删除 x这个字符串的 但是translate 功能无法按我想要的方式工作 gt gt gt input wave
  • Keras 中预测的流输出

    我在 Keras 中有一个 LSTM 我正在训练它来预测时间序列数据 我希望网络在每个时间步上输出预测 因为它将每 15 秒收到一个新输入 所以我正在努力解决的是训练它的正确方法 以便它在接收 x 0 x 1 x t 作为输入流时将输出 h
  • Javac 调试打开和关闭之间有性能差异吗?

    如果我打开使用 Javac 生成调试信息 则类文件会增大 20 25 这对运行 Java 程序有任何性能影响吗 如果是的话 什么条件以及多少 我预计对加载类会有一点影响 因为文件较大 但这应该是最小的 在任何语言中 调试信息都是元信息 它本
  • 如何将 HTML 转换为 XHTML? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我需要将 HTML 文档转换为有效的 XML 最好是 XHTML 最好的方法是什么 有人知道工具包 库 样本 任何可以帮助我完成任务的东西
  • 每次查询后关闭 MySQL 连接

    在挖掘一位我敬佩的前同事整理的一些旧代码时 我注意到每次查询后他们都会关闭 MySQL 服务器的连接 这看起来有点奇怪 因为我总是在页面末尾关闭它 并且看到大多数人都这样做 那么问题来了 这是 PHP MySQL 中最好的想法吗 无论如何
  • 使用 Bash 获取一对 HTML 标签之间的内容

    我需要使用 bash 脚本获取一对给定标签之间的 HTML 内容 作为示例 具有以下 HTML 代码 text div text2 div text3 div div 使用 bash 命令 脚本 给定body标签 我们会得到 text di
  • 在 Windows 上分配开始失败之前检测内存运行不足

    我们有一个应用程序可能会分配大量小对象 取决于用户输入 有时应用程序会耗尽内存并导致崩溃 然而 如果我们知道内存分配变得紧张 那么一些优先级较低的对象可能会被销毁 从而允许我们优雅地降低用户结果 在调用 new 实际失败之前检测进程内存不足
  • 从 Metro 应用程序检测桌面可用性(检测 ARM、检测 Windows RT 系统)

    这是一个相关的问题在 WinRT Metro 应用程序 C 中获取操作系统版本 https stackoverflow com questions 10125324 get os version in winrt metro app c s
  • 如何在c#中从arraylist中检索对象

    如何在 C 中从 arraylist 中检索对象及其成员 你的意思是这样吗 ArrayList list new ArrayList YourObject myObject new YourObject list Add myObject
  • AJAX、子域和 SSL

    我有一个网站 foo com 它向 bar foo com 发出 ajax 请求 这行得通吗 另外 如果 foo 是安全连接 https 那么 bar foo com 也需要是 https 吗 这两个站点可以使用不同的证书吗 使用纯 htt
  • 在 cygwin 中运行简单的 map-reduce hadoop 示例时出现问题

    我只是想在独立模式下运行 64 位 Windows 7 的笔记本电脑上运行 Hadoop 我已将 Cygwin 1 7 安装在默认文件夹 c cygwin 中 我在文件夹 c jdk1 7 0 03 中有最新的 JDK 并设置了 JAVA
  • 如何使用Antlr实现函数调用,以便在定义之前就可以调用它?

    一旦构建了 AST 实现树遍历器以便可以按任意顺序定义和调用函数的最佳方法是什么 例如 这在 PHP 中是有效的 我猜想一定有第二遍 或者树转换 但我在这个主题上找不到任何有趣的东西 这个问题可能不是 Antlr 特有的问题 但如果你能给我