Part 8 作用域与块
在 Part 8 中,你的编译器需要完善对语句块和作用域的语义支持。
语法规则没有变化。
语义约束
Block
Block
表示语句块。语句块会创建作用域,语句块内声明的变量的生命周期在该语句块内。- 同一作用域中不能有同名的变量或常量。
- 语句块内可以再次定义与语句块外同名的变量或常量(通过
Decl
语句),其作用域从定义处开始到该语句块尾结束,它隐藏语句块外的同名变量或常量。
示例
样例 1
样例程序 1:
int main() {
int a = getint();
{
int b = 2;
putint(a + b);
int a = getint();
putint(a + b);
}
int b = a + 2;
putint(a + b);
return 0;
}
示例 IR 1:
declare i32 @getint()
declare void @putint(i32)
define dso_local i32 @main() {
%1 = alloca i32
%2 = alloca i32
%3 = alloca i32
%4 = alloca i32
%5 = call i32 @getint()
store i32 %5, i32* %4
store i32 2, i32* %3
%6 = load i32, i32* %4
%7 = load i32, i32* %3
%8 = add i32 %6, %7
call void @putint(i32 %8)
%9 = call i32 @getint()
store i32 %9, i32* %2
%10 = load i32, i32* %2
%11 = load i32, i32* %3
%12 = add i32 %10, %11
call void @putint(i32 %12)
%13 = load i32, i32* %4
%14 = add i32 %13, 2
store i32 %14, i32* %1
%15 = load i32, i32* %4
%16 = load i32, i32* %1
%17 = add i32 %15, %16
call void @putint(i32 %17)
ret i32 0
}
输入样例 1:
1 5
输出样例 1:
374
样例 2
样例程序 2:
int main() {
const int c1 = 10 * 5 / 2;
const int c2 = c1 / 2, c3 = c1 * 2;
if (c1 > 24) {
int c1 = 24;
putint(c2 - c1 * c3);
putch(10);
}
{
int c2 = c1 / 4;
putint(c3 / c2);
{
int c3 = c1 * 4;
putint(c3 / c2);
}
}
putch(10);
putint(c3 / c2);
return 0;
}
示例 IR 2:
declare void @putint(i32)
declare void @putch(i32)
define dso_local i32 @main() {
%1 = alloca i32
%2 = alloca i32
%3 = alloca i32
%4 = icmp sgt i32 25, 24
br i1 %4, label %5, label %9
5:
store i32 24, i32* %3
%6 = load i32, i32* %3
%7 = mul i32 %6, 50
%8 = sub i32 12, %7
call void @putint(i32 %8)
call void @putch(i32 10)
br label %9
9:
%10 = sdiv i32 25, 4
store i32 %10, i32* %2
%11 = load i32, i32* %2
%12 = sdiv i32 50, %11
call void @putint(i32 %12)
%13 = mul i32 25, 4
store i32 %13, i32* %1
%14 = load i32, i32* %1
%15 = load i32, i32* %2
%16 = sdiv i32 %14, %15
call void @putint(i32 %16)
call void @putch(i32 10)
%17 = sdiv i32 50, 12
call void @putint(i32 %17)
ret i32 0
}
输出样例 2:
-1188
816
4
样例 3
样例程序 3:
int main() {
int a = 1;
int a = 2;
return 0;
}
输出样例 3:
编译器直接以非 0 的返回值退出。