【问题标题】:ANTL4 Parser (Flat parser vs Structor parse) for Language Translator用于语言翻译的 ANTLR4 解析器(平面解析器与结构解析器)
【发布时间】:2022-01-23 04:23:09
【问题描述】:

在过去的几个月里,在本网站成员的帮助下,我已经能够编写(第一阶段)一个 Lexer 和 Parser 来将 Lang X 翻译成 Java。因为我是这个主题的新手,所以我选择了一个简单的逐行解析器,现在它能够在 15 分钟内解析大约 1000 个语言文件,并且出现少量错误/异常和大约 1M 行代码,问题被隔离到源文件而不是解析器。为了更好的表达,我将其称为平面解析。

现在进入第 2 阶段,即转换为 Java。像任何语言一样,我的有数据结构、过程、子例程等,我认为最好从下面更改解析器(为简单起见,我专注于数据结构(称为 TABLE)):

// Main entry point of the program
program
   : executableUnit+ EOF
   ;
   
// Execution units (line by line)
executableUnit:
    |   itemBlockStart
    |   itemBlockEnd
    |   itemStatement
    |   tableHeader
;

itemBlockStart: BEGIN;
itemBlockEnd:   END;
tableHeader: // A TABLE declaration statement
    TABLE atom LETTER (atom)*
;
// Item statement
itemStatement:
        // Tables with Item statements
        ITEM atom+
// Base atom lowest of the low
atom:
        MINUS? INT              #IntegerAtom
    |   REAL_FORMAT             #RealAtom
    |   FIX_POINT               #FixPointAtom
    |   (MINUS | EQUALS)? NAME DOT?     #NameAtom
    |   LETTER                  #LetterAtom
    |   keywords DOT?           #KeywordAtom
    |   DOLLAR atom DOLLAR      #DollarAtom
    |   hex_assign              #HexItem
    ;               

到这里:

// Execution units (by structure)
executableUnit:
        tableStatement
    |   itemStatement
;

// Table statement, header and body
tableStatement:
    tableHeader (itemBlockStart | itemBlockEnd | itemStatement)*;

在我们继续之前,TABLE 和单独的 ITEM 语句可以出现在代码中的任何地方,它们自己(Java 输出将是公共的)或在过程中(Java 输出将是私有的)

想象一下,当解析器产生相同数量的错误,但解析输入的时间要长 10 倍时,我会感到沮丧(如果你愿意的话)。在选择正确的道路方面,我有点理解增加的时间段。我对小组的问题是:

  1. 有没有办法强制解析器提前关闭 TABLE 结构以减少时间段?
  2. 具有这种逻辑树结构分组是否值得增加时间?

我希望朝这个方向发展的愿望是有一个带有迷你树的 Listener 回调,其中所有相关项目都可以访问。 IE。如果过程语句中的迷你树不在 Java 中是公共的。

【问题讨论】:

  • 随着你的变化,语法模棱两可。解析器无法轻易确定 tableStatement 何时结束以及下一个 executableUnit 何时开始。我认为在解析错误时,会有一连串的回溯,剥离一个 itemStatement,重试并再次失败,然后再一次。尝试添加语义谓词来阻止 itemStatement 上的贪婪 * 运算符。实际上是一个有趣的例子,我需要在语法分析中注意和测试。

标签: performance parsing grouping antlr4


【解决方案1】:

我并不完全清楚你指的是什么性能差异(大概是“逐行”解析器和这个完整文件解析器之间的差异。(???)

一些关于你的语法“跳出”的事情,可能会对性能产生一些影响:

1 - itemBlockStart: BEGIN;itemBlockEnd: END;。有一个单一令牌的规则是没有意义的。只需在规则定义中使用令牌即可。

2 - 在此规则 (tableStatement: tableHeader (itemBlockStart | itemBlockEnd | itemStatement)*;) 中,您可能无意中对itemStartBlockitemStopBlock 的接受程度非常 放松。这也可能对性能产生影响。我假设在此回复的其余部分中,BEGIN 应该出现在 itemStatement 的开头,END 应该出现在末尾(并不是这三个可以以任何顺序出现)。

试试这个重构:

// Main entry point of the program
program
   : executableUnit+ EOF
   ;
   
// Execution units (line by line)
executableUnit:
    |   itemStatement  # ItemStmt
    |   tableHeader    # TableHeader
;

tableHeader: // A TABLE declaration statement
    TABLE atom LETTER atom*
;

// Item statement
itemStatement: // Tables with Item statements
    BEGIN ITEM atom+ END
;

// Base atom lowest of the low
atom:   MINUS? INT              #IntegerAtom
    |   REAL_FORMAT             #RealAtom
    |   FIX_POINT               #FixPointAtom
    |   (MINUS | EQUALS)? NAME DOT?     #NameAtom
    |   LETTER                  #LetterAtom
    |   keywords DOT?           #KeywordAtom
    |   DOLLAR atom DOLLAR      #DollarAtom
    |   hex_assign              #HexItem
    ;  

诚然,我不太清楚你的意图是什么,但这应该是朝着正确方向迈出的一步。

正如 Kaby76 所指出的,tableHeader 末尾的贪婪运算符很可能会“吞噬”大量输入。这部分是因为缺少终止令牌(毫无疑问,这会在没有终止令牌之前停止令牌消耗。但是,您的 atom 规则似乎有点像可以匹配所有输入方式的“厨房水槽”规则。再加上atom+atom* 的使用,很有可能会消耗大量令牌。@987654334 中的任何一个真的是你的意图吗@s 可以在没有结构的情况下一个接一个地出现?它们似乎是表达式的片段/部分。如果是这种情况,您将需要为表达式定义语法。这种添加的结构既有助于提高性能,又能为您提供更多有用的解析树。

很像您问题语法中tableStatement 的结构,它并不真正代表任何结构(请参阅我的建议将其更改为BEGIN ITEM atom+ END,而不是接受任何顺序的任何组合。同样的思考过程需要应用于atom。这两种方法都让 ANTLR 遍历您的代码,消耗大量令牌,而没有任何关于订单是否实际正确的线索(然后在出现问题时尝试“退出”非常昂贵遇到)。

【讨论】:

  • 嗨,迈克,我的意图是从一个扁平的逐行解析器转移到一个更结构化的标记树。我相信我需要朝这个方向前进,因为当我将树翻译成 Java(例如使用 JavaPoet)时,我会拥有更多的 context。例如。如果 TABLE 包含在过程中,则生成的 Java 输出将是过程的私有。相反,如果它不是那么它的公共。我可能会看到其他理解上下文的方式,但这样做似乎更多地利用了 Antlr4。
  • P.S.我确实将 // 表语句、标题和正文更改为 tableStatement: tableHeader (itemBlockStart itemStatement+ itemBlockEnd)?但这似乎没有帮助。我希望 esd 提供明确的结束/终止声明。
  • 我在回答中添加了一些内容。简而言之,您的语法似乎对它将接受什么作为有效输入并包含贪婪结构非常“放松”。这种组合将有重大的性能问题。它也不会提供非常有用的解析树(您将如何处理“atoms 的列表”?)。如果您打算逐渐添加更多规则来覆盖该结构,那么在您有足够的定义以使 ANTLR 可以快速识别输入中的错误、报告并恢复之前,这将是痛苦的并且表现不佳。
  • 只是一个猜测.. 看起来有点像您试图在整个输入上获得一种“有效”的语法,然后从那里改进规则(因此,atom+atom*,并且表语句没有终止标记。)。我建议您从“自下而上”开发事物可能会有更好的体验。确保您的所有标记都是正确的,然后为正确的表达式设置正确的规则等,并根据这些规则测试代码子集。然后从那里建立起来。让 ANTLR 验证结构并构建好的解析树是它的主要价值。
  • 嗨,迈克,1) 我在某些方面感到放松是有原因的:
猜你喜欢
  • 2014-02-23
  • 2016-03-18
  • 2020-10-19
  • 1970-01-01
  • 2023-03-12
  • 2011-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多