【问题标题】:How to encode FIRST & FOLLOW sets inside a compiler如何在编译器中编码 FIRST 和 FOLLOW 集
【发布时间】:2012-03-17 20:05:51
【问题描述】:

我正在为我正在学习的编译器设计课程编写编译器,我目前正在语法分析中,我需要编写一个解析器。

我需要设置 FIRST 和 FOLLOW 来处理源文本中可能出现的任何错误。我已经为我的语法中的所有非终结符预先计算了 FIRST 和 FOLLOW 集,但是我无法决定我应该在程序中实际编码它们的位置。

我应该将它们放置在关键是非终端名称的地图中吗?

任何建议都会有所帮助

这篇文章可能看起来有点不清楚,如果需要,我可以澄清任何问题。

【问题讨论】:

    标签: grammar recursive-descent compiler-construction


    【解决方案1】:

    如果你想保留它们,你想把它们附加到它们所代表的非终结符上。您可能还需要反转,例如,从集合成员返回到它们是 FIRST 或 FOLLOW 的非终结符的映射。

    然后,您的错误恢复例程可以使用前一个或更可能的“下一个”输入令牌(即导致您报告错误的那个)来决定您可以在输入流中插入什么。

    我实际上并不存储这些。我使用了一个 GLR 解析器,它的解析表本质上是 LALR 解析表,然后简单地构建一个递归算法来爬取这些表,以查看哪些令牌可能允许解析器继续进行。间接地,我利用了 FIRST 和 FOLLOW,因为它们用于构建解析表。

    如果您正在学习编译器设计课程,我建议您关注解析后的问题。您可以花费大量时间尝试“修补”源以响应错误,而您将学到的只是 a) 这很难,并且 b) 没有人会特别喜欢您提供的选择。您可以将精力花在语法修复上,直到脸色发青,但我会等到有人要求您为工作做这件事。同时,对于一个编译器类,我会让我的编译器简单地说“第 N 行的语法错误”并中止。 很糟糕,但足以让您继续更有趣的部分。

    【讨论】:

    • 在处理语法错误时我也想在第一个遇到的错误处停下来,因为显然用户需要修复它才能编译成功;但是这个项目的一个要求是我必须在向用户报告之前收集所有语法错误。
    • 您能详细解释一下倒置吗?这基本上是一些非终端X的第一个和后面的所有终端符号的映射吗?也感谢您的回复,这非常有帮助。
    • @Hunter:“收集所有语法错误?”这有点含糊,因为一旦您修补了输入以便解析器继续运行,您就已经猜到了程序员的实际意图,而猜测永远不会正确。通常,一旦您的解析器继续进行,它将遇到另一个(“级联”)语法错误……这是用户造成的,还是由您的错误恢复引起的?一个便宜的技巧:如果输入标记不可接受,则报告语法错误,将其删除,然后继续(您可能会抑制在同一位置发生的其他语法错误)。 ...
    • @Hunter:第二个便宜(更好)的技巧:将语法中的某些非终结符指定为“恢复点”(例如,“语句”)。确定 LAST(statement) 类似于计算 FIRST 的方式。当您遇到语法错误时,请回溯堆栈,直到找到可以在错误恢复非终结符之一上移动的位置,例如 S(表示“语句”)。将堆栈烧回到那个地方;跳过输入标记,直到你点击 LAST(S) 并把它扔掉,现在假装你看到了一个 S 并继续正常解析。这将通过扫描“;”来跳过“语句”的正文如果您的语言类似于 C。
    • 我正在关注一篇论文,该论文声称如果遇到语法错误,我应该跳过输入符号,直到我到达一个可能会继续编译的符号,即 FOLLOW 中的符号目前正在应用的生产。正如您提到的,这仍然是一个猜测,但作为要求的一部分,我需要记录所有这些级联语法错误并将它们报告给用户。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-27
    • 2011-04-18
    • 2013-07-10
    • 2018-05-05
    • 2014-01-10
    相关资源
    最近更新 更多