根据C ++标准的语法分析数字文字的不一致

时间:2018-12-11 11:39:25

标签: c++ syntax c-preprocessor language-lawyer user-defined-literals

通读C ++ 17标准,在我看来,由预处理器处理的 pp-number 与数字文字(例如 user-defined-integer-literal ,因为它们被定义为由“上层”语言处理。

例如,根据预处理程序语法,以下内容正确地解析为 pp-number

123_e+1

但是放置在C ++ 11兼容代码片段的上下文中,

int  operator"" _e(unsigned long long)
    { return 0; }

int test()
    {
    return 123_e+1;
    }

当前的Clang或GCC编译器(我尚未测试其他编译器)将返回类似于以下的错误:

unable to find numeric literal operator 'operator""_e+1'

未找到operator"" _e(...)且试图定义operator"" _e+1(...)的情况将是无效的。

这似乎是由于编译器首先将令牌作为 pp-number 进行词法分析,然后又无法回滚并为 {{ 1}} 解析最终表达式时。

相比之下,以下代码可以很好地编译:

user-defined-integer-literal

这是对标准的正确阅读吗?如果是这样,编译器应该处理这种可能很少见的特殊情况是否合理?

1 个答案:

答案 0 :(得分:3)

您已经成为maximal munch rule的牺牲品,该词法分析器使用尽可能多的字符来构成有效的令牌。

[lex.pptoken]p3节对此进行了介绍,该段内容为(强调我的):

  

否则,下一个预处理标记是可能构成预处理标记的最长字符序列,即使会导致进一步的词法分析失败,除了标题名称([lex。标头])仅在#include指令内形成。

并包含几个示例:

  

[示例:

#define R "x"
const char* s = R"y";           // ill-formed raw string, not "x" "y"
     

-示例]

     

4 [示例:程序片段 0xe + foo被解析   作为预处理数字令牌(不是有效的浮动或   整数文字标记),即使将其解析为三个预处理   标记0xe,+和foo可能会产生有效的表达式(例如,   如果foo是定义为1的宏)。同样,程序片段1E1   被解析为预处理编号(一个有效的浮点数   文字标记),无论E是否为宏名。 —示例]

     

5 [示例:程序片段x +++++ y解析为x ++ ++ + y,   如果x和y具有整数类型,则违反   即使分析x ++ + ++ y可能会产生一个增量运算符   正确的表达。 —示例example]

此规则在a+++++btokens >= which required a fix to allow等其他一些知名案例中也会生效。

pp-token 语法如下:

pp-number:  
  digit  
  . digit  
  pp-number digit  
  pp-number identifier-nondigit 
  pp-number ' digit  
  pp-number ' nondigit    
  pp-number e sign  
  pp-number E sign  
  pp-number p sign  
  pp-number P sign  
  pp-number .  

注意e sign的产生,这就是这种情况的困扰。另一方面,如果您像第二个示例一样使用d,则不会点击该(see it live on godbolt)。

添加间距也可以解决您的问题,因为您将不再受到最大的浪费(see it live on godbolt):

123_e + 1