接上篇怎么用C语言写语法分析,继续介绍剩下的几个数据结构。
语法分析涉及的数据结构,如下图,就这么几个。前一篇类型type、变量var、节点node、运算符operator、作用域scope,接着说下标号label、块block、函数function。
标号,label,在其他语言里用的不多,主要是在C和C++中用于goto语句。
goto语句的目的地址是个标号,可以往前跳,也可以往后跳,特别的灵活。
一般情况下,除了错误处理代码之外,不建议使用goto。
标号
如上图,标号的数据结构还是很简单的。
与变量类似,它也是位于某个作用域内(函数或者语句块)。当在goto语句中使用标号时,为它生成一个node节点。
type类型自然是标号。
scf_lex_word_t* w表示它的单词,单词里存有标号的名字字符串。
scf_node_t* node,为它标记的目的代码的第一个节点。
例如,
if (!p1) goto error1;
if (!p2) goto error2;
error2:
free(p1);
error1:
return -1;
error1中的node就指向return -1语句,error2中的node指向free语句。
块
块,它是需要直接挂在语法树上的,有scf_node_t类型的节点node。
它下属的语句,都添加在node成员的子节点数组里。
它下属的变量或函数,都添加在它的scope作用域里。
字符串name用于记录它的名字,w_start和w_end记录起始和结束的大括号。
int a; // 1
if (1) {
int a; // 2
for (;;) {
int a; // 3
}
以上代码里的3个a,分别处于3个块里。
使用的时候,首先查找当前块的作用域,然后查找上一级块,一级级的往上查找。所以for循环里使用的a,是注释为3的a,而不是注释为2的a。
如果在同一个块里声明2个a,就出现了数据的重复定义,这是常见的语法错误。在分析变量的定义时,可以查找当前作用域里是否有同名变量,有则报语法错误。
函数
函数的定义还是比较复杂点的,见上图。
它也是需要添加到语法树的,所以也有个scf_node_t node成员。
函数里的语句,也存在node的子节点列表里。
函数里的变量(局部变量),存在它的scope成员里。
它的前几项与块一样,函数也是一个复杂的块。
函数也可以是类的成员函数,它被挂在类类型的scope成员上,所以16行有个链表元素list。非成员函数,则挂在文件块或者全局块的scope上。
18行和20行,分别是返回值ret和形参列表argv。
返回值之所以用变量而不是类型,是因为类型只存储基本类型或类类型,而指针类型需要记录指针的级数,这个值是记录在变量里的。
argv列表,每一个都是scf_variable_t变量的指针,表示该参数的细节。
如果是运算符重载,op_type成员表示原来的运算符类型。
24行以后的内容,都是和中间代码生成、机器码生成有关的内容,不属于语法分析部分。
举报/反馈