【问题标题】:C11 grammar ambiguity between _Atomic type specifier and qualifier_Atomic 类型说明符和限定符之间的 C11 语法歧义
【发布时间】:2012-05-19 21:21:00
【问题描述】:

我正在尝试基于 N1570 为 C11 编写 lex/yacc 语法。我的大部分语法都是从信息丰富的语法摘要中逐字复制的,但出现了一些 yacc 冲突。我已经设法解决了所有问题,除了一个:“_Atomic”用作类型说明符和用作类型限定符之间似乎存在一些歧义。

在说明符形式中,_Atomic 后面紧跟括号,所以我假设它与 C 的很少使用的语法有关,它允许声明符放在括号中,从而允许括号紧跟限定符。但是我的语法已经知道如何区分 typedef 名称和其他标识符,所以 yacc 应该知道区别,不是吗?

我这辈子都想不出一个实际上是模棱两可的案例。

我怀疑它是否有帮助,但这是我使用 yacc 的 -v 标志时得到的相关状态输出。 “ATOMIC”显然是我对“_Atomic”的标记名称

state 23

  152 atomic_type_specifier: ATOMIC . '(' type_name ')'
  156 type_qualifier: ATOMIC .

    '('  shift, and go to state 49

    '('       [reduce using rule 156 (type_qualifier)]
    $default  reduce using rule 156 (type_qualifier)

【问题讨论】:

  • 在语法中区分说明符和限定符在很大程度上是行不通的,因为声明可以按任何顺序混合说明符和限定符:const unsigned int, unsigned const int, int unsigned const, ...

标签: c grammar yacc c11


【解决方案1】:

好吧,我们是否能想出一个语法上模棱两可的情况并不重要。 N1570 第 6.7.2.4 节第 4 段指出:

如果 _Atomic 关键字后紧跟左括号,则将其解释为类型说明符(带有类型名称),而不是类型限定符。

为了强制执行此操作,我只是在我的 lex 规则中将 _Atomic 作为说明符,将 _Atomic 作为限定符单独标记。

"_Atomic"/{WHITESPACE}*"(" {return ATOMIC_SPECIFIER;}
"_Atomic"                  {return ATOMIC_QUALIFIER;}

总的来说,我对 lex/yacc 和解析器生成器比较陌生,但我的直觉认为这是一种 hack。同时,lex 中的尾随上下文语法还有什么用途?

【讨论】:

  • 如果中间有 cmets 会失败。
  • @o11c 在同一行的代码之间放置 cmets 的人将被枪决。
【解决方案2】:

是的,我认为规范中有歧义。采取

_Atomic int (*f)(int);

这里的_Atomic 是一个类型限定符。 (作为函数的返回类型,它没有多大意义,但我认为是有效的)。现在采取这种替代形式

int _Atomic (*f)(int);

通常类型限定符可以出现在int 之后,这应该等同于另一个声明。但是现在_Atomic 后面是括号,所以它必须被解释为一个类型说明符,这是一个语法错误。我认为甚至可以编写一个示例,将*f 替换为有效的typedef

看看6.7.2.4 p4的第一句

与原子类型相关的属性仅对 左值表达式。

这清楚地表明他们不期望函数的返回类型是_Atomic 限定的。

编辑:

同样的歧义会发生在

_Atomic int (*A)[3];

这很有意义(一个指向三个原子整数数组的指针)并且我们应该能够重写为

int _Atomic (*A)[3];

编辑 2: 要查看括号中包含类型的标准没有消除歧义,请使用以下有效的 C99 代码:

typedef int toto;

int main(void) {
  const int toto(void);
  int const toto(void);
  const int (toto)(void);
  int const (toto)(void);
  return toto();
}

这将toto 内部的main 重新声明为一个函数。并且所有四行都是相同功能的有效原型。现在使用_Atomic 作为限定符

typedef int toto;

int main(void) {
  int _Atomic (toto)(void);
  return toto();
}

这应该与带有const 的版本一样有效。现在我们有一个例子,_Atomic 后面跟有括号,里面有一个类型,但它不是类型说明符。

【讨论】:

  • 当你说,“但是现在 _Atomic 后面跟着括号,所以它必须被解释为类型限定符”我假设你的意思是,“但是现在 _Atomic 后面跟着括号,所以它必须是解释为类型说明符”?
  • 嗯,原子类型说明符规则要求括号中的类型名称,而不是声明符,所以我认为带有星号的_Atomic(*anything) 永远不会是有效的原子-类型说明符。但我最近在标准 (6.7.2.4 - 4) 中注意到了这一点:如果 _Atomic 关键字后面紧跟左括号,则将其解释为类型说明符(带有类型名称),而不是类型限定符. 在这种情况下永远不会有歧义。括号表示类型说明符,无括号表示限定符,就这么简单。现在以某种方式将该规则合并到我的语法中......
  • @JoBates,首先,我不是那样读的。对我来说,它说 must 括号中有一个类型。其次,我认为消除歧义是不够的。我会试着做一个例子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-22
  • 2015-01-21
  • 2011-01-20
  • 1970-01-01
  • 1970-01-01
  • 2022-01-17
  • 2014-12-21
相关资源
最近更新 更多