根据 GNU 的正式哲学,GCC 中存在的每种语言(即,对于具有单独前端的语言)都应该有自己的子目录。因此,GCC 对我们的首要期望是有一个单独的目录。让我们在 srcdir/gcc 中创建一个新的子目录,以我们的语言名称命名(例如“demo”)。
如前所述,gcc 期望有许多文件和函数。在我们的目录中也应该存在一些文件。首先应该存在的是 make 文件。它分为两个文件,Make-lang.in 和 Makefile.in。两者都是 gcc 的主 make 文件的一部分。
Make-lang.in 实际上包含在 gcc 的主 make 文件中,并从那里(objdir/gcc)调用语言目录中的 make。因此,文件名应提供完整路径名。不要尝试使用相对路径名。该文件提供了有关我们语言源文件的信息。因此,我们应该在这里指定我们的语言所需的文件。
Makefile.in 用于在语言目录中创建 make 文件。它包含在语言目录中。
gcc 期望的第三个文件是 config-lang.in。它被文件 srcdir/gcc/configure(一个 shell 脚本)使用。
gcc 期望的第四个文件是 lang-specs.h。该文件有助于修改 gcc 驱动程序。驱动程序必须理解我们新语言的存在。这个文件巧妙地完成了这项工作。我们语言的扩展名等详细信息就在这里。您可以根据自己的喜好指定它们。
现在是最重要的事情。没有人期望您从头开始创建所有这些文件。最好的方法是从任何现有目录复制这些文件并进行相关更改。这些更改可能包括语言名称、我们使用的文件、我们选择的扩展名等的一些修改。
所有提供的信息均来自我的观察,有时上述细节可能存在差异。
如前所述,我们将使用 gcc 的主要部分来编译我们的语言。因此,我们有责任定义后端使用的一些函数和变量。其中大多数对我们没有直接帮助。但后端期望它,所以我们应该提供它。
与上述情况一样,最好从一些现有的前端复制。但让我们对每个函数有一个大致的了解。如果您觉得本节很枯燥,您可以跳过本节,但不要跳过在程序中包含这些例程。
type_for_size(unsigned precision, int unsignedp)它返回一个整数类型的树,其位数由参数 precision 给出。如果 unsignedp 非零,则它是无符号类型,否则它是有符号类型。
init_parse(char *filename)它初始化解析。
finish_parse()它执行解析清理。
lang_init_options()特定于语言的初始化选项处理。
lang_print_xnode(FILE *file,tree t,int i)gcc 需要。不知道它具体做什么。
type_for_mode(enum machine_mode mode,int unsignedp)它返回由我们给定的所需模式的树类型。mode 表示机器数据类型,如整数。unsignedp 像往常一样用于获取无符号类型,否则返回有符号类型。
unsigned_type(tree type_node)返回 type_node 的无符号版本。
signed_type(tree type_node)返回 type_node 的有符号版本。
signed_or_unsigned_type(int unsignedp, tree type)根据 unsignedp 返回有符号或无符号树节点。
global_bindings_p()如果我们当前处于全局绑定级别,则返回非零值。
getdecls()返回当前级别中的声明列表,但顺序相反。
kept_level_p()当必须为当前符号表级别创建“BLOCK”时,它为非零值。
pushlevel(int ignore)进入新的绑定级别。在另一个绑定级别中之前使用的符号名称在进入新级别时被覆盖。
poplevel(int keep, int reverse, int functionbody)删除由 pushlevel 创建的新级别。符号表状态恢复(即 pushlevel 之前存在的状态)。
insert_block(tree block)在当前绑定级别的子块列表末尾插入块。
set_block(tree block)设置当前作用域的块。
pushdecl(tree decl)将声明 decl 插入符号表并返回树。
init_decl_processing()初始化符号表。它设置全局变量并将其他变量插入符号表。
lang_decode_option(int a, char **p)它解码 GCC 无法解码的所有特定于语言的选项。如果成功,则返回 1,否则返回 0。
lang_init()执行前端所需的所有初始化步骤。它包括设置某些全局变量。
lang_finish()执行所有前端特定的清理。
lang_identify()返回一个简短的字符串,用于向调试器标识语言。
maybe_build_cleanup(tree decl)创建一个树节点,表示自动清理操作。
incomplete_type_error(tree value, tree type)打印有关不完整类型无效使用的错误消息。
truthvalue_conversion(tree expr)它返回相同的 expr,但类型表示真值。
mark_addressable(tree expr)将 expr 标记为需要在存储中寻址的构造。
print_lang_statics()打印任何特定于语言的编译统计信息。
copy_lang_decl(tree node)如果 DECL_LANG_SPECIFIC 为非零值,则复制声明。
print_lang_decl(FILE *file, tree node, int indent)将节点声明输出到文件 file,缩进深度为 indent。
print_lang_type(FILE *file, tree node, int indent)将节点类型输出到文件 file,缩进深度为 indent。
print_lang_identifier(FILE *file, tree node, int indent)将节点标识符输出到文件 file,缩进深度为 indent。
int_lex()执行语言相关的词法分析器所需的任何初始化步骤。
set_yydebug()为解析器设置一些调试标志。
yyerror(char *s)用于打印解析错误消息的例程。
language_string一个字符字符串,用于保存我们的语言名称。例如,demo。
flag_traditionaldwarfout.c 文件所需的变量
error_mark_node一个用于定义错误的树节点。它表示部分树。当语法分析阶段发生一些错误时,它非常有帮助。
integer_type_node, char_type_node, void_type_node从名称中清除。
integer_zero_node, integer_one_node类型为 integer_type_node 的常量,值分别为 0 和 1。