Dan*_*aum 10 c++ standards c++11
提出一个被认为过于挑剔的问题的风险,我花了很长时间试图证明(作为在不同背景下贯穿整个标准的事物的一个例子)下面的integer literal§2.14.2中的定义.C++ 11标准,特别是关于一个细节,在语法符号本身中存在空格.
(注意,这个例子 - 整数文字的定义 - 不是我的问题.我的问题是询问C++标准本身使用的语法描述符号,特别是关于语法类别名称之间的空格我在这里给出的例子 - 整数文字的定义 - 是专门选择的,因为它只是一个简单明了的例子.)
(缩写为简称,来自§2.14.2):
integer-literal:
decimal-literal integer-suffix_opt
decimal-literal:
nonzero-digit
decimal-literal digit
Run Code Online (Sandbox Code Playgroud)
(有nonzero-digit和digit如预期的,[0] 1 ... 9).(注意:上面的文字在标准中都是斜体.)
这一切对我来说很有意义,假设语法范畴描述内容之间的空间decimal-literal和digit被理解为不会出现在实际的源代码,但只出现在语法描述本身,因为它出现在这里部分§2.14.2.
这种约定 - 在符号中的类别描述符之间放置一个空格,其中理解该空间不存在于源代码中 - 在规范中的其他地方使用.这里的例子只是一个明确的案例,其中显然不应该在源代码中出现空格.(参见此问题的附录,其中包含空格或其他分隔符必须存在的标准的反例,或者当源类型中的实际标记替换这些类别描述时,类别描述之间是可选的.)
同样,冒着被挑剔的风险,我无法在标准的任何地方找到一个约定声明,在解释符号时,例如在本例中,空格不会出现在源代码中.
该标准确实讨论了§1.6.1(及其后)中的符号约定.我能找到的唯一相关文字是:
在本国际标准中使用的语法表示法中,句法类别以斜体类型表示,文字词语和字符以恒定宽度类型表示.替代方案在单独的行中列出,除了少数情况下,一长串备选方案用短语"one of"标记.
我不会那么挑剔; 但是,我发现标准中使用的符号有些棘手,所以我想清楚所有细节.我感谢任何愿意花时间来填补这个问题的人.
附录 为了回应一些声明,其中声明类似于" 很明显,最终源代码中不应包含空格,因此标准无需明确说明 ":我在这个问题中选择了一个简单的例子,很明显.有许多情况下,它的标准是不是很明显没有.先验的语言知识(在我看来),如§8.0.4讨论"const"和"volatile":
cv-qualifier-seq:
cv-qualifier cv-qualifier-seq_opt
Run Code Online (Sandbox Code Playgroud)
...请注意相反的假设(最终源代码中需要空格或其他分隔符或分隔符),但这不可能从语法表示法本身推断出来.
还有一些空间是可选的,例如:
noptr-abstract-declarator:
noptr-abstract-declarator_opt parameters-and-qualifiers
Run Code Online (Sandbox Code Playgroud)
(在这个例子中,为了说明一点,我不会给出部分编号或解释正在讨论的内容;我只是问一下,从语法符号本身来看,在这个上下文中,最终源代码中是否有空格在令牌之间是可选的.)
我怀疑沿着这些方向发表的评论 - "很明显,这就是它必须是什么" - 是我所选择的例子如此明显的结果.这正是我选择这个例子的原因.
§2.7.1
标记,关键字,文字,运算符和其他分隔符有五种标记.如下所述,空白,水平和垂直制表符,换行符,换页符和注释(统称为"空白空间")将被忽略,除非它们用于分隔令牌.
因此,如果文字是一个标记,并且空格用于分隔标记,则文字数字之间的空格将被解释为两个单独的标记,因此不能是同一文字的一部分.
我有理由相信标准中没有更直接的解释这个事实.
使用的符号类似于典型的BNF,它们将许多相同的一般约定视为理所当然,包括符号中的空格除了分离BNF本身的标记之外没有任何意义 - 如果/当空白具有重要性时除了分隔标记之外的源代码,它们还包括用于直接指定它的符号(例如,对于大多数预处理指令,new-line直接指定:
#ifdef identifier new-line group opt
要么:
#include <h-char-sequence>换行
对此的责任可能可以追溯到Algol 68标准,该标准在精确指定语法的过程中远远落后于其他任何人在没有数周的全日制学习1的情况下阅读基本上是不可能的.从那时起,语法描述语言的最粗略的解释导致拒绝,因为它太像Algol 68,并且无疑会失败,因为它太正式,没有人会阅读或理解它.
1你问怎么可能那么糟糕?它基本上是这样的:他们从语法描述语言的正式英语描述开始.但这并不是用来定义Algol 68的 - 它用于指定(甚至更精确地)另一种语法描述语言.这第二则语法描述语言被用来指定的Algol 68本身的语法.因此,在开始阅读Algol 68语法本身之前,您必须学习两种不同的语法描述语言.你可以毫无疑问地猜测,几乎没有人做过.
正如你所说,标准说:
\n\n\n等宽类型的文字单词和字符
\n
因此,如果规则中包含文字空间,则必须以恒定宽度类型呈现。仔细检查该标准将发现您所引用的产品中的空间比恒定宽度类型更窄。(此外,您尝试引用该标准是一种误传,因为它以恒定宽度类型呈现,而本应以斜体呈现,从而导致语义更改。)
\n好吧,这就是“有抱负的语言律师”的答案;此外,它并没有真正起作用,因为它在所有以下形式的产品上都失败了:
\nOne of:\n0 1 2 3 4 5 6 7 8 9\nRun Code Online (Sandbox Code Playgroud)\n我认为,实际上,答案是空格不是正式语法的一部分,因为它仅用于分隔标记;此外,该陈述对于语法本身来说大多是正确的,其标记由空格分隔,而该空格不是标记,除了语法中的缩进很重要,这与程序中的缩进不同。
\n附录 回答附录
\n实际上这不是真的const,volatile需要用空格分隔。它们只需是单独的令牌即可。例子:
#define A(x)x\nA(const)A(volatile)A(int)A(x)A(;)\nRun Code Online (Sandbox Code Playgroud)\n更严肃地说,第 2 章(特别参考 2.2 和 2.5,但您必须阅读整个文本)描述了如何处理程序文本以生成令牌流。您声明必须忽略空格的所有规则都在语法的这一部分中,而您声明可能需要空格的所有规则则不然。
\n这实际上是两个独立的语法,但词法语法必然是不完整的,因为您需要考虑预处理器的操作才能应用它。
\n我相信我所说的一切都可以从标准中收集到。以下是一些摘录:
\n\n\n2.2(3) 源文件被分解为预处理标记(2.5)和空白字符序列(包括注释)\xe2\x80\xa6 将源文件\xe2\x80\x99s个字符划分为预处理标记的过程是依赖于上下文。
\n\xe2\x80\xa6
\n2.2(7) 分隔标记的空白字符不再重要。每个预处理标记都会转换为一个标记。(2.7)。对生成的标记进行句法和语义分析,并将其翻译为翻译单元。
\n
我认为所有这些都清楚地表明有两种语法,一种是词法的——也就是说,它从一系列字素(字符)中产生一个词素(标记)——另一种是句法——也就是说,它产生一个来自词位(标记)序列的抽象语法树。在这两种情况下(除了一个小例外,我将在一分钟内讨论),空白都不会被认为是阻止两个词素相互碰撞的东西,如果词法语法允许的话。(参见2.5(3)中的算法。)
\nC++语法上不太漂亮,所以几乎总是有例外。其中之一,继承自C,是以下之间的区别:
#define A(X)(X)\nRun Code Online (Sandbox Code Playgroud)\n和
\n#define A (X)(X)\nRun Code Online (Sandbox Code Playgroud)\n预处理指令有自己的解析规则,定义如下:
\n\n\nlparen :
\n
\n\xc2\xa0\xc2\xa0a(字符前面没有紧接着空格
我想说,这是证明规则的例外[注1]。事实上,有必要说它(前面没有空格,这表明(在句法规则中标记的正常使用并没有说明它的空白空间上下文。
因此,套用雷·卡明斯(Ray Cummings)(而不是有时声称的阿尔伯特·爱因斯坦)的话说,“时间和空白是将一个标记与另一个标记分开的全部。” [笔记2]
\n[注 1] 根据西塞罗,我在这里使用该短语的原始法律含义。
\n[笔记2]:
\n\n\n“时间,”乔治说,“为什么我可以给你时间的定义。它阻止一切同时发生。”
\n一小群人周围爆发出阵阵笑声。
\n“确实如此,”化学家同意道。“而且,先生们,这并不像听起来那么有趣。事实上,这确实是一个不错的科学定义。时间和空间是将一个事件与另一个事件分开\xe2\x80\xa6
\n
——摘自《掌控时间的人》,雷·卡明斯着,1929 年,Ace Books。请参阅Google 图书中的第一页
\n