1

这是一个更普遍的问题,因为我真的不知道如何开始。基本上,我必须使用 Yacc 来解释/翻译一种叫做 CALC 的虚构语言,它可以对变量执行算术运算,然后将它们打印出来。我已经完成了解释工作,但我项目的第二部分是编写一个 C++ 文件,其中包含原始文件中的所有指令,已翻译。

我的问题是,我该怎么做?我是在语法规则的代码中写入文件,还是在 main 中写入?我一直在尝试在语法规则代码中执行此操作,但我发现数据正在向后写入文件(也就是说,如果我声明了四个变量,程序会打印出原始文件中声明的最后一个先编程,以此类推)。

4

3 回答 3

2

好吧,Yacc 确实进行了自下而上的解析。

您大致有两种选择:

  1. 当输入导致减少并且附加代码被执行时,您可以像现在一样输出结果,但是您将需要一直重新排序。

  2. 您可以在规则中构建抽象语法树,然后按顺序遍历它。这是通常的做法。

于 2013-03-03T20:38:11.280 回答
0

数据被向后写入文件

这个特殊的位听起来像是您选择了与您想要的不同的构造。Yacc 允许左递归和右递归,这让您(例如)按照您看到每个项目的顺序(左递归)或相反的顺序解析列表。这是您现在可能正在执行的正确递归的示例:

list : ITEM
     | ITEM list

请注意,当此子语法在输入中看到一个 ITEM 时,它不知道仅基于此使用这两个产生式中的哪一个——它们都以一个 ITEM 开头。因此,解析器向前看一个令牌。如果下一个令牌不是 ITEM,则它知道使用第一个产生式。但是如果下一个令牌是一个项目,那么它必须处理第二个产生式。但是该产生式中包含非终结符list,这意味着解析器实际上根本没有减少,而是将第一个 ITEM 推入堆栈并寻找另一个list.

这样做的结果是,如果你给这个子语法一个 ITEM 标记的列表,它只会继续将它们推入堆栈,直到它最终看到一个没有被另一个 ITEM 跟随的 ITEM。到那时,最终的 ITEM 将被第一个产生式减少(从而变成 a list,并且所有其他 ITEM 将被第二个产生式一个一个减少。在左递归上。

list : ITEM         /* matches first ITEM in list */
     | list ITEM    /* matches all other ITEMs in list */

这一次,当解析器看到一个 ITEM 时,只有一个list产生式以一个 ITEM 开头,所以它会立即减少第一个产生式,把那个 ITEM 变成一个list. 现在,如果输入流中有另一个 ITEM,它将尝试匹配 alist后跟一个 ITEM,并且与第二个产生式完全匹配。

这些是解析简单列表的常用习语。请注意,如果您的列表是“零个或多个”而不是“一个或多个”,那么您只需使用一个空产生式而不是包含单个项目的一个产生式。使用左递归(您通常想要的),拥有一个与第一项匹配的单独产生式为您提供了一个方便的地方来放置一个操作,例如,初始化一个数组,该数组将保存(可能)跟随的所有 ITEM。

于 2013-03-04T20:43:02.053 回答
0

我将分两个阶段执行此操作:使用 yacc 创建解析树,然后遍历树以输出需要输出的任何内容。

于 2013-03-03T20:43:49.720 回答