解析器和预处理器[编辑源代码]初始化后,函数 do_compile() 调用函数 compile_file()。此函数调用 parse_file() 前端语言钩子,该钩子设置为 C 语言的函数 c_common_parse_file()。后一个函数调用函数 finish_options(),该函数初始化预处理器并处理 -D、-U 和 -A 命令行选项(分别等效于 #define、#undef 和 #assert)。C 预处理器处理预处理器指令,例如源代码中的 #define、#include。 解析器[编辑源代码]解析器是在文件 c_parser.c 中手动实现的。与早期版本的 GCC 相比,新解析器生成 较低级别的 AST。循环有特殊的树代码, 例如FOR_STMT表示 for() 循环。在此版本中, 循环表示为条件语句和 gotos,即 代码树 COND_EXPR、LABEL_EXPR 和 GOTO_EXPR。这可能 意味着不可能将 AST 表示提升到原始表示 源代码。 预处理器[编辑源代码]预处理器作为库实现。C 语言词法分析器函数 c_lex() 调用处理预处理器关键字的 libcpp 函数 cpp_get_token()。预处理器的状态由变量 cpp_reader *parse_in 定义。类型 struct cpp_reader 包含最重要的正在处理的文本缓冲区列表。每个缓冲区对应一个源文件(.c 或 .h)。函数 cpp_get_token() 为合法的预处理器关键字调用适当的函数。例如,当遇到 #include 时,会调用函数 do_include_common()。它分配一个新的缓冲区,并将其放在缓冲区堆栈的顶部,使其成为当前缓冲区。编译新文件时,缓冲区会从堆栈中弹出,并继续编译旧文件。 每当使用 #define 关键字定义新宏时,都会调用函数 do_define()。
|
说点什么...