12

我正在尝试基于 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)
4

2 回答 2

9

好吧,我们是否能想出一个语法模棱两可的案例并不重要。N1570 第 6.7.2.4 节第 4 段规定:

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

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

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

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

于 2012-05-20T13:20:28.037 回答
8

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

_Atomic int (*f)(int);

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

int _Atomic (*f)(int);

通常类型限定符可以在 the 之后int,这应该等同于另一个声明。但是 now_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这将inside重新声明main为一个函数。并且所有四行都是相同功能的有效原型。现在使用_Atomic作为限定符

typedef int toto;

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

这应该作为带有const. 现在我们有一个例子,_Atomic括号后面是一个类型,但它不是类型说明符。

于 2012-05-19T22:34:03.987 回答