实现 C #include 指令的内部处理
Implement the internal processing for C #include directives
我需要以最简洁的方式思考为 C 编译器实现 #include
指令的功能。
我只知道如何实现处理的外部部分:将行首的 '#'
字符获取到 运行 预处理器专用循环,我也知道如何收集"include"
字符串和 <>
或 ""
.
之间的字符串
我不知道的是实现内部处理的最佳方式运行 #include 指令的实际效果:扩展库头文件的完整路径(使用<>
) 但不适用于使用 ""
的那些(假设它们在当前目录中可能更清晰、更灵活,因为这也允许正确包含具有完整路径的源文件)。
我认为我需要执行的任务是:
作为命令行参数传递给编译器的主C文件应该像#include "mainfile.c"
指令一样处理,以统一的方式开始编译。
扩展包含引号的文件的路径(""
,单引号 ''
是否至少对某些编译器有效?)
将文件放在文件列表中,同时指出我们在哪一行和哪个文件中找到了#include
指令
在预处理器阶段,看是否是#include
指令,尝试无条件打开指定文件,尝试从头开始正确获取所有文件。如果一个文件不存在,不要在预处理器阶段发出错误信号,只有当我们将它们标记为可用时,当我们决定是否应该包含它们时 #ifdef
或 #elif
,同时尝试翻译实际的 C 代码。
完成代码中所有 #includes
的处理后,现在处理其余的预处理器代码以及要包含的全套潜在文件。
我认为使用一堆文件会有用,但只有在完成预处理器阶段之后,并且当我们已经翻译了整个代码并添加文件时(将文件索引推送到源文件堆栈 #include
并在源文件末尾弹出文件索引。)
我认为处理代码最简单的方法是检查 #include
指向的所有文件,列出它们,然后仅标记为可用,我将实际包含并完全处理的文件,满足 #ifdef
或 #elif
条件的文件,但为此我需要查看整个源文件集中包含哪些文件。
您通常会在阅读时处理所有预处理器指令。因此,当您看到 #include
时,您会获取文件名、搜索包含路径、打开文件并开始处理它——无需延迟。到达包含文件的末尾后,您将继续处理原始文件。
与 #if
类似,您阅读条件并确定它是真还是假。如果为 false,则开始跳过输入,忽略它,直到找到匹配的 #else
或 #endif
。所以如果里面有 #include
,你就跳过它。
似乎需要解析预处理器代码,以便正确了解我们是否已经执行过定义内容或包含文件等任务,以避免再次这样做,因此当我们找到预处理器时确实需要对其进行解析按照我们找到它的顺序排列指令。
实际的 C 代码可能可以通过多次传递以任何顺序进行分析,主要是对全局声明的东西进行分析,以便能够在声明它们之前使用它们,但是需要处理预处理器才能能够有选择地定义和包含事物。
我需要以最简洁的方式思考为 C 编译器实现 #include
指令的功能。
我只知道如何实现处理的外部部分:将行首的 '#'
字符获取到 运行 预处理器专用循环,我也知道如何收集"include"
字符串和 <>
或 ""
.
我不知道的是实现内部处理的最佳方式运行 #include 指令的实际效果:扩展库头文件的完整路径(使用<>
) 但不适用于使用 ""
的那些(假设它们在当前目录中可能更清晰、更灵活,因为这也允许正确包含具有完整路径的源文件)。
我认为我需要执行的任务是:
作为命令行参数传递给编译器的主C文件应该像
#include "mainfile.c"
指令一样处理,以统一的方式开始编译。扩展包含引号的文件的路径(
""
,单引号''
是否至少对某些编译器有效?)将文件放在文件列表中,同时指出我们在哪一行和哪个文件中找到了
#include
指令在预处理器阶段,看是否是
#include
指令,尝试无条件打开指定文件,尝试从头开始正确获取所有文件。如果一个文件不存在,不要在预处理器阶段发出错误信号,只有当我们将它们标记为可用时,当我们决定是否应该包含它们时#ifdef
或#elif
,同时尝试翻译实际的 C 代码。完成代码中所有
#includes
的处理后,现在处理其余的预处理器代码以及要包含的全套潜在文件。
我认为使用一堆文件会有用,但只有在完成预处理器阶段之后,并且当我们已经翻译了整个代码并添加文件时(将文件索引推送到源文件堆栈 #include
并在源文件末尾弹出文件索引。)
我认为处理代码最简单的方法是检查 #include
指向的所有文件,列出它们,然后仅标记为可用,我将实际包含并完全处理的文件,满足 #ifdef
或 #elif
条件的文件,但为此我需要查看整个源文件集中包含哪些文件。
您通常会在阅读时处理所有预处理器指令。因此,当您看到 #include
时,您会获取文件名、搜索包含路径、打开文件并开始处理它——无需延迟。到达包含文件的末尾后,您将继续处理原始文件。
与 #if
类似,您阅读条件并确定它是真还是假。如果为 false,则开始跳过输入,忽略它,直到找到匹配的 #else
或 #endif
。所以如果里面有 #include
,你就跳过它。
似乎需要解析预处理器代码,以便正确了解我们是否已经执行过定义内容或包含文件等任务,以避免再次这样做,因此当我们找到预处理器时确实需要对其进行解析按照我们找到它的顺序排列指令。
实际的 C 代码可能可以通过多次传递以任何顺序进行分析,主要是对全局声明的东西进行分析,以便能够在声明它们之前使用它们,但是需要处理预处理器才能能够有选择地定义和包含事物。