1

我很难理解我应该做什么。我唯一想到的是我需要在 cminus.y 文件上使用 yacc。我对之后的一切都感到困惑。有人可以以不同的方式向我解释这一点,以便我了解我需要做什么吗?

介绍:

我们将使用 lex/flex 和 yacc/Bison 来生成 LALR 解析器。我会给你一个名为 cminus.y 的文件。这是一个 yacc 格式的语法文件,用于一种名为 C-minus 的简单的类 C 语言,来自 Kenneth C. Louden 的 Compiler Construction 一书。我认为语法应该是相当明显的。雅虎组有几个关于如何使用 yacc 的描述的链接。既然您知道了 flex,那么学习 yacc 应该是相当容易的。唯一的基本类型是 int。一个 int 是 4 个字节。布尔值作为整数处理,就像在 C 中一样。(实际上,语法允许您将变量声明为 void 类型,但我们不要这样做。)您可以拥有一维数组。没有指针,但对数组元素的引用应被视为指针(如在 C 中)。该语言提供赋值、IF-ELSE、WHILE 以及函数调用和返回。我们希望我们的编译器输出 MIPS 汇编代码,然后我们将能够在 SPIM 上运行它。对于像这样没有优化的简单编译器,IR 应该不是必需的。我们可以一次直接输出汇编代码。然而,我们的第一步是生成一个符号表。

符号表:

我喜欢 Barrett 博士在这里的方法,它使用大量指针来处理不同类型的对象。本质上,符号表的元素是标识符、类型和指向属性对象的指针。属性对象的结构会根据类型而有所不同。我们只有少数类型需要处理。我建议至少在开始时使用线性搜索来查找表中的符号。如果您想要更好的性能,您可以稍后将其更改为散列。(如果你想保留在 C 中,你可以使用 malloc 动态分配对象。)首先你需要列出所有不同类型的符号 - 数量不多 - 以及哪些属性是必要的每个。确保允许添加新属性,因为我们尚未涵盖所有问题。看语法,函数的参数列表问题是需要在设计中投入一些思考的地方。我建议更多的符号表条目和指针。

测试:

语法是正确的,因此采用现有语法并生成解析器,解析器将接受正确的 C 减号程序,但不会产生任何输出,因为没有与规则关联的代码片段。我们想添加代码片段来构建符号表并打印信息。声明标识符时,应打印输入符号表的信息。如果在同一范围内找到了相同符号的先前声明,则应打印错误消息。引用标识符时,您应该在表中查找它以确保它存在。如果尚未在当前范围内声明,则应打印错误消息。关闭范围时,应为未引用的标识符生成警告。您的测试输入应该是格式正确的 C 减号程序,

范围:

最基本的方法具有全局范围和声明的每个函数的范围。该语言允许在任何复合语句中声明,即范围嵌套。实现这一点需要某种范围编号或堆叠方案。(堆叠最适合一次性编译器,这是我们正在构建的。)

4

1 回答 1

3

(免责声明)我对编译器类没有太多经验(如在编译器的学校课程中),但这是我的理解:

1)您需要使用提到的工具来创建一个解析器,当给定输入时,它会告诉用户输入是否是与 cminus.y 中定义的语法有关的正确程序。我从未使用过 yacc/bison,所以我不知道它是如何完成的,但这似乎是这样做的:

  • (input) file-of-some-sort 表示要解析的输出
  • (output) reply-of-some-sort ,它告诉 (input) 对于提供的语法是否正确。

2) 输出似乎还需要检查变量一致性(即,您不能使用未声明为与任何编程语言相同的变量),这是通过符号表完成的。简而言之,每次声明某些内容时,您都将其添加到符号表中。当您遇到一个标识符时,如果它不是语言标识符之一(如iforwhilefor),您将在符号表中查找它以确定它是否已被声明。如果它在那里,请继续。如果不是 - 打印某种错误

注意:point(2) 对符号表进行了简化;实际上,它们的内容比我刚刚写的要多,但这应该可以帮助您入门。

我将从 yacc 示例开始 - 看看 yacc 可以做什么以及它是如何做到的。我想那里一定有一些大的示例完整的符号表,您可以阅读以进一步理解。

例子:

让我们输入 A:

int main()
{
     int a;
     a = 5;
     return 0;
}

并输入 B:

   int main()
    {
         int a;
         b = 5;
         return 0;
    }

并假设我们使用 C 语法进行解析。你的解析器应该认为输入 A 没问题,但应该对输入 B 大喊“b 未声明”。

于 2009-11-16T10:06:07.600 回答