【问题标题】:Is GLR algorithm a must when bison parsing C grammar?野牛解析C语法时必须使用GLR算法吗?
【发布时间】:2020-01-19 09:33:30
【问题描述】:

我正在尝试用 flex/bison 学习 C 语法。

我发现 bison 无法解析这个 bison 语法:https://www.lysator.liu.se/c/ANSI-C-grammar-y.html,因为 LALR 算法无法递归处理多个表达式。

C语法一定要GLR算法吗?

【问题讨论】:

  • 仅供参考,Gcc 已经将解析器从 bison 更改为手写自上而下的解析器已有一段时间了,就像 Clang 所做的那样。正如程序员所说,没有办法避免在野牛中添加丑陋的黑客来解析代码。目前据我所知,没有编译器再使用 LR,所以我认为 GLR 对于 C 语法来说不是必须的。
  • 您是如何得出 bison 无法解析该语法的结论的?它肯定可以,所以如果您在尝试时遇到问题(很可能与在语法期望的地方生成类型名标记有关),在此处描述这些问题可能会更有帮助,因此我们可以帮助您解决它们。
  • 删除了 C++ 标签。 C++ 有非常不同的解析要求,但在问题的任何地方都没有提到。

标签: c compiler-construction bison flex-lexer


【解决方案1】:

该语法没有任何问题,除了:

  • 它代表了一个非常旧的 C 版本
  • 它需要一个能够以某种方式区分IDENTIFIERTYPE_NAME 的词法分析器
  • 它甚至不尝试处理预处理器阶段

此外,由于"dangling else" 的歧义,它有一个移位/减少冲突。但是,可以忽略该冲突,因为在这种情况下,bison 的冲突解决算法会产生正确的结果。 (您可以使用%expect 指令或通过包含优先声明来抑制警告,该声明有利于转移else 而不是减少if。或者您可以使用维基百科页面中描述的technique 消除语法中的歧义上面链接。(注意:我不是在谈论从维基百科页面复制和粘贴代码。在 C 的情况下,您需要考虑所有以 if 语句结尾的复合语句的情况。)

此外,LR 解析器不是递归的,它没有可以描述为“递归处理多个表达式”失败的问题。 (你可能会遇到递归下降解析器的问题,尽管它很容易解决这个问题。)

因此,您可能遇到的任何问题(如果您的问题涉及具体问题)与您的问题中描述的内容无关。

在我上面列出的问题中,最令人不安的是强制转换运算符的语法歧义。强制转换运算符实际上并不模棱两可。显然,C 编译器设法正确编译此类表达式。但是区分(x)-y*z 的两种可能的解析需要知道x 是命名类型还是变量。

在 C 中,所有名称都是词法范围的,因此当然可以在编译时解析 x。但该决议不是上下文无关的。由于 GLR 也是一种用于解析上下文无关文法的技术,因此使用 GLR 解析器不会直接帮助您。从理论上讲,GLR 解析器可以生成“解析森林”而不是解析树,这可能很有用;也就是说,GLR 解析器的输出可能有效地包含所有可能的正确解析,从而可以通过为每个作用域构建符号表来解决歧义,然后通过检查每个站点上有效的名称绑定来选择替代解析。 (这是因为类型别名声明——“typedefs”——没有歧义,所以所有潜在的解析都将具有相同的别名声明。)

不过,通常的解决方案是使用确定性解析器解析程序文本,在解析过程中维护一个符号表,并让词法分析器访问这个符号表,以便区分 IDENTIFIER 和 @987654333 @,正如您链接的语法所预期的那样。这种技术被礼貌地称为“词法反馈”,尽管它也经常被称为“词法分析器”。

【讨论】:

  • 嗨,请告诉我,如何修复这个语法中的shift/reduce
  • @linrongbin:你看过我提供的维基百科链接了吗?无论如何,正如我在答案中所说,您不需要做任何事情。 Bison 的默认分辨率完美运行。
  • @linrongbin:另外,不要在生产代码中使用该语法。它已经严重过时了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多