第7章语义分析与中间代码生成内容摘要:

struct node *next。 } node。 xx yy nn ee xx tt 0 4 8 2020/11/17 45 记录的翻译  符号表及有关表格处理  为每个记录类型单独构造一张符号表  将域名 id的信息 (名字、类型、字节数 )填入到该记录的符号表中  所有域都处理完后, offset将保存记录中所有数据对象的宽度总和  record应用于指向该记录符号表的指针获得 2020/11/17 46 记录的翻译 T  record D end T  record L D end { := record(top(tblptr))。 := top(offset)。 pop(tblptr)。 pop(offset) } L   {t := mktable(nil)。 push(t,tblprt)。 push(0,offset)} 2020/11/17 47 赋值语句的翻译 翻译的需求  充分了解各种语言现象的语义  包括:控制结构、数据结构、单词  充分了解它们的实现方法  目标语言的语义  了解中间代码的语义  了解运行环境 2020/11/17 48 辅助子程序与语义属性设置  辅助子程序  gencode(code), emit(code):产生一条中间代码  newtemp:产生新的临时变量  lookup:检查符号表中是否出现某名字  语义属性设置  中间代码序列: code  地址: addr  下一条四元式序号: nextquad 2020/11/17 49 简单赋值语句的翻译 S  id := E {p := lookup()。 if p  nil then gencode( p, ‘:=’, ) else error } E  E1 + E2{ := newtemp。 emit(,‘:=’,‘+’,)} E  E1 { := newtemp。 emit(,‘:=’,‘uminus’,)} E  (E1) { := } E  id {p := lookup()。 if p  nil then := p else error } 2020/11/17 50 临时名字的重用  大量临时变量的使用对优化有利  大量临时变量会增加符号表管理的负担  也会增加运行时临时数据占的空间 E  E1 + E2的动作产生的代码的一般形式为 计算 E1到 t1 计算 E2到 t2 t3 := t1 + t2 (( ))((( )( ))( )) 临时变量的生存期像配对括号那样嵌套或并列 2020/11/17 51 基于临时变量生存期特征的三地址代码 x := a  b + c  d  e  f 语 句 计数器 c的值 0 $0 := a  b 1 $1 := c  d 2 $0 := $0 + $1 1 $1 := e  f 2 $0 := $0  $1 1 x := $0 0 引入一个计数器 c,它的初值为 0。 每当临时变量仅作为运算对象使用时, c减去 1;每当要求产生新的临时名字时,使用 $c并把 c增加 1。 2020/11/17 52 数组元素的寻址  数组元素引用的翻译  完成上下界检查  生成完成相对地址计算的代码  目标  x := y[i] 和 y[i] := x  y为数组地址的固定部分 ——相当于第 1个元素的地址, i是相对地址,不是数组下标 数组说明的翻译 •符号表及有关表格 (内情向量 )的处理 •维数、下标上界、下标下界、类型等 •首地址、需用空间计算 •按行存放、按列存放 ——影响具体元素地址的计算 2020/11/17 53 数组元素地址计算 ——行优先  一维数组 A[low1:up1] (nk=upklowk+1) addr(A[i])=base+(ilow1)*w =(baselow1*w)+i*w=c+i*w  二维数组 A[low1:up1 ,low2:up2]; A[i1,i2] addr(A[i1,i2])=base+((i1 low1)*n2+(i2low2))*w = base+(i1 low1)*n2*w+(i2low2)*w = base low1* n2*wlow2*w +i1 * n2*w+ i2*w = base(low1* n2 low2)*w +(i1 * n2 + i2)*w =c+(i1*n2+ i2)*w A[1, 1], A[1, 2], A[1, 3] A[2, 1], A[2, 2], A[2, 3] 2020/11/17 54 数组元素地址计算的翻译方案设计 下标变量访问的产生式 L  id[Elist] | id Elist  Elist, E | E 为了使数组各维的长度 n在我们将下标表达式合 并到 Elist时是可用的 , 需将产生式改写为: L  Elist ] | id Elist  Elist, E | id[E 2020/11/17 55 数组元素地址计算的翻译方案设计 L  Elist ] | id Elist  Elist, E | id[E  目的  使我们在整个下标表达式列表 Elist的翻译过程中随时都能知道符号表中相应于数组名 id的表项,从而能够了解登记在符号表中的有关数组 id的全部信息。  于是我们就可以为非终结符 Elist引进一个综合属性,用来记录指向符号表中相应数组名字表项的指针。 2020/11/17 56 数组元素地址计算的翻译方案设计  属性  ,用来记录指向符号表中相应数组名字表项的指针。  ,用来记录 Elist中下标表达式的个数,即数组的维数。  ,用来临时存放 Elist的下标表达式计算出来的值。  函数  limit(array, j),返回 nj 2020/11/17 57 带有数组引用的赋值语句的翻译 S  Left := E E  E + E E  (E) E  Left Left  Elist] Left  id Elist  Elist,E Elist  id[E 2020/11/17 58 赋值语句的翻译模式 Leftid { :=。 :=null} Elistid[E {:=。 := 1。 := } ElistElist1,E {t:=newtemp。 m:=+1。 gencode(t,‘:=’,‘’, limit(,m))。 gencode(t,‘:=’,t,‘+’,)。 :=。 := t。 := m} Left  Elist] { := newtemp。 := newtemp。 gencode(,‘:=’,base(),‘’,invariant())。 gencode(,‘:=’,‘’,w)} i1*n2 (i1*n2)+i2 ((i1*n2)+i2)*w base(low1* n2 low2)*w 2020/11/17 59 赋值语句的翻译模式 E  Left {if = null then / Left是简单变量 / := else begin := newtemp。 gencode(,‘:=’,‘[’,‘]’)end} E  E1 + E2 { := newtemp。 gencode(,‘:=’,‘+’,)} E  (E1) { := } S  Left := E {if =null then /Left是简单变量 / gencode(, ‘:= ’, ) else gencode(,‘[’,‘]’,‘:=’,)} ((i1*n2)+i2)*w+(base(low1* n2 low2)*w) ((i1*n2)+i2)*w+(base(low1* n2 low2)*w) 2020/11/17 60 例:设 A是一个 10 20的整型数组 ——w=4 S := := x := null x := t4 := t2 := t3 := t1 := 2 := A , := y := 1 := A := z := z := null := y := y := null A [ z ] y x := A[ y, z ]的注释分析树 2020/11/17 61 例 S := := x := null x := t4 := t2 := t3 := t1 := 2 := A , := y := 1 := A := z := z := null := y := y := null A [ z ] y x := A[ y, z ]的注释分析树 t1 := y  20 t1 := t1 + z 2020/11/17 62 例 S := := x := null x := t4 := t2 := t3 := t1 := 2 := A , := y := 1 := A := z := z := null := y := y := null A [ z ] y x := A[ y, z ]的注释分析树 t1 := y  20 t1 := t1 + z t2 :=baseA 84 t3 := 4  t1 2020/11/17 63 例 S := := x := null x := t4 := t2 := t3 := t1 := 2 := A , := y := 1 := A := z := z := null := y := y := null A [ z ] y x := A[ y, z ]的注释分析树 t1 := y  20 t1 := t1 + z t4 := t2 [t3 ] t2 :=baseA 84 t3 := 4  t1 2020/11/17 64 例 S := := x := null x := t4 := t2 := t3 := t1 := 2 := A , := y := 1 := A := z := z := null := y := y := null A [ z ] y x := A[ y, z ]的注释分析树 t1 := y  20 t1 := t1 + z t4 := t2 [t3 ] x := t4 t2 :=baseA 84 t3 := 4  t1 2020/11/17 65 类型检查  类型检查具有发现程序错误的能力 , 为了进行类型检查 , 编译程序需要为源程序的每个语法成分赋予一个类型表达式 , 名字的类型表达式保存在符号表中 , 其他语法成分 (如表达式 E或语句 S)的类型表达式则作为文法符号的属性保存在语义栈中。  类型检查的任务就是确定这些类型表达式是否符合一定的规则 , 这些规则的集合通常称为源程序的类型系统 2020/11/17 66 类型检查的规则  类型综合  从子表达式的类型确定表达式的类型  要求名字在引用之前必须先进行声明  if f的类型为 s→t and x的类型为 s then 表达式 f(x)的类型为 t  类型推断  根据语言结构的使用方式来确定其类型  经常被用于从函数体推断函数类型  if f(x)是一个表达式 then 对某两个类型变量 α和 β,f具有类型 →β and。
阅读剩余 0%
本站所有文章资讯、展示的图片素材等内容均为注册用户上传(部分报媒/平媒内容转载自网络合作媒体),仅供学习参考。 用户通过本站上传、发布的任何内容的知识产权归属用户或原始著作权人所有。如有侵犯您的版权,请联系我们反馈本站将在三个工作日内改正。