什么是编译过程中的词法和句法分析。预处理是否发生在词法和句法分析之后?
5 回答
考虑这段代码:
int a = 10;
if (a < 4)
{
printf("%d", a);
}
在词法分析阶段:您识别每个单词/标记并为其分配含义。在上面的代码中,您首先确定i后跟n后跟t,然后一个空格是单词int,它是一个语言关键字;1后跟0,空格是数字10,依此类推。
在句法分析阶段:您验证代码是否遵循语言语法(语法规则)。例如,您检查运算符的 LHS 上是否只有一个变量(考虑 C 语言),每条语句是否以;结尾。, if后跟一个条件/布尔语句等。
就像其他人提到的那样,通常预处理发生在词法分析或句法分析之前。
词法分析发生在句法分析之前。这是合乎逻辑的,因为当需要调用宏时,必须首先识别标识符的边界。这是通过词法分析完成的。在句法分析开始之后。请注意,编译器通常不会在开始句法分析之前生成完整的预处理源。他们读取源代码,一次选择一个词法,如果需要进行预处理,并将结果提供给句法分析。
在一种情况下,词法分析发生两次。这是粘贴缓冲。看代码:
#define En(x) Abcd ## x ## x
enum En(5)
{
a, b = 20, c, d
};
此代码使用名称定义枚举Abcd55
。在##
宏扩展期间处理这些数据时,会将数据放入内部缓冲区。之后,这个缓冲区就像一个小的#include 一样被扫描。在扫描期间,编译器会将缓冲区的内容分解为词法。可能会发生扫描词法的边界与放置在缓冲区中的原始词法的边界不匹配的情况。在上面的示例中,3 个词法被放入缓冲区,但只有一个被检索。
预处理发生在词法分析 iirc 注释被过滤掉之前,#define,... 之后,编译器使用扫描仪/词法分析器生成标记(词法分析)。之后编译器生成分析树,用于语法分析
也有例外,但通常是这样爆发的:
- 预处理 - 将程序文本转换为程序文本
- 词法分析 - 将程序文本转换为“标记”,它们本质上是带有属性的小整数
- 句法分析 - 将程序文本转换为抽象句法
“抽象语法”的定义可能会有所不同。在一次性编译器中,抽象语法相当于目标代码。但是这些天,它通常是一棵树或 DAG,它在逻辑上代表了程序的结构。
当我们谈论 C 编程语言时,我们应该注意该语言有一个 ISO (ANSI) 标准。这是 C99 (ISO/IEC 9899:1999) 的最新公开草案:www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf
有一节“5.1.1.2 翻译阶段”说明了如何解析 C 程序。有几个阶段:
...多字节、三元组和反斜杠处理的一些步骤...
3)。源文件被分解为预处理标记和空白字符序列(包括注释)。
这是预处理的词法分析。只有预处理器指令、标点符号、字符串常量、标识符、注释在这里被使用。
4)。执行预处理指令,扩展宏调用
这本身就是预处理。此阶段还将包含来自的文件#include
,然后它将删除预处理指令(如#define
or#ifdef
和其他)
...处理字符串文字...
7)。分隔标记的空白字符不再重要。每个预处理令牌都被转换为一个令牌。生成的标记在句法和语义上进行分析,并作为翻译单元进行翻译。
转换为token意味着语言关键字检测和常量检测。这是最终词法分析的步骤;句法和语义分析。
所以,你的问题是:
预处理是否发生在词法和句法分析之后?
做预处理需要一些词法分析,所以顺序是:lexical_for_preprocessor,preprocessing,true_lexical,other_analysis。
PS:Real C 编译器的组织方式可能略有不同,但它的行为方式必须与标准编写的方式相同。