编译原理实验三,四语义分析通常包括:
( 1) 类型检查 。 验证程序中执行的每个操作是否遵守语言的类型系统的过程,,编译程序必须报告不符合类型系统的信息 。
( 2) 控制流检查 。 控制流语句必须使控制转移到合法的地方 。
( 3) 一致性检查 。 在很多场合要求对象只能被定义一次 。 例如 Pascal语言规定同一标识符在一个分程序中只能被说明一次等等 。
(4)名字的作用域分析语义分析
语义分析的要求请参看 <The Decaf
Language>。 例子见后。
语义分析需要用到 Bison/Yacc语言中的
,语义值类型定义,和,语义动作,使用部分。(教材附录有,不再讲述)
语义分析的例子
Type equivalence and compatibility
Two base types are equivalent if and
only if they are the same exact type,
BoolExpr,Expr { $$ =
CheckBoolExprUsage(&@1,$1); }
CheckBoolExprUsage()中检查 $1即
Expr的 type是否是 bool类型的。
变量的类型
在 pp3中我们要获得变量的类型。
在我们给的 StartFiles里面,为了简单起见,我们将 expr,SimpleStmt等也定义为 type类型。同学们可自行选择。
Scope—符号表
Scope类起到符号表的作用。在 scope.h中定义了 static Scope* stack[MaxNestLevel];
每进入一个
scope(Global,Function,Class,Local)就会在
stack顶端加入一项,退出这个 scope时就把该项退栈。 Scope内的标识符都加入 scope内部的加入 hashtable中。
退出一个 scope时,打印出这个 scope内的所有标识符及其信息 。
四种 scope
Global Scope
全局变量,类定义,main函数。
Local Scope
函数内部的临时变量。
Class Scope
类内部的成员变量和方法。
Function Scope
函数的参数。
int test(int c,int d);
void main() {
int c;
string s;
s = "hello";
c = test(4,5);
Print(c);
Print(s);
}
int test(int a,int b)
{
return a + b;
}
Exiting local scope,
Contents,
c,(line 4)
variable,type int
s,(line 5)
variable,type string
Exiting function 'main'
scope,Contents,<empty>
Exiting local scope,
Contents,<empty>
Exiting function 'test'
scope,Contents,
a,(line 13)
variable,type int
b,(line 13)
variable,type int
Exiting global scope,
Contents,
main,(line 3)
function
test,(line 13)
function
Global
Main Function Scope
Main Local Scope
main
Empty
Int c
String s
实验三要求
实验要求:完成语义分析,结果同
sample一致,扩展不做要求。
上交日期:三周以后即 12.8日晚 12:00
上载到 166.111.68.86 compiler/soft
提交方法:同以前一样。
欢迎同学用不同的方法实现相同的功能。
– 如自己设计符号表、类的实现等。
实验四 代码生成
TAC指令
Variable declarations
Assignment
Arithmetic
Relational/equality/logical
Labels and Branches
Function/method calls
Function definitions
Memory references
Array indexing
Object fields method dispatch
Miscellaneous
Data specification
简单的例子
void main (){
Print(“hello world”);
}
Main:
BeginFuncWithParams;
Var _t0;
_t0 =,hello world”;
Lcall _PrintString(_t0);
EndFunc
DeclList ->
Type -> Void
Formals ->
Constant -> stringConstant
Expr -> Constant
Expr -> Expr
PrintStmt -> Print ( ExprList )
Stmt -> PrintStmt
StmtList -> StmtList Stmt
StmtBlock -> { StmtList }
FunctionDefn -> Type
identifier ( Formals)
StmtBlock
Decl -> FunctionDefn
DeclList -> DeclList Decl
Program -> DeclList
Main:
BeginFuncWithParams;
Var _t0;
_t0 =,hello world”;
Lcall _PrintString(_t0);
EndFunc
更复杂的表达式
void main(){
int b;
Int a;
b = 3;
a = 12;
a = (b*3)/6;
}
Main:
BeginFuncWithParams;
Var b;
Var a;
Var _t0;
_t0 = 3;
b = _t0;
Var _t1;
_t1 = 12;
a = _t1;
_t2 = 3;
Var _t3;
_t3 = b * _t2;
Var _t4;
_t4 = 6;
Var _t5;
_t5 = _t3 / _t4;
a = _t5;
EndFunc
数组。 (略)
在 pp4中,我们取消 double,保留 integer,而 string
和其他对象用指针存储,所以所有的变量大小都是
4.
在计算数组的地址的时候,用公式 arr+4*i;
注意:数组的下标越界检查。
函数调用。
注意,Decaf中函数传的参数都是值参,即参数值的改变不影响原来变量的值。
类,继承
Decaf的继承比较简单。
– 每个类都有一个隐藏的 this变量。
– 子类继承所有父类的变量和方法,但是类内部变量对于除它的子类外是不可访问的。
– 如果子类要重载父类的方法,只需要实现一个和父类相同的方法就可以了。反之亦然。
– 类只能在 global scope中实现。
实验要求
说明:
6周以后,即 16周末 12:00之前上交。
识别 run time error对正确的 decaf文件能够生成 Tac代码。
Pp3提交以后交给大家 pp4的 start files,但是同学也可以在 pp3的基础上直接完成,需要注意的是部分文件可能需要改动。
Sample文件 —大家自己生成吧,可以先用例子里的程序。
参考资料。