下一步 上一步 目录

6. 入门

根据 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 驱动程序。驱动程序必须理解我们新语言的存在。这个文件巧妙地完成了这项工作。我们语言的扩展名等详细信息就在这里。您可以根据自己的喜好指定它们。

现在是最重要的事情。没有人期望您从头开始创建所有这些文件。最好的方法是从任何现有目录复制这些文件并进行相关更改。这些更改可能包括语言名称、我们使用的文件、我们选择的扩展名等的一些修改。

所有提供的信息均来自我的观察,有时上述细节可能存在差异。

6.1 回调例程

如前所述,我们将使用 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_traditional
dwarfout.c 文件所需的变量

error_mark_node
一个用于定义错误的树节点。它表示部分树。当语法分析阶段发生一些错误时,它非常有帮助。

integer_type_node, char_type_node, void_type_node 
从名称中清除。

integer_zero_node, integer_one_node 
类型为 integer_type_node 的常量,值分别为 0 和 1。


下一步 上一步 目录