程序的语义分析
主要内容:
声明的语义分析;
执行体的语义分析:
表达式的语义分析;
语句的语义分析;
声明的语义分析
? 语义分析工作:
建立符号表;
检查标识符的重复声明;
? 声明部分:
标号声明,LabelDecPart;
常量声明,ConsDecPart;
类型声明,TypeDecPart;
变量声明,VarDecPart;
过函声明,RoutDecPart;
LabelDecPart → label ? {,? }; | ?
ConstDecPart → const id = C ;,..; id = C ; | ?
TypeDecPart → type id = T ;,..; id = T ; | ?
VarDecPart → var VarList,T ;,..; VarList,T ; | ?
RoutDecPart → RoutDec ;,..; RoutDec ; | ?
RoutDec → ProcHead ; Block | FuncHead ; Block
ProcHead → procedure id (ParamDecList)
FuncHead → function id (ParamDecList),Type
ParamDecList → ParamDec ;,.......,; ParamDec
ParamDec → VarList, Type
| var VarList, Type
| ProcHead | FuncHead
标号- LabelPart
? 标号出现的位置:
标号声明,label ?1,?2,…,?n;
标号定位 ( 语句前),?i,Statement;
标号使用( Goto后),goto ?i;
? 标号部分的语义错误:
标号重复声明;
标号重复定位;
标号有定位而无声明;
标号有使用而无定位;
Goto语句有非法转入,
标号部分语义分析原理
? 设置三种表,LDEC,LDEF,LUSE
LDEC表, (Flag,Label)以子程序为局部单位;
LDEF,LUSE表,(Label) 以结构体为局部单位
? 标号声明部分 label ?1,?2,…,?n,(填写 LDEC表 )
建立本层 LDEC; 令 Flag:=0;检查是否有重复声明;
? 标号定位部分 ?:Statement,(填写 LDEF表 )
若 LDEC中没有 ?,则表示该标号未声明;
否则:若 ?的 flag是 1,则表示有重复定位错误,
否则令 flag:=1,并将 ?填入 LDEF表中。
? 标号使用 goto ?,(填写 LUSE表 )
若 LDEF表中没有 ?,则将 ?填入 LUSE表中,表示 ?的
定位可能在后。
? 进入结构语句时,记录本段 LDEF和 LUSE。
结束时,将 LUSE表中 LDEF中的项删除,删除
本段 LDEF表,LUSE表保留 。
? 进入过函时,记录本层 LDEC,LDEF表;
退出时,将 LUSE表中 LDEF中的项删除,删除
本层 LDEC表和 LDEF表,LUSE表保留。
? 进入主程序时,记录本层 LDEC, LDEF表;
结束时,检查 LUSE是否为空,若非空表示有
非法转入或使用了无定位的标号。
常量声明的语义处理
?形式,ConsDecPart → const ConsDecList
ConsDecList → ConsDec {;ConsDecList}
ConsDec → id = C
?id = C 的语义处理原理:
? 求 C.type,C.val
? 查符号表是否有标识符 id; 若有则重复
声明错误
? 否则构造
(id,C.type,consKind,C.value)
填写到符号表中
类型声明的语义处理
? 形式,TypeDecPart → type TypeDecList
TypeDecList → TypeDec {;TypeDecList}
TypeDec → id = T
? id = T的语义 分析要点:
? 对 T进行类型分析返回 内部表示指针 TPtr;
? 检查符号表是否有 重复声明;
? 若无则构造符号表,
( id,TPtr,typeKind,false/true)
? 当整个类型声明部分结束时, 进行超前指针
类型结点的回填工作
变量声明部分
? 形式,VarDecPart → var VarDecList
VarDecList → VarDec {; VarDecList}
VarDec ? idList, T
? id1,…,idK:T的语义分析 要点:
? 检查符号表是否有重复声明;
? 构造符号表项, 1 ?j?K,
(idj,tp,varKind,Accept,Level,offj),其中 tp
和 offj的值等待回填;
? 对 T进行类型分析返回指针 TPar;
? 回填符号表中的 tp指针;
? off的确定, off:=off+ TPar?.size;
过 /函声明的处理
? 形式,RoutDec → ProcHead;Block|FuncHead;Block
? ProHead → p rocedure id (ParamDecList)
FuncHead→ function id (ParamDecList):Type
ParamDec → idList, Type
| var VarList, Type
| ProcHead | FuncHead
Block → DecPart;Body |forward
? 处理要点:
子程序首部的处理 HeadProcess
声明部分的处理
语句部分的处理
过函首部的处理
? 过函名 id,填写符号表项:
(id,void/?,routKind,L,?,actual,?,?,?)
? 形参,进入新的局部化区 level:= L+1; 第一个形参的 offset
? 由系统确定设为 off0; 构造第 i个形参的符号表项:
值参,(xi,tpi,varKind,dir,L+1,offi)
offi,= offi-1 + sizeof(tpi-1)
变参,(xi,tpi,varKind,indir,L+1,offi)
offi,= offi-1 + 1
过函形参,(r,void/?,routKind,L+1,?,formal,offr)
进入新的局部化区 leve:= L+2,形参同上处理,
但 off值为空。结束时结束局部化区;回填值。
首部结束,回填类型及形参表地址。
? forward值,如果过函体为 forward则为 1否则为 0
子程序首部的处理例子
Procedure p(x:real ; var y, boolean ;
function f(i,j, integer), integer)
当前层数为 L,InitOff=1.则,
falsesizecodeactualparaPLroutKindvoidppEntry
L+2dirvarKindintPtri
L+2dirvarKindintPtrj
iEntry
jEntry
2L+1indirvarKindboolPtryyEntry
1L+1dirvarKindrealPtrxxEntry
3formalparaFL+1routKindintPtrffEntry
程序体部分的语义分析
? 表达式的语义分析
? 赋值语句的语义分析
? 调用语句的语义分析
? 标号语句的语义分析
? 结构语句的语义分析
表达式的语义分析
? 任务,检查运算分量的类型相容性,求表
? 达式类型。
? 分析:
? C
? V,id,Var[E],Var.id,Var?
? E op E
赋值语句的语义分析
? 任务,检查赋值相容性
? 分析步骤:
? var 的类型分析 var.Type
? E 的类型分析 E.Type
? 判定 var.Type和 E.Type是否赋值相容
调用语句的语义分析
? 任务,形实结合的相容性。函数求出返回类
型。
? 原理,P(AE1,...,AEn )
? 用 P查符号表,找出无声明错
? routkind?,找出非过 /函标识符
? Params保证个数相同,对应类型相容,类别
相同 。
结构语句的语义分析
? 问题,结构语句结束符对应多个结构语句结束。
? 解决办法,对结构化语句重新定义,使得每个结
构化语句都自带结束符 。
for i = 1 to 10 do
for j = 1 to 100 do
begin A [ i,j ] = 0 ; end ;
修改后的结构语句的定义
? Statement→ IF Expr THEN Statement FI
? Statement→ IF Expr THEN Statement ELSE
? Statement FI
? Statement→ WHILE Expr DO Statement OD
? Statement→ FOR,.............,DO Statement OD
? Statement→ BEGIN StatemenList END
修改后的 if语句的分析
? 形式,if E then S1 else S2 fi
? 分析步骤:
? ① 创建本层 LDEF,LUSE表
? ② E的分析; E.Type? boolptr
? ③ 分析 S1
? ④ 有 else 则分析 S2
? ⑤ 删掉本层 LDEF。
主要内容:
声明的语义分析;
执行体的语义分析:
表达式的语义分析;
语句的语义分析;
声明的语义分析
? 语义分析工作:
建立符号表;
检查标识符的重复声明;
? 声明部分:
标号声明,LabelDecPart;
常量声明,ConsDecPart;
类型声明,TypeDecPart;
变量声明,VarDecPart;
过函声明,RoutDecPart;
LabelDecPart → label ? {,? }; | ?
ConstDecPart → const id = C ;,..; id = C ; | ?
TypeDecPart → type id = T ;,..; id = T ; | ?
VarDecPart → var VarList,T ;,..; VarList,T ; | ?
RoutDecPart → RoutDec ;,..; RoutDec ; | ?
RoutDec → ProcHead ; Block | FuncHead ; Block
ProcHead → procedure id (ParamDecList)
FuncHead → function id (ParamDecList),Type
ParamDecList → ParamDec ;,.......,; ParamDec
ParamDec → VarList, Type
| var VarList, Type
| ProcHead | FuncHead
标号- LabelPart
? 标号出现的位置:
标号声明,label ?1,?2,…,?n;
标号定位 ( 语句前),?i,Statement;
标号使用( Goto后),goto ?i;
? 标号部分的语义错误:
标号重复声明;
标号重复定位;
标号有定位而无声明;
标号有使用而无定位;
Goto语句有非法转入,
标号部分语义分析原理
? 设置三种表,LDEC,LDEF,LUSE
LDEC表, (Flag,Label)以子程序为局部单位;
LDEF,LUSE表,(Label) 以结构体为局部单位
? 标号声明部分 label ?1,?2,…,?n,(填写 LDEC表 )
建立本层 LDEC; 令 Flag:=0;检查是否有重复声明;
? 标号定位部分 ?:Statement,(填写 LDEF表 )
若 LDEC中没有 ?,则表示该标号未声明;
否则:若 ?的 flag是 1,则表示有重复定位错误,
否则令 flag:=1,并将 ?填入 LDEF表中。
? 标号使用 goto ?,(填写 LUSE表 )
若 LDEF表中没有 ?,则将 ?填入 LUSE表中,表示 ?的
定位可能在后。
? 进入结构语句时,记录本段 LDEF和 LUSE。
结束时,将 LUSE表中 LDEF中的项删除,删除
本段 LDEF表,LUSE表保留 。
? 进入过函时,记录本层 LDEC,LDEF表;
退出时,将 LUSE表中 LDEF中的项删除,删除
本层 LDEC表和 LDEF表,LUSE表保留。
? 进入主程序时,记录本层 LDEC, LDEF表;
结束时,检查 LUSE是否为空,若非空表示有
非法转入或使用了无定位的标号。
常量声明的语义处理
?形式,ConsDecPart → const ConsDecList
ConsDecList → ConsDec {;ConsDecList}
ConsDec → id = C
?id = C 的语义处理原理:
? 求 C.type,C.val
? 查符号表是否有标识符 id; 若有则重复
声明错误
? 否则构造
(id,C.type,consKind,C.value)
填写到符号表中
类型声明的语义处理
? 形式,TypeDecPart → type TypeDecList
TypeDecList → TypeDec {;TypeDecList}
TypeDec → id = T
? id = T的语义 分析要点:
? 对 T进行类型分析返回 内部表示指针 TPtr;
? 检查符号表是否有 重复声明;
? 若无则构造符号表,
( id,TPtr,typeKind,false/true)
? 当整个类型声明部分结束时, 进行超前指针
类型结点的回填工作
变量声明部分
? 形式,VarDecPart → var VarDecList
VarDecList → VarDec {; VarDecList}
VarDec ? idList, T
? id1,…,idK:T的语义分析 要点:
? 检查符号表是否有重复声明;
? 构造符号表项, 1 ?j?K,
(idj,tp,varKind,Accept,Level,offj),其中 tp
和 offj的值等待回填;
? 对 T进行类型分析返回指针 TPar;
? 回填符号表中的 tp指针;
? off的确定, off:=off+ TPar?.size;
过 /函声明的处理
? 形式,RoutDec → ProcHead;Block|FuncHead;Block
? ProHead → p rocedure id (ParamDecList)
FuncHead→ function id (ParamDecList):Type
ParamDec → idList, Type
| var VarList, Type
| ProcHead | FuncHead
Block → DecPart;Body |forward
? 处理要点:
子程序首部的处理 HeadProcess
声明部分的处理
语句部分的处理
过函首部的处理
? 过函名 id,填写符号表项:
(id,void/?,routKind,L,?,actual,?,?,?)
? 形参,进入新的局部化区 level:= L+1; 第一个形参的 offset
? 由系统确定设为 off0; 构造第 i个形参的符号表项:
值参,(xi,tpi,varKind,dir,L+1,offi)
offi,= offi-1 + sizeof(tpi-1)
变参,(xi,tpi,varKind,indir,L+1,offi)
offi,= offi-1 + 1
过函形参,(r,void/?,routKind,L+1,?,formal,offr)
进入新的局部化区 leve:= L+2,形参同上处理,
但 off值为空。结束时结束局部化区;回填值。
首部结束,回填类型及形参表地址。
? forward值,如果过函体为 forward则为 1否则为 0
子程序首部的处理例子
Procedure p(x:real ; var y, boolean ;
function f(i,j, integer), integer)
当前层数为 L,InitOff=1.则,
falsesizecodeactualparaPLroutKindvoidppEntry
L+2dirvarKindintPtri
L+2dirvarKindintPtrj
iEntry
jEntry
2L+1indirvarKindboolPtryyEntry
1L+1dirvarKindrealPtrxxEntry
3formalparaFL+1routKindintPtrffEntry
程序体部分的语义分析
? 表达式的语义分析
? 赋值语句的语义分析
? 调用语句的语义分析
? 标号语句的语义分析
? 结构语句的语义分析
表达式的语义分析
? 任务,检查运算分量的类型相容性,求表
? 达式类型。
? 分析:
? C
? V,id,Var[E],Var.id,Var?
? E op E
赋值语句的语义分析
? 任务,检查赋值相容性
? 分析步骤:
? var 的类型分析 var.Type
? E 的类型分析 E.Type
? 判定 var.Type和 E.Type是否赋值相容
调用语句的语义分析
? 任务,形实结合的相容性。函数求出返回类
型。
? 原理,P(AE1,...,AEn )
? 用 P查符号表,找出无声明错
? routkind?,找出非过 /函标识符
? Params保证个数相同,对应类型相容,类别
相同 。
结构语句的语义分析
? 问题,结构语句结束符对应多个结构语句结束。
? 解决办法,对结构化语句重新定义,使得每个结
构化语句都自带结束符 。
for i = 1 to 10 do
for j = 1 to 100 do
begin A [ i,j ] = 0 ; end ;
修改后的结构语句的定义
? Statement→ IF Expr THEN Statement FI
? Statement→ IF Expr THEN Statement ELSE
? Statement FI
? Statement→ WHILE Expr DO Statement OD
? Statement→ FOR,.............,DO Statement OD
? Statement→ BEGIN StatemenList END
修改后的 if语句的分析
? 形式,if E then S1 else S2 fi
? 分析步骤:
? ① 创建本层 LDEF,LUSE表
? ② E的分析; E.Type? boolptr
? ③ 分析 S1
? ④ 有 else 则分析 S2
? ⑤ 删掉本层 LDEF。