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

时间:2018-09-23 17:03:49

标签: c c-preprocessor token

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

以前,我在某处读到预处理器命令不算作令牌。 但是,当我在Geeksforgeeks上阅读有关令牌的信息时,它会在“特殊符号”部分中给出:

  

预处理器(#):预处理器是一个宏处理器,编译器会在自动编译之前自动使用它来转换程序。

所以我很困惑,在程序中,如果我们写#define是令牌吗?

例如:

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

此示例中有多少个令牌??

1 个答案:

答案 0 :(得分:6)

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

解析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分别是两个令牌:#和指令名称是分开的。有些人喜欢在第1列中写上所有带有井号的复杂#if嵌套,但指令名称缩进。

在转换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 DECIMAL-INTEGER:0 SEMICOLON
RBRACE

然而'n'却是来自stdio.h的许多令牌。

预处理指令(#include#define#if等) 总是从令牌流中删除,并可能被其他内容替换,因此您转换6之后永远不会有直接来自指令行文本的标记。但是,通常会有每个指令的效果产生的标记,例如stdio.h的内容,并用DECIMAL-INTEGER:100代替IDENT:max

最后,C和C ++几乎几乎执行了这一系列操作,但并不完全相同,并且规范在形式上是独立的。只要您仅使用预处理器执行简单的操作,通常就可以依靠预处理操作来在两种语言中表现相同,这是当今的最佳做法。


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