10

我为 C++17 编写了一个 LALR(1) 解析器。我发现了156个歧义,其中一些我可以根据标准解决它,但其他我不能。

例如:当遇到小于时,在解析“ operator+ < ...... ”时发生 Shift-Reduce 冲突:

我们可以将其解析为:

(1)

模板 ID -> 操作符函数 ID · < ...... >

或者:

(2)

unqualified-id -> operator-function-id · 其中 (1) 需要移位但 (2) 需要减少。

但是,该标准具有:

在名称查找 (3.4) 发现名称是模板名称或 operator-function-id 或literaloperator-id 引用一组重载函数后,其中任何成员都是函数模板,如果后面跟着一个<,< 总是作为模板参数列表的分隔符,而不是小于运算符。解析模板参数列表时,第一个非嵌套 >137 被视为结束分隔符而不是大于运算符。

所以我们选择转移。

不幸的是,有很多歧义我找不到解决方案。在这里,我列出了其中的一些(其中一些可以清楚地做出选择,但我就是找不到证据):

  1. 当出现歧义时,标准中是否有某些部分表明“转移”是默认选择?

声明者

(1)当解析一个 noptr-declarator 并遇到一个左括号时,我应该根据以下方式减少它:

ptr-declarator -> noptr-declarator ·

或移动左括号以满足:

declarator -> noptr-declarator ·参数和限定符

parameters-and-qualifiers -> · left-paren parameter-declaration-clause right-paren......

(2)当解析一个declarator-id遇到左括号时,我应该按照以下方式减少它:

noptr-declarator -> declarator-id · noptr-declarator -> noptr-declarator · \left-bracket ?constant-expression \right-bracket ?attribute-specifier-seq

或移动左方以满足:

noptr-declarator -> declarator-id ·attribute-specifier-seq

(属性说明符序列为 [[.......]])

4

2 回答 2

6

跟进 TonyD 的评论:请参阅Why can't C++ be parsed with a LR(1) parser?

在某些地方,您基本上必须保留解析产生的歧义,并通过名称解析来解决它,或者等效地,您必须将名称解析缠结到解析过程中。无论哪种情况,您都必须解释标准以确定应如何解决歧义,是的,这是一项非常困难的任务。

然后你会发现编译器真正做了什么;GCC 和 MS 在语法和语义解释方面都有许多标准的扩展和变体(这些产生的程序在不同的编译器下会产生不同的结果)。最后,您可以在系统头文件中找到可憎的内容;这些是编译器人员为了方便他们的生活而添加的技巧,如果有的话,它们的文档记录非常糟糕。

于 2016-02-24T10:14:17.863 回答
0

C++ 是图灵完备的来解析.

非常相关的帖子在这里

于 2016-02-24T12:13:19.537 回答