【问题标题】:Can I use ANTLR for not pre-processed code?我可以将 ANTLR 用于未预处理的代码吗?
【发布时间】:2011-01-28 11:49:28
【问题描述】:

我即将为 OpenEdge(一种 4GL 数据库语言)编写解析器,并且我想使用 ANTLR(或类似语言)。

我认为这可能是一个问题有两个原因:

  1. OpenEdge 是一种 4GL 数据库语言,它允许以下结构:

    assign
        customer.name = 'Customer name'
        customer.age = 20
    .
    

    末尾的. 是行分隔符,此语句结合了两个数据库字段的分配。 OpenEdge 有更多这样的结构;

  2. 我需要保留源文件的所有细节,所以我不能在解析文件之前扩展预处理器语句,所以:

    // file myinc.i
    7 * 14
    
    // source.p
    assign customer.age = {myinc.i}.
    

    在上面的示例中,我需要保留 customer.age 是使用 {myinc.i} 而不是 7 * 14 分配的事实。

我可以使用 ANTLR 来实现这一点还是需要编写自己的解析器?

更新:
我需要这个解析器不是从它生成可执行文件,而是用于代码分析。这就是为什么我需要 AST 来包含使用了 include 的事实。

【问题讨论】:

    标签: c# .net parsing antlr


    【解决方案1】:

    澄清一下:ANTLR 不是解析器,而是解析器生成器。

    您可以为该语言编写自己的解析器,或者为它编写(ANTLR)语法,让 ANTLR 为您生成词法分析器和解析器。您可以在语法中混合自定义代码来跟踪您的作业。

    所以,答案是:是的,您可以使用 ANTLR。

    注意我不熟悉 OpenEdge,但是 SQL 语法通常很难编写解析器或语法。看看ANTLR wiki,看看从头开始写一篇文章并非易事。您没有提到它,但我假设您已经查看了可以解析您的语言的现有解析器?

    仅供参考:您可能已经拥有它,但这里有一个文档链接,包括 OpenEdge SQL 方言的 BNF 语法:http://www.progress.com/progress/products/documentation/docs/dmsrf/dmsrf.pdf

    【讨论】:

    • 我已经更新了问题。我明白你在说什么。我正在查看的具体问题是我需要在我的 AST 中保留预处理器结构。你能详细说明一下这个问题吗?
    • 没有太多要详细说明:如果您自己在语法中不将 {myinc.i} 替换为 7 * 14(或者更好的是:在语法中的自定义代码中),那么 {myinc.i} 将继续存在在您的解析树(或 AST)中。
    • 您如何看待拥有一个预处理器的想法,该预处理器创建一个包含所有扩展组件位置的元流,我可以使用它来增强输出 AST?这样,我将拥有一个干净的语法,但仍保留所有细节并拥有预处理器参数的任何代码参数的 AST(包括可以具有包含部分查询的参数)。有什么建议吗?
    • @Pieter,这与pragma解决方案完全相同。
    【解决方案2】:

    解决方案在于 OpenEdge 架构师本身。您应该签出 opensge 架构师 jar 文件(C:\Progress\OpenEdge\oeide\eclipse\plugins\com.openedge.pdt.core_10.2.1.01\lib\progressparser.jar)

    在这里您可以找到解析器类。它们一直链接到 Eclipse,但我做了与 Eclipse 框架的分离,它可以工作。 progressparser使用antlr,antlr文档可以在以下文件夹中找到... C:\Progress\OpenEdge\oeide\eclipse\plugins\com.openedge.pdt.core_10.2.1.01\oe_common_services.jar。

    在该文件中,您将找到 antlr 定义(检查 opensge.g)。

    祝你好运。如果你想要单独的 eclipse 环境,请给我发邮件。

    【讨论】:

      【解决方案3】:

      您是否知道 OpenEdge / Progress 4GL 已经有一个开源解析器?它被称为Proparse,使用 ANTLR 编写(最初它是在 OpenEdge 本身中手动编码的,但最终转换为 ANTLR)。它是用 Java 编写的,但我认为您可以使用 IKVM 在 C# 中运行它。

      该许可证是 Eclipse 许可证,因此对商业友好。

      【讨论】:

      • 运气好的话,我可以使用该项目中的语法。非常感谢。
      • 当然!在某个时候,我打算使用 Proparse 为 OpenEdge 编写一个新的 linter(Prolint 已经过时了),以便对我们的源存储库的提交进行一些自动代码审查。然而,我的首要任务是让我们的版本控制系统脱离 SourceSafe,这样这甚至是可能的。我很想看看你用 Proparse 做了什么。
      【解决方案4】:

      您可以执行与 C 预处理器相同的操作 - 使用某种设置源位置的 pragma 扩展您的语法,并让您的预处理器生成填充该 pragma 的代码。

      【讨论】:

      • 我已经更新了问题。我需要保留所有细节的原因是我正在进行源代码分析。实际的可执行文件对我没有多大用处,但源代码是。这就是为什么我真的不能使用预处理器的原因,因为这会删除所有有趣的细节,即使是你描述的编译指示(我怀疑你是指#line编译指示)。换句话说:我的 AST 需要包含在代码中当时使用了包含的事实。
      • 您可以发明任何一组编译指示:保留源文件名、行号、列、时间戳等等。
      【解决方案5】:

      多重赋值的问题在语法中很容易处理。只允许多个分配:

      assign_stmt = 'assign' assignments '.' ;
      assignements = ;
      assignments = assignments target '=' expression ;
      

      您可以使用的一种方法是扩充语法,以便在可以允许非终结符的任何地方都允许预处理器标记序列,并且根本不进行预处理器扩展。对于您的示例,您有一些语法规则:

      expression = ... ;
      

      只需添加规则:

      expression = '{'  include_reference '}' ;
      

      在不滥用预处理器来生成跨越非终结边界的多个语言元素的情况下,这有效。

      你打算做什么样的代码分析?几乎要做任何事情,您都需要命名和类型解析,这将需要扩展预处理器指令。在这种情况下,您将需要一个更复杂的方案,因为您需要扩展树来进行名称解析,并且需要相关的包含信息。

      我们的DMS Software Reengineering Toolkit 有一个 OpenEdge 解析器,我们在其中展示了前面的“保留包含文件引用”的技巧。 DMS 的 C 解析器向树中添加一个“宏节点”,其中的宏(OpenEdge“包含”只是编写宏定义的一种有趣方式)子节点包含您所期望的树,以及引用回宏定义。这需要一些仔细的组织,并对它们出现的宏节点进行大量特殊处理。

      【讨论】:

      • 感谢您的回复。我一直在进一步研究 ANTLR,并在词法分析器中解决这个问题看起来像是要走的路。
      猜你喜欢
      • 2015-12-18
      • 1970-01-01
      • 2016-12-08
      • 1970-01-01
      • 2013-11-15
      • 2016-04-28
      • 2015-12-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多