【问题标题】:ANSI C - direct-declarator grammar - Why does the C grammar allow syntactically legal, but sementically illegal declarations like int func()()?ANSI C - 直接声明符语法 - 为什么 C 语法允许语法上合法但语义上非法的声明,如 int func()()?
【发布时间】:2018-05-10 13:46:26
【问题描述】:

ANSI C 语法规定:

declarator:
    pointer_opt direct-declarator

direct-declarator:
    identifier
    ( declarator )
    direct-declarator [ constant-expression_opt ]
    direct-declarator ( parameter-type-list )
    direct-declarator ( identifier-list_opt )

根据这个语法,可以推导出来

func()()

作为声明者,并且

int func()()

作为声明,这在语义上是非法的。为什么 C 语法允许这种语法上合法但语义上非法的声明?

【问题讨论】:

  • 这真的是关于 C89 的吗?把语言律师放在那里?
  • 语法的相关部分是pointer:* type-qualifier-listopt* type-qualifier-listopt pointertype-qualifier-list:type-qualifiertype-qualifier-list type-qualifier。这些允许您为每个指针(constvolatilerestrict)提供无限数量的类型限定符,但这并不意味着将其中的 30 个连续写入是有意义的。是的,你在一个层面上是对的,但它大多是无关紧要的。 (数字中的数字是语法没有限制的另一个地方。...)
  • 这个语法在 C11 中实际上是一样的。

标签: c syntax grammar declaration c89


【解决方案1】:

这类问题通常无法确定地回答,因为您要询问的是关于 C 委员会的集体思想和审议的信息,在 1989 年。他们从未像负责 Python 的人那样完全公开地进行语言开发工作,而 30 年前他们这样做的更少。如果你亲自调查他们,他们可能不会记得了。

我们可以查看C Rationale document(我链接到对应于 C1999 的版本,但据我所知自 1989 年以来它并没有太大变化)寻找线索,但快速浏览一下,我不知道'看不到任何与您的问题相关的内容。

这让我根据编程语言设计的一般原则进行猜测。 有一个与您的问题相关的一般原则:特别是对于较旧的语言,设计人员会尽量使正式语法为context-free。这使得编写高效的解析器变得更加容易。诸如“你不能有一个返回函数的函数”之类的规则需要上下文,因此它们被排除在语法之外。将它们作为应用于解析树的事后约束来处理很简单,这就是设计人员所做的。

C 语法有很多地方似乎都使用了这个原则,而不仅仅是你要问的那个。例如,存在用于标记化的“最大咀嚼”规则,因为这意味着标记器不需要了解完整的解析器上下文,即使它会导致不方便的结果,例如 a-----b 被解释为 a -- -- - b 而不是a -- - -- b,即使解析器会拒绝前者但接受后者。

编程语言的这种设计原则常常令初学者感到惊讶,因为它与人类理解自然语言的方式大不相同;我们将不遗余力地从最荒谬的句子中“修复”某种上下文适当的含义,实际上我们在对话中rely on this。考虑worse is better 的元原理可能会有所帮助(过于简单化,因为您可以快速完成前 90% 的工作并将其放在那里,然后对剩余的 90% 进行迭代)。

【讨论】:

  • 非常感谢您的澄清回答。
  • 如果没有 typedef,编写一个上下文无关的语法会相当简单,该语法不允许返回类型为函数或数组的函数。语法会更复杂,但它不必是上下文相关的。但是,由于您可以为数组或函数类型设置别名,因此仍然需要语义限制以防止 ArrayType foo(void); 有效。由于无论如何都需要额外的语法限制,因此语法复杂化几乎没有意义(甚至比现在更复杂)。
【解决方案2】:

为什么 C 语法允许像 int func()() 这样的语法合法但语义非法的声明?

您的问题基本上可以自行回答: 很简单,这是因为接受语法上合法的结构是语法的全部工作。如果某些东西在语法上是合法的,但在语义上是无意义的或非法的,那么拒绝它不是语法的工作——它稍后会在语义分析期间被拒绝。

如果问题是,“为什么语法没有不同的写法,所以语义上非法的构造在语法上也是非法的(这样语法可以拒绝它们)?”,答案是,通常需要权衡是否在解析或语义分析期间拒绝事物。 C 的声明语法非常复杂,显然希望使接受它的语法与它必须的一样复杂,但不会比它必须的复杂得多。通常,您可以通过将某些检查推迟到语义分析阶段来保持语法非常简单。

【讨论】:

    【解决方案3】:

    为什么 C 语法允许这种语法上合法但语义上非法的声明?

    是什么让您认为期望语言语法无法表达任何语义不正确的语句是明智的?

    甚至不是所有的语义问题都可以在编译时检测到(例如:y = 1 / x;,除了x 为零时,它是明确定义的)。即使制定语法规则以使其不接受任何可以在编译时在语义上被证明是错误的语句、声明或表达式,也没有什么好处。由于编译器必须以任何一种方式进行语义分析,这会使语法规则变得非常复杂。

    请注意,语言标准的主要受众是,而不是机器。这就是为什么它用散文来描述语言语义的原因。

    【讨论】:

      猜你喜欢
      • 2012-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-30
      • 2020-06-09
      • 2021-12-20
      相关资源
      最近更新 更多