为什么预处理器区分数字和字符标记?

9

根据语言规范,词法元素的定义如下:

token:
    keyword
    identifier

    constant

    string-literal
    operator
    punctuator

preprocessing-token:
    header-name
    identifier

    pp-number
    character-constant

    string-literal
    operator
    punctuator

    each non-white-space character that cannot be one of the above

为什么在预处理标记级别上数字和字符之间有区分,而在标记级别上只有常量?我看不出这种区分的好处。
1个回答

5
C语言文法中非终结符的名称并不是规范的;它们只是为了描述而存在。重要的是行为被正确地描述。文法本身不能充分描述语言;需要与文本一起阅读,这进一步限制了良好形式程序的范围。
预处理器标记与程序标记之间不存在一对一的关系。它们有重叠:预处理器中的identifier可能是关键字,也可能是各种可定义的符号类型(包括一些常量和typedef名称)。pp-number可能是整数或浮点常量,但也可能无效。词法产生式并不是全部互斥的,将词法类别实际应用于程序子字符串需要在标准文本中描述的过程,而不是在正式文法中。
字符常量直接从预处理器传递到程序语法中而没有修改(尽管它们随后被纳入constant类别)。如果有一个关于预处理器数字的单个评论(例如,如果它们幸存下来,则必须转换为真实数字常量文字),那么有该类别的充分理由。
此外,将character-constant包含在pp-number的定义中会增加什么?您仍然需要两个产生式才能描述语言。

@fredoverflow:一些例子:3q,3.14159U,019,0y21和我永远喜爱的0x7E + 2(与0x7F + 1不同,它是一个单独的标记)。 - rici
@FredOverflow:另一个在第7个翻译阶段无法分配值(正如标准所述)的pp-number是192.168.0.1。然而,这是一个单一的预处理器标记(如果您需要使用##运算符,则会有所不同)。 - rici
事实上,C++标准表示:“程序片段1Ex被解析为预处理数字标记(不是有效的浮点或整数字面量标记)”...那么这样的预处理器标记会发生什么呢?它会导致编译器错误吗,因为它无法转换为标记?那么,拥有预处理器数字标记作为数字标记的严格超集的意义是什么? - fredoverflow
@FredOverflow:无论是预处理标记还是程序的有效性(目前不确定是未定义还是需要诊断),要么在预处理后成为有效标记,要么就是程序无效。它们既不能被分成几个标记(0x7E+2 是无效的,不会被重新解析为 0x7E + 2),也不能被连接起来(给定 #define MINUS -MINUS-x 是两个一元减运算符,而不是前置自减)。 - mafso
2
@mafso:这是一个约束违规(6.4/2“每个预处理标记转换为标记时,应具有关键字、标识符、常量、字符串文字或标点符号的词法形式。”),因此需要进行诊断(5.1.1.3)。虽然可能会将pp标记字符串化或忽略(#define IGNORE(x) / IGNORE($=>)),但也有可能永远不会将其转换为标记。 - rici
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接