1、语义分析和符号表,主要内容:语义分析概述(必要性、功能、描述方法)符号表类型表达式声明和程序体的语义分析,语义分析的必要性,语法和语义的区别;语法:关于什么样的字符串才是该语言 在组成结构上合法的程序的法则。语义:关于结构上合法的程序的意义的 法则。,语义分析的分类,语义种类静态语义:在编译阶段(从程序文本上)可以检查的语义。动态语义:通过程序的执行才能检查的语义。,语义错误 各种条件表达式的类型是不是boolean型? 运算符的分量的类型是否相容? 赋值语句的左右部的类型是否相容? 形参和实参的类型是否相容? 下标表达式的类型是否为所允许的类型? 变体记录中表示情形的常量是否为合法类型? 函
2、数说明中的函数类型和返回值的类型是否一致? VE中的V是不是变量,而且是数组类型? V.id中的V是不是变量,而且是记录类型? id是不是该记录类型中的域名? V中的V是不是指针或文件变量? y+f()中的f是不是函数名?形参个数和实参个数是否一致? p()语句中的p是不是过程名?形参个数和实参个数是否一致? 每个使用性标识符是否都有声明?在同层内有无标识符被声明多次? 标号是否有声明?有无重复声明和重复定位错误?有无非法转入错误? 子界类型中的下界和上界类型是否相容?下界是否小于等于上界?,语义分析的内容:类型分析;标识符相关信息; 语义分析的功能:检查语义错误构造标识符属性表(符号表) 语
3、义分析的实现:与语法分析相结合,语义分析的功能图示,语义分析,语法分析树,TokenList,语义定义,自然语言描述规定,符号表,判定,标识符的内部表示类型的内部表示值的内部表示,三种内部表示,Code,标识符的内部表示,标识符种类:常量名、类型名、变量名、函数名、过程名、域名。TYPE idkind=( consKind, typeKind, varKind, fieldKind, procKind,funcKind )内部表示(AttributeIR):常量:类型:变量:域名*:过函:,Value,Kind,TypePtr,Forward,Kind,TypePtr,Off,Level,Ac
4、cess,Kind,TypePtr,HostType,Off,Kind,TypePtr,Size,Forward,Class,Parm,Level,Kind,TypePtr,Off,例有声明如下:CONST pai= 3.14 ;TYPE vector=ARRAY110 OF integer;VAR x, y : real ;r, s : vector ;设当前层数和可用offset值分别为L和0,构造标识符 pai, vector, x, y, r 和s 的属性表示。,类型的内部表示,类型的种类:标准、子界、枚举、数组、记录、集合、文件、指针类型等等。TypeKind=(intTy,bool
5、Ty,charTy,realTy,enumTy,subTy,arrayTy,recordTy,setTy,fileTy,pointerTy)内部表示:(TypeIR)标准类型:sub: enum: array:,Up,Low,HostType,Kind,Size,Leng,Elems,Kind,Size,ElemType,IndexType,Kind,Size,Kind,Size,record:FixBody:VariBody:set: file: pointer:,VariBody,FixBody,Kind,Size,Next,Off,FixUnitType,id,VariUnits,Cas
6、eUnit,Next,VariBody,FixBody,BaseType,Kind,Size,CompType,Kind,Size,TypeName,Kind,Size,例有如下的类型定义:at = ARRAY 110 OF ARRAY1100 OF integer;rt = RECORD x : real ; a : at;CASE u: boolean OFfalse:(k : integer);true:(y: real; b: boolean)END构造类型的内部表示。,值的内部表示,非结构类型值的内部表示:实型:指针:有序类型:整数形式,有序类型的常量表示: 整型常量:ord(N)
7、= N布尔常量:ord(false)=0, ord(true) = 1字符常量:ord(C) = ASC (C)枚举常量:设有枚举类型(D,A,B),则有ord(D)=0,ord(A)=1,ord(B)=2子界常量:设有子界类型C1C2,则值空间为ord(C1).ord(C2),符号表,标识符的作用:声明部分:定义了各种对象及对应的属性和使用规则。程序体:对所定义的对象进行各种操作。,$id,idname,Idname,AttributeIR,必要性Token:新表符号表(种类、类型等信息):,有关符号表的操作:添加、作用域删除、查询处理符号表的模块:定义符号表数据结构 定义符号表上的操作,符
8、号表,符号表的作用:为语义检查和代码生成提供标识符的语义信息。 标识符的处理思想: 遇到定义性标识符时,在符号表中填写被定义标识符的符号项; 当遇到使用性标识符时,用该标识符查符号表求得其属性。,标识符的特点,标识符的作用域:标识符有效的最大程序段 嵌套作用域规则:当存在标识符的嵌套声明时,最近定义的属性为标识符的当前属性 局部化单位:允许有声明的程序段,P:,Var x ,y,z,Var x,m,n,x:=1; m:=x+1;,y:=x+1;,x:=0;,Q:,局部化区入口,Proc p( Func f( 形式过/函 p( f( Record begin,符号表的种类:全局符号表、局部符号表
9、 原则: 进入一个局部化区时,记录本层符号表的 位置 遇到定义性标识符时,构造其语义信息, 查本层符号表,若存在,则有重复声明错 误,否则将语义信息填入表中 遇到一个使用性标识符时,查表(从里层 到外层),查不到则有未定义标识符错 误,否则构造新的TOKEN 退出一个局部化区时,作废本层符号表,标识符处理的原则,符号表的实现,用局部符号表实现 proc p:x,y,zproc p1:x,y1,z1proc p2:yy,zx,y1,z1,yproc p3:z,ax,y,ax,z,符号表的实现,用全局符号表实现proc p0:x,yproc p1:x,zyproc p2:x1,y1yx,z,语义分
10、析例子,program p()type at=array1100 of array110 of intetervar x:real; a:at; i:integer;proc p1(var a1:at; a2:at)var x:integer; a:real;proc p2(n:integer)var m:150; x:real;m,n,x(使用性出现)enda1,a2,x,a,i(使用性出现)endx,a,i(使用性出现)end,标号的语义分析,标号出现的位置:标号声明:label 1, 2, , n;标号定位(语句前):i:Statement;标号使用(Goto后):goto i;标号部分
11、的语义错误:标号重复声明;标号重复定位;标号有定位而无声明;标号有使用而无定位;Goto语句有非法转入.,标号部分语义分析原理,设置五种表:LDEC,LDEF,LUSE,SL,PLLDEC表:(Flag, Label,);LDEF、LUSE表:(Label);SL表:(kind,LDEFaddr,LUSEaddr);PL表:(LDECaddr,LDEFaddr); 标号的语义分析原理1)进入一个过/函时,将本层LDEC和LDEF的地址填入PL表;2)遇到一个标号声明“label 1, 2,n”时,建立本层LDEC表(检查重复声明错误),其中的Flag标志均设置为0;3)遇到定位性标号“:Sta
12、tement”时: 检查在LDEC表中有无 ,若无则表示无标号声明错误; 若有,则检查其Flag位,若是1,则有重复定位错误; 若Flag=0,令其Flag位为1,并将 填入LDEF表中。 查看LUSE表,若其中有则将其删除掉。,4)进入一个结构语句时,将本语句的LDEF和LUSE表位置填入SL表;5)遇到一个“goto ” 时: 查看LDEF表,看其中是否有; 若无,将填入LUSE表;6)退出一个结构化语句时: 清查本层LUSE表(若有定位则删除该项):用本层的LUSE中标号查本层定位表,若查到,则把该项从LUSE中删除; 作废本层的LDEF。7)退出一个过/函时: 清查本层LUSE表; 作废本层的LDEC和LDEF。8)程序结束时,清查LUSE表,若非空,则说明有标号为定位的错误。,