关于语法/解析器理论的问题

时间:2011-12-27 10:44:15

标签: parsing compiler-construction

我最近完成了第一个用于专用编程语言的解析器/编译器。我在这种语言的规范中有一些自由,在某些地方我调整了规范,以便更容易解析;在某些地方,这导致了一些(迄今为止)语言本身的改进。也许我会在将来的v2中修复它们;现在我还在消化我从这个过程中学到的东西,我对此有几点疑问。我从未参加过关于编译器设计的正式课程,因此我想验证我的理解是否符合该领域的最新技术水平。

  • 大多数文章和教科书将解析过程分为两个阶段:标记化和词法分析。然后通常会提到,在大多数实际实现中,两者通常有些交织在一起,以使实现更容易。我自己的经验是相反的,因为混合它们使事情变得更难,我甚至添加了第三遍。我做了第一遍,我做了简约的标记化,我的意思是我以最简单的形式定义'标记'。我尝试了一些方法,例如,构造函数作为一个整体是'令牌'。我放弃了这种方法,现在只调用'令牌'这个程序最基本的构建块。然后我做了一个词法分析传递,我建立了一个AST。然后我的第三遍是(我称之为)结构分析,其中我做了例如类型检查,检查传递给函数的参数数量是否与这些函数的签名相匹配等。这通常不是“解析”的一部分,还是放在“词法分析”之下,或者为什么文献主要提出两个 - 通过解析方法? (可以说我有第四遍,代码生成,但这主要是一个单独的过程)。

  • 我的词法分析器(我认为)是递归下降的 - 我有匹配令牌流的例程或者当它们不能时返回false,然后尝试匹配另一个'规则',直到所有令牌都被处理。这些例程最多可以看到2个令牌;据我所知,这意味着我有一个'LL(2)语法'。我的问题是:这个数字有什么关系? “LL(1)语法”在某种程度上比那些数字更高的人更好吗?另外,为什么回溯不受欢迎? (或者不是,我只是误解?)

  • 为什么语法的分类如此重要?所有文本都以它们(通常是相当广泛的)的解释开头,但据我所知,如果不改变你设计的语言的工作方式,你就无法真正改变语法的属性。现在我明白,如果你想解析现有的语言,对它的结构进行分类将使你能够证明生成的解析器的复杂性类;但是在设计一种新语言时,(imo)最重要的是表达性或其他类型的适用性,并且解析器的性能是次要的。虽然我意识到这最后一部分是有争议的,但是在设计新语言时,是否有实际的原因要仔细观察语法的类型?

1 个答案:

答案 0 :(得分:4)

  1. 我认为你的术语有点令人困惑。解析只涉及从源到AST,并分为“阶段”,而不是“通过”。使用“pass”一词意味着它们是按顺序执行的,这通常是不正确的。

    实际上词法分析(即标记化)和实际解析交织在一起的原因是由于目标语言中的句法特性:通过定义“上下文敏感”标记可以更好地描述许多真实语言的语法。考虑使用字符串插值或用户可定义的运算符的语言。

  2. LL(k)语法的解析表在最坏的情况下以k为指数增长,我想这就是使它们成为坏名称的原因(对于k> 1)。如果您手动实现递归下降解析器,那么前瞻并不重要。然而,回溯仍然很糟糕,因为它可能导致指数运行时间。

  3. 您可以在不影响目标语言的情况下更改语法。确保语法属于某个类允许您使用现有工具(如LALR解析器生成器),并为您提供有关解析器的运行时特征的一些信息。我同意语言设计不应该通过解析考虑来指导,虽然一点常识确实有帮助,或者你最终会得到像C ++这样不可思议的混乱。