1 #include "token_define.h" 2 //这个文件是用来处理句型的,对于算术表达式都是放在前面的那个头文件中来处理 3 typedef struct _handle_tree_node//句型语法树的节点 4 { 5 union 6 { 7 int handle_type;//1代表基本句型,2代表代码块, 8 enum keywords_type keyword;//代表关键字的类型 9 } 10 union//产生体 11 { 12 phrase_tree_node* orginal_phrase_node;//代表单个基本句型 13 struct 14 { 15 struct _handle_tree_node* for_initiate; 16 struct _handle_tree_node* for_judge; 17 struct _handle_tree_node* for_modify; 18 struct _handle_tree_node* for_codeblock; 19 }for_code;//代表for句型 20 struct 21 { 22 struct _handle_tree_node* while_judge; 23 struct _handle_tree_node* while_codeblock; 24 }while_code;//代表while句型 25 struct 26 { 27 struct _handle_tree_node* branch_judge; 28 struct _handle_tree_node* if_code; 29 struct _handle_tree_node* else_code; 30 }branch_code;//代表if else句型 31 }; 32 }handle_tree_node; 33 //上面的是动作执行代码,根据我们对文法的定义,还有类型定义部分,函数定义部分,变量声明部分 34 //其中函数定义部分里面比较复杂,会有递归,我们放到最后去考虑 35 //下面先谈最简单的变量声明部分,变量声明部分中最重要的是声明头部,因为声明头经常会被使用。 36 //注意这里的声明头部与c语言不一样的地方就是*是跟着声明头的,而不是跟着变量名 37 //对于声明头的结构,我们在符号表中已经定义过了 38 //这里我们再次定义一下 39 //对于变量的结构,在符号表中也已经定义过了 40 //typedef struct _var_hash_node 41 //{ 42 // pbasic_type_pattern current; 43 // char* var_name; 44 // int pointer_layer;//代表指针的级数,我们限制为8级,即只占一个字节,其他三个字节以后再使用,先留着 45 // parray_description array_layer;//这里是数组描述,以链表串起多级数组 46 // ptype_avl_tree current_type;//代表分量的类型 47 //}var_hash_node,*pvar_hash_node; 48 //变量声明的产生式 49 //list_name: new_name|list_name[unsign_constant_int] 对应数组的情形 50 //data_type_basic_body: int |char|float|double|long|unsigned 基础类型体 51 //data_type_basic_pointer: data_type_basic *|data_type_basic_pointer * 基础类型的指针 52 //data_type_basic:data_type_basic_body|data_type_basic_pointer 基础类型(包括指针) 53 //data_type_struct:data_type_struct_body|data_type_struct_pointer 结构体类型声明头部 54 //data_type_union:data_type_union_body|data_type_union_pointer 联合类型声明头部 55 //data_type_head:data_type_basic|data_type_struct|data_type_union 所有的类型头部 56 //data_var_decl: data_type_head list_name; 所有的显示变量声明 57 //注意我们这里只允许一次生命一个变量名 58 //实际处理的时候我们并不是按照前面的产生体严格执行的,我们在遇到变量声明的时候,首先查看第一个name 59 //如果不是struct和union,则对这个名字进行查找类型avl,如果存在,则获得这个类型,然后再处理指针 60 //然后是变量名字,然后是数组描述,这些工作很简单,我们没有必要去放到lr文法分析中去,那样只会增加复杂度 61 //如果是struct和union,则获得下一个token,对这个token执行上述操作,都是一样的 62 //所以我们碰到变量声明的时候,直接处理然后把data_var_decl放到句型栈中,让文法分析来处理 63 // 64 // 65 // 66 //现在来处理类型定义,由于类型定义也是嵌套的,所以我们也需要使用一个栈来处理类型定义,同时为当前定义 67 //构建一个语法分析树来处理,但是类型定义除了嵌套定义外,还存在自引用定义,为此,我们每次处理符合类型的时候 68 //首先记录各个分量的变量名字和类型名字(这里要求各个分量的类型名都已经被处理了)。当得到所有的分量之后 69 //另外分配空间来构造产生体链表,并把类型名字通过查找avl来获得相应的avl节点,并把类型名修改为avl节点的指针 70 //注意这里还有自引用,因此我们在插入avl的时候,只是先把产生体链表构造为空,插入之后再去填充产生体链表。 71 //注意在处理类型声明的时候,我们还要为代码块维护一个类型链表,按照拓扑序来排列 72 //因此在每处理完一个复合类型之后就插入到当前的类型链表中 73 //我们对于每一个代码块都有一个类型链表,而每个函数又是一个代码块,因此会有嵌套的处理 74 //为此我们又需要维护一个栈,栈中存放的是当前的类型链表。 75 //我们为每一个函数代码块维护一个类型链表、一个变量链表、一个代码块语法树的头、一个参数链表 76 //每当调用一个函数的时候,我们就把类型链表、变量链表、参数链表挂载到符号表里面,然后再用后序遍历语法树 77 //来执行代码。 78 //在调用返回之后,按照插入序的逆序来删除所有插入到符号表里面的项 79 //至此一个代码块里面的类型链表已经构建完成了 80 //由于这里只是构建链表,所以所有的类型都是靠名称来索引的,而不是靠指针来索引 81 int code_scope;//这个用来表示当前的代码域 82 struct _composition_list* current_block_pattern_list_rear;//这个代表了当前代码块的类型链表的末尾 83 struct var_decl_link//这个是代码块的变量链表 84 { 85 struct _var_hash_node* current_var_node; 86 struct var_decl_link* next; 87 }; 88 struct type_decl_link//这个是代码块的类型链表 89 { 90 struct _type_description_ current_type_node; 91 struct type_decl_link* next; 92 }; 93 struct function_description 94 { 95 struct var_decl_link* current_var_link; 96 struct type_decl_link* current_type_link; 97 struct _handle_tree_node* current_action_link;//代表动作链表 98 }; 99 100 int check_constant_type(char* in_constant)//1代表小数,0代表整数 101 { 102 while(*(in_constant)!='