C 中的预处理器命令算作令牌吗?

问题描述 投票:0回答:1

我正在阅读有关令牌的内容并计算程序中令牌的数量。

之前我在某处读到预处理器命令不计为令牌。 但是当我在 Geeksforgeeks 上读到有关令牌时,它在“特殊符号”部分中给出:

预处理器(#):预处理器是编译器自动使用的宏处理器,用于在实际编译之前转换程序。

所以我很困惑,在程序中,如果我们写

#define
,它会是一个令牌吗?

例如:

#include<stdio.h> 
#define max 100 
int main() 
{ 
    printf("max is %d", max); 
    return 0; 
} 

这个例子中有多少个代币?

c c-preprocessor token
1个回答
8
投票

链接的文章充满了基本错误,不应依赖。

解析 C 或 C++ 的过程被定义为一系列转换:1

  1. 反斜杠换行符不被任何内容替换——甚至连空格也没有。
  2. 注释已被删除并替换为单个空格。
  3. 幸存的文本被转换为一系列预处理标记。这些比语言本身使用的标记不太具体:例如,关键字
    if
    是语言本身的 IF 标记,但只是预处理器的 IDENT 标记。
  4. 执行预处理指令并扩展宏。
  5. 每个预处理标记都会转换为一个标记。
  6. 标记流被解析为抽象语法树,编译器的其余部分从那里获取它。

您的示例程序

#include<stdio.h> 
#define max 100 
int main() 
{ 
    printf("max is %d", max); 
    return 0; 
}

在转换 3 之后,将成为这一系列 23 个预处理标记:

PUNCT:# IDENT:include INCLUDE-ARG:<stdio.h>
PUNCT:# IDENT:define IDENT:max PP-NUMBER:100
IDENT:int IDENT:main PUNCT:( PUNCT:)
PUNCT:{
IDENT:printf PUNCT:( STRING:"max is %d" PUNCT:, IDENT:max PUNCT:) PUNCT:;
IDENT:return PP-NUMBER:0 PUNCT:;
PUNCT:}

现阶段指令仍然存在。请注意,

#include
#define
分别是 two 标记:
#
和指令名称是分开的。有些人喜欢编写复杂的
#if
嵌套,井号标记全部位于第 1 列,但指令名称缩进。

但是,在转换 5 之后,指令消失了,我们有了这一系列 16+n 个令牌:

[ ... some large volume of tokens produced from the contents of stdio.h ... ]
INT IDENT:main LPAREN RPAREN
LBRACE
IDENT:printf LPAREN STRING:"max is %d" COMMA DECIMAL-INTEGER:100 RPAREN SEMICOLON
RETURN OCTAL-INTEGER:0 SEMICOLON
RBRACE

其中“n”表示来自 stdio.h 的令牌数量。

预处理指令(

#include
#define
#if
等)are始终从令牌流中删除,并且可能用其他内容替换,因此在转换 6 之后,您永远不会拥有直接从文本产生的令牌一条指令线。但您通常会拥有由每个指令的 effects 产生的标记,例如
stdio.h
的内容,以及
DECIMAL-INTEGER:100
替换
IDENT:max

最后,C 和 C++ 做这一系列操作几乎,但又不完全一样,而且规范在形式上是独立的。您通常可以依靠预处理操作在两种语言中表现相同,只要您只使用预处理器做简单的事情,无论如何,这是当今的最佳实践。


1 有时你会看到人们谈论翻译阶段,这是 C 和 C++ 标准正式描述这一系列操作的方式。我的列表不是翻译阶段的列表;它包含一些按标准分组为单个阶段的单独要点,并省略了与本讨论无关的几个步骤。

© www.soinside.com 2019 - 2024. All rights reserved.