Parsing 解析器语法中的循环依赖

Parsing 解析器语法中的循环依赖,parsing,grammar,yacc,Parsing,Grammar,Yacc,我正在尝试构建我的第一个解析器。不幸的是,我不熟悉语法理论,现在我想知道它是否是 明令禁止 只是个坏主意或者 还可以 在我的语法中有循环依赖关系。我的直觉发出了警告,但由于我不熟悉解析器的理论,我不能确定 如果我的lexer定义良好,并且是它的标记,那么我有以下语法: list_content : value | list_content COMMA list_content list : LBRACE list_content

我正在尝试构建我的第一个解析器。不幸的是,我不熟悉语法理论,现在我想知道它是否是

  • 明令禁止
  • 只是个坏主意或者
  • 还可以
在我的语法中有循环依赖关系。我的直觉发出了警告,但由于我不熟悉解析器的理论,我不能确定

如果我的lexer定义良好,并且是它的标记,那么我有以下语法:

list_content    : value
                | list_content COMMA list_content

list            : LBRACE list_content RBRACE

value           : INT
                | list
其中,
值取决于
列表
列表
取决于
列表内容
列表内容
取决于

我以前在语法中见过递归定义,例如:

sum             | NUMBER + NUMBER
                | NUMBER + sum
                | LBRACE sum RBRACE
然而,我认为,我的循环定义是不同的(就:dirtier而言),因为它更难概述,而且定义循环跨越多个语法规则。我不确定我的循环定义是否会在语法中造成歧义。我还担心这会使我的代码难以调试

因此,我有两个问题:

A) 我应该重组我的语法(和词法)还是接受这个循环定义


B) 如果我应该重新构造,我最好怎么做?

像这样的循环依赖很好——它是一个递归定义,类似于在程序中使用递归。因此,需要关注的重要问题是基本情况是如何实现的,因为这就是重复终止的方式。如果没有基本情况(或者在不触发额外递归的情况下无法达到基本情况),那么就有一个问题——一个永远无法匹配任何有限输入的无限循环

在您的例子中,基本情况是
原语
规则——因为
可以简化为单个
原语
,而
列表内容
可以简化为单个
,所以一切都很好

你的语法确实有一个问题,那就是规则

list_content: list_content COMMA list_content
这是模棱两可的。这意味着,对于任何包含三个或更多元素(两个或更多逗号)的列表,都有多种解析方法——首先匹配左逗号(左递归)或右逗号(右递归)。这将导致大多数无法处理歧义的解析器工具出现问题,并且在您的情况下可能与此无关(您并不真正关心解析它的方式,因为您很可能只是连接列表)

解决方法是将规则重写为一个简单的左或右递归规则(但不是两者都重写)。您想要使用哪一种取决于您正在使用的解析器样式——对于LL(自顶向下或递归下降)解析器,您需要一个正确的递归规则。对于LR(自底向上或shift/reduce)解析器,您(通常)需要一个左递归规则

  • 左递归:
    list_content:value | list_content逗号值
  • 右递归:
    list_content:value | value逗号list_content

当我意识到我最初发布的语法不是我问题的一个小例子后,我编辑了我的文章。我删除了
原语
规则,只放了终止令牌
INT
。核心问题基本上没有改变,你的答案仍然是一个有效且非常好的答案。但是,如果您希望该线程的后续读者更容易理解您的答案,您可能希望对您的答案进行必要的小更新,以使其与问题的更新版本保持一致。很抱歉造成混乱和额外的工作!