我为C++编写了一个LALR(1)解析器17.我发现了156个歧义,其中一些我可以按照标准解决它,但其他我不能.
例如:当遇到小于的时,解析" operator + <...... "时发生Shift-Reduce冲突:
我们可以解析为:
(1)
template-id - > operator-function-id · <......>
要么:
(2)
unqualified-id - > operator-function-id · 其中(1)需要移位但(2)需要减少.
但是,标准有:
名称查找(3.4)后发现名称是模板名称或者operator-function-id或literaloperator-id引用一组重载函数,其中任何成员都是函数模板,如果后面是<,<始终作为模板参数列表的分隔符,而不是小于运算符.解析模板参数列表时,第一个非嵌套> 137被视为结束分隔符而不是大于运算符.
所以我们选择转变.
不幸的是,有很多含糊不清的地方我找不到解决方案.在这里我列出了其中一些(其中一些可以明确做出选择,但我找不到证据):
声明符
(1)当解析noptr-declarator并遇到left-paren时,我应该根据以下内容减少它:
ptr-declarator - > noptr-declarator ·
或者改变左派以满足:
声明器 - > noptr-declarator ·参数和限定符
参数和限定符 - > · left-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
(attribute-specifier-seq是[[.......]])
跟进TonyD的评论:看看为什么不能用LR(1)解析器解析C++?
在某些地方,您基本上必须保持解析产生的歧义,并通过执行名称解析来解决它,或者等效地,您必须将名称解析纠缠到解析过程中.在任何一种情况下,您都必须解释标准以确定如何解决歧义,是的,这是一项非常困难的任务.
然后你就可以找出编译器真正做的事了; GCC和MS都有很多标准的扩展和变体,无论是在语法和语义解释方面(这些都会产生在不同编译器下产生不同结果的程序).最后,您可以找到系统头文件中的可憎之处; 这些都是编译人员为了让他们的生活变得方便而添加的黑客,并且如果有的话,他们的记录非常糟糕.