数据被向后写入文件
这个特殊的位听起来像是您选择了与您想要的不同的构造。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。