10+8--语义分析与符号表
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
c hfwang - 8/22 -
基本概念
符号表
类型检查
VSL语言的符号表 1/3
符号表元素的数据类型 typedef struct symb { struct symb *next; int type; union { int val; char *text;
/* /* /* /* /*
} val1; union { /* 变量的第一个值 */ int val; /* 对变量取偏移量等 */ struct tac *label; /* 对标号取三地址码 指针 */ } val2 ; } SYMB ; /* 整数常量, 字符串常量和语句标号等也使用 本数据类型, 但是由于没有对其查找的要求, 这些数据将不保存在Hash表中 */ SYMB *symbtab[HASHSIZE] ; /* 符号表 */
静态性质(static):在编译阶段就可以确定的性质, 如:C语言的全 局变量, 类型, 变量和类型的关系,运算和转移指令和函数的入口 地址; 动态性质(dynamic):程序在运行阶段才能确定的性质— 程序在运 行时才能确定的性质,如:C语言的被调用函数的运行环境 (参数、 返回地址、 局部变量和返回值) ;面向对象语言的Virtual Function的动态绑定(binding); 动态性质有相对不变性, 栈式运行环境中, 如: 局部变量和栈顶的 位置关系是不变的; 动态性质必须用其相对不变性实现, 如:函数的调用和被调用转 化为相对不变的调用序列和被调用序列; 语义分析(Semantic Analysis)是编译器前端(front-end)的最后一个 环节, 主要是符号表的建立和类型检查(type checking), 为下一 步中间表示提供必要的上下文相关的信息。
下一个节点 */ 符号的数据类型 */ 变量的第一个值 */ 对整数常数取其值 */ 对变量取其形, 为字符指针 */
HASH符号表 i(int) • • f(fct) • • g(fct) j(int) • 用chaining解决HASH表的collision l(int) •
c hfwang
- 9/22 -
c hfwang
- 5/22 -
基本概念
符号表
类型检查
命题公式的抽象语法树的数据结构
struct symrec { char *name; /* 原子名 */ int value; /* 原子的值 */ } sym_table [16]; /* 符号表 */ typedef enum { And=1, Or=2, Impl=3, Not=4, Equi=5, ConstKind=6, Atom = 7} Kind; /* AST 结点类型 */ typedef struct streenode { Kind op; struct streenode *lchild, *rchild; union { int true_value; struct symrec *atom; } val; } STreeNode; /* AST数据结构 */ typedef STreeNode * SyntaxTree; in lex file: [a-zA-Z][a-zA-Z0-9]* { int tmp = getsym(yytext); yylval = mkAtomNode(&sym_table[tmp]); return ID; }
有序或无序线性链表:适合处理较小规模的符号表;如:记录C语言 的纪录类型的分量名和相关属性 Binary Search tree: 访问速度: O(log(n)) (n是符号表元素的个数) Hash表: 访问速度: O(n/m) (n是符号表元素的个数, m是hash表的 大小); 在实践中效果最好, 是目前编译器采用的主要方法.
HASH符号表 i(int) • • f(fct) • • g(fct) j(int) • 用chaining解决HASH表的collision l(int) •
c hfwang
- 10/22 -
基本概念
符号表
类型检查
VSL语言的符号表 3/3
插入与查表操作 void insert( SYMB *s ) { int hv = hash( s->TEXT1 ) ; s->next = symbtab[hv] ; /* 插入到链表的表头 */ symbtab[hv] = s ; } SYMB *lookup( char *s ) /* 查找是否在符号表中是否有和s同名的符号, 如果没有则返回空指针。 */ { int hv = hash( s ) ; SYMB *t = symbtab[hv] ; while( t != NULL ) if( strcmp( t->TEXT1, s ) == 0 ) break ; else t = t->next ; return t ; }
插入操作的动态演示 i(int) • • f(fct) • • g(fct) j(int) • 用chaining解决HASH表的collision! l(int) •
c hfwang
- 11/22 -
基本概念
符号表
类型检查
VSL语言的符号表 3/3
插入与查表操作 void insert( SYMB *s ) { int hv = hash( s->TEXT1 ) ; s->next = symbtab[hv] ; /* 插入到链表的表头 */ symbtab[hv] = s ; } SYMB *lookup( char *s ) /* 查找是否在符号表中是否有和s同名的符号, 如果没有则返回空指针。 */ { int hv = hash( s ) ; SYMB *t = symbtab[hv] ; while( t != NULL ) if( strcmp( t->TEXT1, s ) == 0 ) break ; else t = t->next ; return t ; }
插入操作的动态演示 i(int) • • f(fct) • • g(fct) j(int) • 用chaining解决HASH表的collision! l(int) • k(int)
c hfwang
- 11/22 -
基本概念
符号表
类型检查
VSL语言的符号表 3/3
插入与查表操作 void insert( SYMB *s ) { int hv = hash( s->TEXT1 ) ; s->next = symbtab[hv] ; /* 插入到链表的表头 */ symbtab[hv] = s ; } SYMB *lookup( char *s ) /* 查找是否在符号表中是否有和s同名的符号, 如果没有则返回空指针。 */ { int hv = hash( s ) ; SYMB *t = symbtab[hv] ; while( t != NULL ) if( strcmp( t->TEXT1, s ) == 0 ) break ; else t = t->next ; return t ; }
c hfwang
evaluate($1); } { { { { { { { { $$ $$ $$ $$ $$ $$ $$ $$ = = = = = = = = $1; } $1; } mkOpNode(And, $1, $3); } mkOpNode(Or, $1, $3); } mkOpNode(Impl, $1, $3); } mkOpNode(Equi, $1, $3); } mkOpNode(Not, $2, NULL); } $2; }
c hfwang - 3/22 -
基本概念
符号表
类型检查
抽象语法树
具体文法(Concrete Syntax): 借助一些辅助终结符号用产生式表达的文 法, 如: 增加覆盖优先级别的括号中缀表达式文法; 后缀表达式文法等 具体文法可能存在二义性; 抽象文法(Abstract Syntax): 表达不同具体文法的相同特征; 如, 前缀, 中 缀和后缀表达式均要表达的是运算量和运算符结合的次序关系; 抽象文法的表现形式是抽象语法树(Abstract Syntax Tree); 如: 运算符作 为父结点, 运算符或运算量作为子结点的树结构是任何表达式文法的抽象 语法树; AST避开的具体文法的细节和二义性; 如: 没有括号, 没有了优先级别和 结合次序等 AST作为编译过程的一个属性, 在编译器需要对文法结构进行多次遍历时 使用, 这样可以避免了对具体文法进行多次遍历;
基本概念符Βιβλιοθήκη 表类型检查语义分析
c hfwang
- 1/22 -
基本概念
符号表
类型检查
1
基本概念 引言 抽象语法树 命题公式的抽象语法树 符号表 符号表 非全局变量的处理 向前引用 类型检查 类型检查 类型等价
2
3
c hfwang
- 2/22 -
基本概念
符号表
类型检查
语义分析Semantic Analysis
对命题公式求其真值表, 需要对公式遍历2n 次(n为公式中原 子的个数); C语言的说明语句, 需要保留被说明的类型, 可以用类型表达 式这样一个AST.
c hfwang - 4/22 -
基本概念
符号表
类型检查
Example: 命题公式的抽象语法树
公式(P → Q) ↔ (¬P ∨ Q)的抽象语法树 ↔ → P Q P ¬ ∨ Q
c hfwang
- 6/22 -
基本概念
符号表
类型检查
命题公式的抽象语法树的建立
in yacc file: %{ #define YYSTYPE SyntaxTree %} %token NUM ID %left ’=’ %left ’>’ %left ’|’ %left ’&’ %right ’-’ %% line : exp ’\n’ { ; exp : NUM | ID | exp ’&’ exp | exp ’|’ exp | exp ’>’ exp | exp ’=’ exp | ’-’ exp | ’(’ exp ’)’ ;
- 7/22 -
基本概念
符号表
类型检查
符号表
符号表是编译器在编译阶段记录程序语言的标识符的相关语义性 质的数据结构; 如: 变量的词形, 类型信息, 内存地址, 作用域等; 符号表的生命周期是从语法分析开始到整个编译过程结束, 如果 编译器支持动态调试, 符号表的内容可能还保存在编译好的执行 文件中; 符号表是有副作用的属性, 一部分内容是综合属性, 如词形;另一 些内容是继承属性:如函数的向前引用(Forward Reference); 还有 一部分可能需要two pass才能确定; 对符号表的操作主要有:insert; search; update; delete; 符号表的实现方式主要有:
基本概念
符号表
类型检查
VSL语言的符号表 2/3
词法阶段符号的语义动作 In scanner.l: {variable} { mkname(); return VARIABLE; } ... void mkname ( void ) { struct symb *t; char *s; if((t = lookup(yytext)) != NULL) { yylval.symb = t; return; } s = (char *) safe_malloc(yyleng + 1); strncpy(s, yytext, yyleng); s[yyleng] = EOS; t = get_symb(); /* 创建符号内存单元 */ t->type = T_UNDEF; /* 定义符号单元 */ t->TEXT1 = s; insert(t); /* 插入符号表 */ yylval.symb = t; } /* 设置语义值 */
插入操作的动态演示 i(int) • • f(fct) • • g(fct) j(int) • 用chaining解决HASH表的collision! l(int) • k(int)
c hfwang
- 11/22 -
基本概念
符号表
类型检查
VSL语言的符号表 3/3
插入与查表操作 void insert( SYMB *s ) { int hv = hash( s->TEXT1 ) ; s->next = symbtab[hv] ; /* 插入到链表的表头 */ symbtab[hv] = s ; } SYMB *lookup( char *s ) /* 查找是否在符号表中是否有和s同名的符号, 如果没有则返回空指针。 */ { int hv = hash( s ) ; SYMB *t = symbtab[hv] ; while( t != NULL ) if( strcmp( t->TEXT1, s ) == 0 ) break ; else t = t->next ; return t ; }
基本概念
符号表
类型检查
VSL语言的符号表 1/3
符号表元素的数据类型 typedef struct symb { struct symb *next; int type; union { int val; char *text;
/* /* /* /* /*
} val1; union { /* 变量的第一个值 */ int val; /* 对变量取偏移量等 */ struct tac *label; /* 对标号取三地址码 指针 */ } val2 ; } SYMB ; /* 整数常量, 字符串常量和语句标号等也使用 本数据类型, 但是由于没有对其查找的要求, 这些数据将不保存在Hash表中 */ SYMB *symbtab[HASHSIZE] ; /* 符号表 */
静态性质(static):在编译阶段就可以确定的性质, 如:C语言的全 局变量, 类型, 变量和类型的关系,运算和转移指令和函数的入口 地址; 动态性质(dynamic):程序在运行阶段才能确定的性质— 程序在运 行时才能确定的性质,如:C语言的被调用函数的运行环境 (参数、 返回地址、 局部变量和返回值) ;面向对象语言的Virtual Function的动态绑定(binding); 动态性质有相对不变性, 栈式运行环境中, 如: 局部变量和栈顶的 位置关系是不变的; 动态性质必须用其相对不变性实现, 如:函数的调用和被调用转 化为相对不变的调用序列和被调用序列; 语义分析(Semantic Analysis)是编译器前端(front-end)的最后一个 环节, 主要是符号表的建立和类型检查(type checking), 为下一 步中间表示提供必要的上下文相关的信息。
下一个节点 */ 符号的数据类型 */ 变量的第一个值 */ 对整数常数取其值 */ 对变量取其形, 为字符指针 */
HASH符号表 i(int) • • f(fct) • • g(fct) j(int) • 用chaining解决HASH表的collision l(int) •
c hfwang
- 9/22 -
c hfwang
- 5/22 -
基本概念
符号表
类型检查
命题公式的抽象语法树的数据结构
struct symrec { char *name; /* 原子名 */ int value; /* 原子的值 */ } sym_table [16]; /* 符号表 */ typedef enum { And=1, Or=2, Impl=3, Not=4, Equi=5, ConstKind=6, Atom = 7} Kind; /* AST 结点类型 */ typedef struct streenode { Kind op; struct streenode *lchild, *rchild; union { int true_value; struct symrec *atom; } val; } STreeNode; /* AST数据结构 */ typedef STreeNode * SyntaxTree; in lex file: [a-zA-Z][a-zA-Z0-9]* { int tmp = getsym(yytext); yylval = mkAtomNode(&sym_table[tmp]); return ID; }
有序或无序线性链表:适合处理较小规模的符号表;如:记录C语言 的纪录类型的分量名和相关属性 Binary Search tree: 访问速度: O(log(n)) (n是符号表元素的个数) Hash表: 访问速度: O(n/m) (n是符号表元素的个数, m是hash表的 大小); 在实践中效果最好, 是目前编译器采用的主要方法.
HASH符号表 i(int) • • f(fct) • • g(fct) j(int) • 用chaining解决HASH表的collision l(int) •
c hfwang
- 10/22 -
基本概念
符号表
类型检查
VSL语言的符号表 3/3
插入与查表操作 void insert( SYMB *s ) { int hv = hash( s->TEXT1 ) ; s->next = symbtab[hv] ; /* 插入到链表的表头 */ symbtab[hv] = s ; } SYMB *lookup( char *s ) /* 查找是否在符号表中是否有和s同名的符号, 如果没有则返回空指针。 */ { int hv = hash( s ) ; SYMB *t = symbtab[hv] ; while( t != NULL ) if( strcmp( t->TEXT1, s ) == 0 ) break ; else t = t->next ; return t ; }
插入操作的动态演示 i(int) • • f(fct) • • g(fct) j(int) • 用chaining解决HASH表的collision! l(int) •
c hfwang
- 11/22 -
基本概念
符号表
类型检查
VSL语言的符号表 3/3
插入与查表操作 void insert( SYMB *s ) { int hv = hash( s->TEXT1 ) ; s->next = symbtab[hv] ; /* 插入到链表的表头 */ symbtab[hv] = s ; } SYMB *lookup( char *s ) /* 查找是否在符号表中是否有和s同名的符号, 如果没有则返回空指针。 */ { int hv = hash( s ) ; SYMB *t = symbtab[hv] ; while( t != NULL ) if( strcmp( t->TEXT1, s ) == 0 ) break ; else t = t->next ; return t ; }
插入操作的动态演示 i(int) • • f(fct) • • g(fct) j(int) • 用chaining解决HASH表的collision! l(int) • k(int)
c hfwang
- 11/22 -
基本概念
符号表
类型检查
VSL语言的符号表 3/3
插入与查表操作 void insert( SYMB *s ) { int hv = hash( s->TEXT1 ) ; s->next = symbtab[hv] ; /* 插入到链表的表头 */ symbtab[hv] = s ; } SYMB *lookup( char *s ) /* 查找是否在符号表中是否有和s同名的符号, 如果没有则返回空指针。 */ { int hv = hash( s ) ; SYMB *t = symbtab[hv] ; while( t != NULL ) if( strcmp( t->TEXT1, s ) == 0 ) break ; else t = t->next ; return t ; }
c hfwang
evaluate($1); } { { { { { { { { $$ $$ $$ $$ $$ $$ $$ $$ = = = = = = = = $1; } $1; } mkOpNode(And, $1, $3); } mkOpNode(Or, $1, $3); } mkOpNode(Impl, $1, $3); } mkOpNode(Equi, $1, $3); } mkOpNode(Not, $2, NULL); } $2; }
c hfwang - 3/22 -
基本概念
符号表
类型检查
抽象语法树
具体文法(Concrete Syntax): 借助一些辅助终结符号用产生式表达的文 法, 如: 增加覆盖优先级别的括号中缀表达式文法; 后缀表达式文法等 具体文法可能存在二义性; 抽象文法(Abstract Syntax): 表达不同具体文法的相同特征; 如, 前缀, 中 缀和后缀表达式均要表达的是运算量和运算符结合的次序关系; 抽象文法的表现形式是抽象语法树(Abstract Syntax Tree); 如: 运算符作 为父结点, 运算符或运算量作为子结点的树结构是任何表达式文法的抽象 语法树; AST避开的具体文法的细节和二义性; 如: 没有括号, 没有了优先级别和 结合次序等 AST作为编译过程的一个属性, 在编译器需要对文法结构进行多次遍历时 使用, 这样可以避免了对具体文法进行多次遍历;
基本概念符Βιβλιοθήκη 表类型检查语义分析
c hfwang
- 1/22 -
基本概念
符号表
类型检查
1
基本概念 引言 抽象语法树 命题公式的抽象语法树 符号表 符号表 非全局变量的处理 向前引用 类型检查 类型检查 类型等价
2
3
c hfwang
- 2/22 -
基本概念
符号表
类型检查
语义分析Semantic Analysis
对命题公式求其真值表, 需要对公式遍历2n 次(n为公式中原 子的个数); C语言的说明语句, 需要保留被说明的类型, 可以用类型表达 式这样一个AST.
c hfwang - 4/22 -
基本概念
符号表
类型检查
Example: 命题公式的抽象语法树
公式(P → Q) ↔ (¬P ∨ Q)的抽象语法树 ↔ → P Q P ¬ ∨ Q
c hfwang
- 6/22 -
基本概念
符号表
类型检查
命题公式的抽象语法树的建立
in yacc file: %{ #define YYSTYPE SyntaxTree %} %token NUM ID %left ’=’ %left ’>’ %left ’|’ %left ’&’ %right ’-’ %% line : exp ’\n’ { ; exp : NUM | ID | exp ’&’ exp | exp ’|’ exp | exp ’>’ exp | exp ’=’ exp | ’-’ exp | ’(’ exp ’)’ ;
- 7/22 -
基本概念
符号表
类型检查
符号表
符号表是编译器在编译阶段记录程序语言的标识符的相关语义性 质的数据结构; 如: 变量的词形, 类型信息, 内存地址, 作用域等; 符号表的生命周期是从语法分析开始到整个编译过程结束, 如果 编译器支持动态调试, 符号表的内容可能还保存在编译好的执行 文件中; 符号表是有副作用的属性, 一部分内容是综合属性, 如词形;另一 些内容是继承属性:如函数的向前引用(Forward Reference); 还有 一部分可能需要two pass才能确定; 对符号表的操作主要有:insert; search; update; delete; 符号表的实现方式主要有:
基本概念
符号表
类型检查
VSL语言的符号表 2/3
词法阶段符号的语义动作 In scanner.l: {variable} { mkname(); return VARIABLE; } ... void mkname ( void ) { struct symb *t; char *s; if((t = lookup(yytext)) != NULL) { yylval.symb = t; return; } s = (char *) safe_malloc(yyleng + 1); strncpy(s, yytext, yyleng); s[yyleng] = EOS; t = get_symb(); /* 创建符号内存单元 */ t->type = T_UNDEF; /* 定义符号单元 */ t->TEXT1 = s; insert(t); /* 插入符号表 */ yylval.symb = t; } /* 设置语义值 */
插入操作的动态演示 i(int) • • f(fct) • • g(fct) j(int) • 用chaining解决HASH表的collision! l(int) • k(int)
c hfwang
- 11/22 -
基本概念
符号表
类型检查
VSL语言的符号表 3/3
插入与查表操作 void insert( SYMB *s ) { int hv = hash( s->TEXT1 ) ; s->next = symbtab[hv] ; /* 插入到链表的表头 */ symbtab[hv] = s ; } SYMB *lookup( char *s ) /* 查找是否在符号表中是否有和s同名的符号, 如果没有则返回空指针。 */ { int hv = hash( s ) ; SYMB *t = symbtab[hv] ; while( t != NULL ) if( strcmp( t->TEXT1, s ) == 0 ) break ; else t = t->next ; return t ; }