ANSI C - 直接声明符语法 - 为什么 C 语法允许语法上合法但语义上非法的声明,如 int func()()?

ANSI C - direct-declarator grammar - Why does the C grammar allow syntactically legal, but sementically illegal declarations like int func()()?

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 语法允许这种语法上合法但语义上非法的声明?

这类问题通常无法得到肯定的回答,因为您要询问的是有关 C 委员会集体思想和审议的信息,1989 年。他们从来没有像负责 Python 的人那样完全以 public 的方式进行语言开发工作,三十年前他们这样做的更少。如果您亲自对他们进行投票,他们可能不会记得。

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

这让我只能根据编程语言设计的一般原则进行猜测。 与您的问题相关的一般原则:特别是对于较旧的语言,设计者尽量使正式语法成为 context-free。这使得编写高效的解析器变得更加容易。 "you can't have a function that returns a function" 之类的规则需要上下文,因此它们被排除在语法之外。将它们作为应用于解析树的 post-hoc 约束来处理是很简单的,所以这就是设计人员所做的。

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

这种编程语言的设计原则常常令初学者感到惊讶,因为它与人类理解自然语言的方式大相径庭;即使是最荒谬的句子,我们也会竭尽全力 "repair" 某种上下文适当的含义,实际上我们 rely on this in conversation. It might help to contemplate the meta-principle that worse is better (过于简单化,因为你可以完成前 90% 的工作快速将其放在那里然后迭代剩余的 90%)。

Why does the C grammar allow such syntactically legal, but sementically illegal declarations?

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

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

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

Why does the C grammar allow syntactically legal, but semantically illegal declarations like int func()()?

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

如果问题是 "Why wasn't the grammar written differently, so that semantically illegal constructs were also syntactically illegal (such that the grammar could reject them)?",答案是在解析或语义分析期间是否拒绝事物通常是一种权衡。 C 的声明语法非常复杂,显然希望使接受它的语法尽可能复杂,但不会比它必须的复杂得多。通常,您可以通过将某些检查推迟到语义分析阶段来使语法非常简单。