【发布时间】:2012-06-17 19:12:08
【问题描述】:
Walter Bright 关于 C++ 编译的文章谈到了这两个短语
“转换为预处理令牌。”
什么是初始令牌?预处理令牌是什么样的?
“将预处理标记转换为 C++ 标记” 这个 C++ Token 是什么,为什么一开始没有转换成它?
【问题讨论】:
标签: c++ parsing compiler-construction compilation lexer
Walter Bright 关于 C++ 编译的文章谈到了这两个短语
“转换为预处理令牌。”
什么是初始令牌?预处理令牌是什么样的?
“将预处理标记转换为 C++ 标记” 这个 C++ Token 是什么,为什么一开始没有转换成它?
【问题讨论】:
标签: c++ parsing compiler-construction compilation lexer
预处理标记是预处理器语法的一个元素。来自 C++ 标准中的 [lex.pptoken]:
预处理令牌:
- 标题名称
- 标识符
- pp 号
- 字面量
- 用户定义的字符文字
- 字符串字面量
- 用户定义的字符串文字
- 预处理操作或穿孔
- 不能是上述之一的每个非空白字符
...
预处理标记是翻译阶段 3 到 6 中语言的最小词汇元素。
因此“转换为预处理标记”是对翻译单元进行词法分析并识别单个标记的过程。
C++ 标记(实际上只是“标记”)在 [lex.token] 中列出:
令牌:
- 标识符
- 关键字
- 文字
- 操作员
- 标点符号
这些仅在所有其他翻译阶段发生后才存在(宏扩展等)。
关于整个过程的更多信息,我建议阅读C++标准中的[lex.phases]。
【讨论】:
更简单的解释。
而且,您可能知道,许多编译器都有词法分析过程,其中源代码被拆分为标记。
本源代码:
void main()
{
int x = -3 - -5;
printf("Hello World");
} // void main()
变成类似这样的东西:
+--------------+------------------+ |代币 |正文 | +--------------+------------------+ |无效 | “空虚” | +--------------+------------------+ |标识符 | “主要” | +--------------+------------------+ |左卷曲 | "{" | +--------------+------------------+ |标识符 | “整数” | +--------------+------------------+ |标识符 | "x" | +--------------+------------------+ |分配 | “=” | +--------------+------------------+ |减号 | "-" | +--------------+------------------+ |整数 | "3" | +--------------+------------------+ |减号 | "-" | +--------------+------------------+ |减号 | "-" | +--------------+------------------+ |整数 | "5" | +--------------+------------------+ |分号 | “;” | +--------------+------------------+ |标识符 | “打印” | +--------------+------------------+ |左派 | "(" | +--------------+------------------+ |字符串 | “你好世界” | +--------------+------------------+ |正确的 | ")" | +--------------+------------------+ |分号 | “;” | +--------------+------------------+ |右卷曲 | "}" | +--------------+------------------+ |评论 | "// 无效 main()" | +--------------+------------------+每一段称为“令牌”的文本都有其含义。
有时,在编译过程的其他部分,标记可能会被其他标记替换:
+--------------+------------------+ |代币 |正文 | +--------------+------------------+ |无效 | “空虚” | +--------------+------------------+ |函数dec | “主要” | +--------------+------------------+ |左卷曲 | "{" | +--------------+------------------+ |类型 | “整数” | +--------------+------------------+ |变量dec | "x" | +--------------+------------------+ |分配 | “=” | +--------------+------------------+ |负| "-" | +--------------+------------------+ |整数 | "3" | +--------------+------------------+ |减 | "-" | +--------------+------------------+ |负| "-" | +--------------+------------------+ |整数 | "5" | +--------------+------------------+ |分号 | “;” | +--------------+------------------+ |函数调用 | “打印” | +--------------+------------------+ |左派 | "(" | +--------------+------------------+ |字符串 | “你好世界” | +--------------+------------------+ |正确的 | ")" | +--------------+------------------+ |分号 | “;” | +--------------+------------------+ |右卷曲 | "}" | +--------------+------------------+ |评论 | "// 无效 main()" | +--------------+------------------+从“减号”标记到“负号标记”和“减法标记”的转换是“预处理标记”到“最终标记”的一个很好的例子。
这是一个非常概念性的解释。您可能希望阅读有关您的特定编译器文档的更详细的技术信息。
干杯
【讨论】: