ZZZ语言的语义分析,第一步,解析Specifier(上)
2013-06-06 22:47
302 查看
1 语义分析的任务
我们的任务是检查我们的程序语言ZZZ的语义错误以及为后续的中间代码生成创造便利条件。其中很重要的内容是有关类型的检查。
首先,我们就得知道每个变量的类型,
要进行语义分析,首先就要知道每个变量的类型。我们采取解析语法树的办法,把遇到的变量和它的类型存入符号表,之后每次遇
到一个变量,都查看符号表,看变量在其作用域内的声明或定义是否存在,其类型是什么,之后才能进一步判断语义是否正确。
2 解析Specifier
ZZZ的语言支持的类型包括基本类型(double,int,bool),数组,结构体和它们的指针,加上我们的模板类(Template,模板类
只支持结构体)。要得到每个变量的类型,就必须解析语法树的Specifier节点。
2.1 表示类型的数据结构
首先,定义类型的数据结构。我在参考的实验攻略的基础上定义的表示类型的结构体如下:
对上面的Type_的定义,有几点需要注意。
1) 其中kind表示这个类型是基本类型(basic),还是数组(array)还是结构体(structure),
它们分别对应联合体u的三个成员。
2 ) basic具体是什么,就用3个宏定义表示;
3) array是一个Type类型的链表,从头开始记录每一个维度的size,n维数组的前n-1个Type结点的kind都是array,最后一个结点的Type表示元素的类型。
4) 注意,kind_t.T表示的是当前类型就是泛型T,还没有具体类型。它只会出现在泛型结构体和泛型函数的参数,返回类型和局部变量中。此时
联合体u中没有对应的值;
5) isTempDec表示的是当前结构体是否为一个泛型结构体,当它为true时,此时它的kind一定为kind_t.structure(因为只有结构体类型有泛型,不要和kind.T混淆)。
该结构体成员依旧由FieldList structure链表连起来。只不过其成员有可能会有kind_t.T的类型。
2.2 解析Specifier
分析每个变量的类型,当然是根据语法树的结构,也就是对应的产生式进行解析。以下是Specifier的产生式:
产生式的左边的非终结符就是语法树的父结点,右边每个终结符或非终结符都是子结点。
通过遍历语法树,我们每次碰到一个Specifier结点,就以此为参数,调用Type parse_specifier(node,isTempDec)函数来解析,函数返回指就是一个Type_的指针,
指向的是一个已经创建好了的Type_结点。
解析函数中,isTempDec被当作参数是因为,TempDec是与Specifier同层的结点,产生式如下:(其中,终结符只有INT DOUBLE BOOL POINT T TEMPLATE ID)
读到这里,对于解析specifier的困难之处,读者乍一看可能看不出来.
其中的难点其实在structSpecifier:
这个产生式中的DefList我还没列出来,DefList,顾名思义,就是定义列表.这里表示的就是结构体的成员定义.
其产生式如下:
DefList是一个递归的定义,表示可以有无穷多个Def,Def就是一个或者一组同类型变量定义,举个例子:
这里int a和double d1,d2;分别是2个Def.这里的主要任务有:
1) 对DecList的解析,要递归的生成一个链表,表中所有的类型都相同(都为Specifier,递归调用parse_specifier(),返回值被当作参数传入parse_decList()).最后
返回FieldList的表头,连接到先前生成的成员链表的尾部;变量名 都必须不同;//查错点1
2 )在解析VarDec的时候,生成的可能是数组,需要递归地连接数组的每一个维度;
3 )结构体中变量不能初始化,(我们没有static机制),所以解析Dec的时候能够查VarDec ASSIGN Exp的语义错;//查错点2
4 )每次返回一个解析完Def后的成员链表,都必须检查这个表与之前的整个结构体成员链表是否有重名的变量,如果有就报错;//查错点3
2.3 有关结构体和指针和泛型的事宜
这部分内容将在下一个博客中讨论。
我们的任务是检查我们的程序语言ZZZ的语义错误以及为后续的中间代码生成创造便利条件。其中很重要的内容是有关类型的检查。
首先,我们就得知道每个变量的类型,
要进行语义分析,首先就要知道每个变量的类型。我们采取解析语法树的办法,把遇到的变量和它的类型存入符号表,之后每次遇
到一个变量,都查看符号表,看变量在其作用域内的声明或定义是否存在,其类型是什么,之后才能进一步判断语义是否正确。
2 解析Specifier
ZZZ的语言支持的类型包括基本类型(double,int,bool),数组,结构体和它们的指针,加上我们的模板类(Template,模板类
只支持结构体)。要得到每个变量的类型,就必须解析语法树的Specifier节点。
2.1 表示类型的数据结构
首先,定义类型的数据结构。我在参考的实验攻略的基础上定义的表示类型的结构体如下:
//basic's value #define BASIC_INT 0 #define BASIC_DOUBLE 1 #define BASIC_BOOL 2 enum kind_t{basic,array,structure,T};//T is a template mark,it will be replaced // by basic or structure later typedef struct Type_* Type; typedef struct FieldList_* FieldList; struct Type_{ char *name; enum kind_t kind; int isTempDec;//Is it a Template structure int isPoint;//Is it a point type union{ int basic; struct {Type elem;int size;} array; FieldList structure;//if (kind == structure && u.structure == NULL),it is the same with the struct who does have members }u; }; struct FieldList_{ char *name; Type type; FieldList next; };
对上面的Type_的定义,有几点需要注意。
1) 其中kind表示这个类型是基本类型(basic),还是数组(array)还是结构体(structure),
它们分别对应联合体u的三个成员。
2 ) basic具体是什么,就用3个宏定义表示;
3) array是一个Type类型的链表,从头开始记录每一个维度的size,n维数组的前n-1个Type结点的kind都是array,最后一个结点的Type表示元素的类型。
4) 注意,kind_t.T表示的是当前类型就是泛型T,还没有具体类型。它只会出现在泛型结构体和泛型函数的参数,返回类型和局部变量中。此时
联合体u中没有对应的值;
5) isTempDec表示的是当前结构体是否为一个泛型结构体,当它为true时,此时它的kind一定为kind_t.structure(因为只有结构体类型有泛型,不要和kind.T混淆)。
该结构体成员依旧由FieldList structure链表连起来。只不过其成员有可能会有kind_t.T的类型。
2.2 解析Specifier
分析每个变量的类型,当然是根据语法树的结构,也就是对应的产生式进行解析。以下是Specifier的产生式:
Specifier : TYPE | StructSpecifier Temp | StructSpecifier | POINT StructSpecifier Temp | POINT StructSpecifier | T | POINT T ; StructSpecifier : STRUCT OptTag LC DefList RC | STRUCT Tag ; OptTag : ID | /*empty*/ ; Tag : ID ; BASICTYPE : INT | DOUBLE | BOOL TYPE : BASICTYPE | POINT BASICTYPE ;
产生式的左边的非终结符就是语法树的父结点,右边每个终结符或非终结符都是子结点。
通过遍历语法树,我们每次碰到一个Specifier结点,就以此为参数,调用Type parse_specifier(node,isTempDec)函数来解析,函数返回指就是一个Type_的指针,
指向的是一个已经创建好了的Type_结点。
解析函数中,isTempDec被当作参数是因为,TempDec是与Specifier同层的结点,产生式如下:(其中,终结符只有INT DOUBLE BOOL POINT T TEMPLATE ID)
ExtDef : TempDec Specifier ExtDecList SEMI | TempDec Specifier SEMI | TempDec Specifier FunDec CompSt ; TempDec : TEMPLATE | /*empty*/ ;
读到这里,对于解析specifier的困难之处,读者乍一看可能看不出来.
其中的难点其实在structSpecifier:
StructSpecifier : STRUCT OptTag LC DefList RC
这个产生式中的DefList我还没列出来,DefList,顾名思义,就是定义列表.这里表示的就是结构体的成员定义.
其产生式如下:
DefList : Def DefList | /*empty*/ ; Def : Specifier DecList SEMI ; DecList : Dec | Dec COMMA DecList ; Dec : VarDec | VarDec ASSIGN Exp ; VarDec : ID | VarDec LB LINTEGER RB ;
DefList是一个递归的定义,表示可以有无穷多个Def,Def就是一个或者一组同类型变量定义,举个例子:
struct Spec0{ int a; double d1,d2; };
这里int a和double d1,d2;分别是2个Def.这里的主要任务有:
1) 对DecList的解析,要递归的生成一个链表,表中所有的类型都相同(都为Specifier,递归调用parse_specifier(),返回值被当作参数传入parse_decList()).最后
返回FieldList的表头,连接到先前生成的成员链表的尾部;变量名 都必须不同;//查错点1
2 )在解析VarDec的时候,生成的可能是数组,需要递归地连接数组的每一个维度;
3 )结构体中变量不能初始化,(我们没有static机制),所以解析Dec的时候能够查VarDec ASSIGN Exp的语义错;//查错点2
4 )每次返回一个解析完Def后的成员链表,都必须检查这个表与之前的整个结构体成员链表是否有重名的变量,如果有就报错;//查错点3
2.3 有关结构体和指针和泛型的事宜
这部分内容将在下一个博客中讨论。
相关文章推荐
- 十二、教你如何利用强大的中文语言技术平台做依存句法和语义依存分析
- 从零开始开发JVM语言(七)语义分析的起步
- 且看如何以精致的方式展现,解析和分析GitHub上语言的发展趋势
- Java语言语法语义分析器设计与实现
- 从零开始开发JVM语言(八)从类型定义开始的语义分析
- Tiny语言编译器之语义分析
- 面板数据分析步骤及流程-R语言
- R语言与统计分析
- 语义分析的一些方法(三)
- Android逆向分析基础-ARM 汇编语言基础
- Android系统Recovery工作原理之使用update.zip升级过程分析(八)---解析并执行升级脚本updater-script
- YAML 一种简洁的具有丰富语义的标记语言
- 解析JDK 7的动态类型语言支持
- UML需求分析步骤实例解析
- [WebKit内核] JavaScriptCore深度解析--基础篇(一)字节码生成及语法树的构建详情分析
- [语义]情感分析方向近况·0908
- paip.语义相关是否可在 哈米 的语义分析中应用
- SQL 数据库语言分析总结(一)
- Java 8 动态类型语言Lambda表达式实现原理解析
- Java6.0新特性之StAX--全面解析Java XML分析技术