Algorithm 如何创建允许语法错误的AST解析器?

Algorithm 如何创建允许语法错误的AST解析器?,algorithm,compiler-construction,language-agnostic,abstract-syntax-tree,Algorithm,Compiler Construction,Language Agnostic,Abstract Syntax Tree,首先,关于解析和构建AST应该阅读什么 如何为将构建AST并允许语法错误的语言(如SQL)创建解析器 例如,对于“3+4*5”: 对于有语法错误的“3+4*+”,解析器会猜测用户的意思是: + / \ 3 * / \ 4 + / \ ? ? 从哪里开始 SQL: 对于如何构建解析器(即构建AST)的问题,标准答案是在编译时阅读标准文本。阿霍和厄尔曼的“龙”编译书非常经典。如果你没有耐心得到最好的参考资料,你会有更多的麻烦,因为它们提供了理论和研究细

首先,关于解析和构建AST应该阅读什么

如何为将构建AST并允许语法错误的语言(如SQL)创建解析器

例如,对于“3+4*5”:

对于有语法错误的“3+4*+”,解析器会猜测用户的意思是:

  +
 / \
3   *
   / \
  4   +
     / \
    ?   ?
从哪里开始

SQL:


对于如何构建解析器(即构建AST)的问题,标准答案是在编译时阅读标准文本。阿霍和厄尔曼的“龙”编译书非常经典。如果你没有耐心得到最好的参考资料,你会有更多的麻烦,因为它们提供了理论和研究细节。但是对于那些急于构建递归下降解析器的人来说

可以使用内置的错误恢复构建解析器。关于这类事情的论文很多,这是20世纪80年代的一个热门话题。查看谷歌学者,搜索“语法错误修复”。其基本思想是,解析器在遇到解析错误时,会跳转到一些著名的信标(“对于类似C的语言,语句分隔符非常流行,这就是为什么在注释中询问您的语言是否有语句终止符的原因”),或提出各种输入流删除或插入,以克服语法错误。这类计划的种类之多令人惊讶。关键思想通常是尽可能多地考虑错误点周围的信息。我见过的最有趣的想法之一是有两个解析器,一个在另一个之前运行N个令牌,寻找语法错误地雷,第二个解析器是在遇到语法错误之前基于可用的N个令牌进行错误修复。这允许第二个解析器在出现语法错误之前选择不同的操作。如果您没有这个,大多数解析器会丢弃左上下文,从而失去修复的能力。(我从未实施过这样的计划。)

要插入的内容的选择通常可以从用于首先构建解析器的信息(通常是FirstFollow集)中派生出来。对于L(AL)R解析器来说,这是相对容易的,因为解析表包含必要的信息,并且在解析器遇到错误时可用。如果您想了解如何做到这一点,您需要了解解析器是如何构造的理论(面向对象的,这又是一本编译器手册)。(我已多次成功实施该计划)

不管您做什么,语法错误修复都没有多大帮助,因为几乎不可能猜测解析文档的编写者的实际意图。这表明,花哨的计划并没有真正的帮助。我坚持简单的原则;人们很高兴得到一个错误报告和一些半优雅的继续解析

为真正的语言运行自己的解析器的一个真正问题是,真正的语言是令人讨厌的、混乱的东西;构建真正的实现的人会因为现有的代码基础而出错并僵化,或者因为语言很酷而坚持弯曲/改进语言(标准是用于WIMP的,好东西是用于营销的)。预计会花费大量时间,对照真实代码的基本事实,重新校准您认为的语法。作为一般规则,如果您想要一个工作的解析器,最好得到一个有跟踪记录的解析器,而不是自己使用它


大多数一心想构建解析器的人没有得到的一个教训是,如果他们想对解析结果或树做任何有用的事情,他们将需要比解析器更基本的机器。查看我的个人简历中的“解析后的生活”。

解析器可以做两件事:

  • 报告错误并让用户重试
  • 修复错误并继续
  • 一般来说,第一种更容易(也更安全)。当语法错误时,可能没有足够的信息供解析器推断意图。根据具体情况,继续修复可能会导致输入语法正确但语义错误

    我已经为一些小语言编写了一些手动递归下降解析器。当编写代码来显式解释语法规则时(与使用解析器生成器相反),很容易检测到错误,因为下一个标记不符合生产规则。生成的解析器倾向于发出简单的“expected$(TOKEN\u TYPE)here”消息,这对用户来说并不总是有用的。使用手工编写的解析器,通常很容易给出更具体的诊断消息,但覆盖每种情况可能会很耗时

    如果您的目标是报告问题,但要继续解析(以便查看是否存在其他问题),则可以在树中的错误点放置一个特殊的AST节点。这样可以防止树倒塌


    然后,为了继续解析,您必须重新同步到错误之外的某个点。正如Ira Baxter在他的回答中提到的,你可以寻找一个标记,比如“;”,这将语句分开。要查找的正确标记取决于您正在解析的语言。另一种可能性是猜测用户的意思(例如,在检测到错误时推断出额外的令牌或不同的令牌),然后继续。如果在接下来的几个标记中遇到另一个语法错误,您可以回溯,做出不同的猜测,然后重试。

    ASTs始终允许语义错误,这是一个语法错误。修复了有问题的错误类型。谢谢)你的语言有一种界定语句的方法吗?它们都“允许”语法错误,因为这在实践中是不可避免的。您需要的是语法错误恢复/修复。@IraBaxter我已更正。(对不起,在看到您的回复之前,我删除了我的原始评论。)
      +
     / \
    3   *
       / \
      4   +
         / \
        ?   ?
    
        SELECT_________________
       /           \           \
      .           FROM        JOIN
     / \           |         /    \
    a city_name  people   address  ON
                                    |
                                    =______________
                                   /               \
                                  .____             .
                                 /     \           / \
                                p  address_id     a  id