本次实验中,你的编译器需要支持 if
、else
条件分支语句以及条件表达式。
你需要支持的语法规则如下(以 CompUnit
为开始符号):
CompUnit -> FuncDef
Decl -> ConstDecl | VarDecl
ConstDecl -> 'const' BType ConstDef { ',' ConstDef } ';'
BType -> 'int'
ConstDef -> Ident '=' ConstInitVal
ConstInitVal -> ConstExp
ConstExp -> AddExp
VarDecl -> BType VarDef { ',' VarDef } ';'
VarDef -> Ident
| Ident '=' InitVal
InitVal -> Exp
FuncDef -> FuncType Ident '(' ')' Block // 保证当前 Ident 只为 "main"
FuncType -> 'int'
Block -> '{' { BlockItem } '}'
BlockItem -> Decl | Stmt
Stmt -> LVal '=' Exp ';'
| Block
| [Exp] ';'
| 'if' '(' Cond ')' Stmt [ 'else' Stmt ]
| 'return' Exp ';' // [changed]
Exp -> AddExp
Cond -> LOrExp // [new]
LVal -> Ident
PrimaryExp -> '(' Exp ')' | LVal | Number
UnaryExp -> PrimaryExp
| Ident '(' [FuncRParams] ')'
| UnaryOp UnaryExp
UnaryOp -> '+' | '-' | '!' // 保证 '!' 只出现在 Cond 中 [changed]
FuncRParams -> Exp { ',' Exp }
MulExp -> UnaryExp
| MulExp ('*' | '/' | '%') UnaryExp
AddExp -> MulExp
| AddExp ('+' | '-') MulExp
RelExp -> AddExp
| RelExp ('<' | '>' | '<=' | '>=') AddExp // [new]
EqExp -> RelExp
| EqExp ('==' | '!=') RelExp // [new]
LAndExp -> EqExp
| LAndExp '&&' EqExp // [new]
LOrExp -> LAndExp
| LOrExp '||' LAndExp // [new]
注:
Cond
中的短路求值在基础实验中不作要求,挑战实验中会有相关内容。- 本部分的测试用例中不会出现对
Stmt -> Block
的变量作用域、生命周期等相关的考察。 Stmt
中的if
语句遵循就近匹配,即if if else
等同于if { if else }
。- 值不为 0 的
Cond
表示true
,值为 0 的Cond
表示false
。
示例 IR 中的基本块跳转有点乱,是历史遗留问题
样例程序 1:
int main() {
int a = getint();
int b = getint();
if (a <= b) {
putint(1);
}
else {
putint(0);
}
return 0;
}
示例 IR 1:
declare i32 @getint()
declare void @putint(i32)
define dso_local i32 @main() {
%1 = alloca i32
%2 = alloca i32
%3 = call i32 @getint()
store i32 %3, i32* %2
%4 = call i32 @getint()
store i32 %4, i32* %1
%5 = load i32, i32* %2
%6 = load i32, i32* %1
%7 = icmp sle i32 %5, %6
br i1 %7,label %8, label %10
8:
call void @putint(i32 1)
br label %9
9:
ret i32 0
10:
call void @putint(i32 0)
br label %9
}
输入样例 1:
9 12
输出样例 1:
1
样例程序 2:
int main() {
int a, b, c = 1, d;
int result;
a = 5;
b = 5;
d = -2;
result = 2;
if (a + b + c + d == 10) {
result = result + 1;
} else if (a + b + c + d == 8) {
result = result + 2;
} else {
result = result + 4;
}
putint(result);
return 0;
}
示例 IR 2:
declare void @putint(i32)
define dso_local i32 @main(){
%1 = alloca i32
%2 = alloca i32
%3 = alloca i32
%4 = alloca i32
%5 = alloca i32
store i32 1, i32* %3
store i32 5, i32* %5
store i32 5, i32* %4
%6 = sub i32 0, 2
store i32 %6, i32* %2
store i32 2, i32* %1
%7 = load i32, i32* %5
%8 = load i32, i32* %4
%9 = add i32 %7, %8
%10 = load i32, i32* %3
%11 = add i32 %9, %10
%12 = load i32, i32* %2
%13 = add i32 %11, %12
%14 = icmp eq i32 %13, 10
br i1 %14, label %29, label %20
15:
%16 = load i32, i32* %1
%17 = add i32 %16, 1
store i32 %17, i32* %1
br label %18
18:
%19 = load i32, i32* %1
call void @putint(i32 %19)
ret i32 0
20:
%21 = load i32, i32* %5
%22 = load i32, i32* %4
%23 = add i32 %21, %22
%24 = load i32, i32* %3
%25 = add i32 %23, %24
%26 = load i32, i32* %2
%27 = add i32 %25, %26
%28 = icmp eq i32 %27, 8
br i1 %28, label %37, label %34
29:
br label %15
30:
%31 = load i32, i32* %1
%32 = add i32 %31, 2
store i32 %32, i32* %1
br label %33
33:
br label %18
34:
%35 = load i32, i32* %1
%36 = add i32 %35, 4
store i32 %36, i32* %1
br label %33
37:
br label %30
}
输出样例 2:
6
样例程序 3:
int main() {
int a, b, c = 1, d;
int result;
a = 5;
b = 5;
d = -2;
result = 2;
if (a + b == 9 || a - b == 0 && result != 4)
result = result + 3;
else if (c + d != -1 || (result + 1) % 2 == 1)
result = result + 4;
putint(result);
return 0;
}
示例 IR 3:
declare void @putint(i32)
define dso_local i32 @main() {
%1 = alloca i32
%2 = alloca i32
%3 = alloca i32
%4 = alloca i32
%5 = alloca i32
store i32 1, i32* %3
store i32 5, i32* %5
store i32 5, i32* %4
%6 = sub i32 0, 2
store i32 %6, i32* %2
store i32 2, i32* %1
%7 = load i32, i32* %5
%8 = load i32, i32* %4
%9 = add i32 %7, %8
%10 = icmp eq i32 %9, 9
br i1 %10, label %27, label %22
11:
%12 = load i32, i32* %1
%13 = add i32 %12, 3
store i32 %13, i32* %1
br label %14
14:
%15 = load i32, i32* %1
call void @putint(i32 %15)
ret i32 0
16:
%17 = load i32, i32* %3
%18 = load i32, i32* %2
%19 = add i32 %17, %18
%20 = sub i32 0, 1
%21 = icmp ne i32 %19, %20
br i1 %21, label %41, label %36
22:
%23 = load i32, i32* %5
%24 = load i32, i32* %4
%25 = sub i32 %23, %24
%26 = icmp eq i32 %25, 0
br i1 %26, label %28, label %16
27:
br label %11
28:
%29 = load i32, i32* %1
%30 = icmp ne i32 %29, 4
br i1 %30, label %31, label %16
31:
br label %11
32:
%33 = load i32, i32* %1
%34 = add i32 %33, 4
store i32 %34, i32* %1
br label %35
35:
br label %14
36:
%37 = load i32, i32* %1
%38 = add i32 %37, 1
%39 = srem i32 %38, 2
%40 = icmp eq i32 %39, 1
br i1 %40, label %42, label %35
41:
br label %32
42:
br label %32
}
输出样例 3:
5
样例程序 4:
int main() {
int a;
a = 10;
if (+-!!!a) {
a = - - -1;
}
else {
a = 0;
}
putint(a);
return 0;
}
示例 IR 4:
declare void @putint(i32)
define dso_local i32 @main() {
%1 = alloca i32
store i32 10, i32* %1
%2 = load i32, i32* %1
%3 = icmp eq i32 %2, 0
%4 = zext i1 %3 to i32
%5 = icmp eq i1 %3, 0
%6 = zext i1 %5 to i32
%7 = icmp eq i1 %5, 0
%8 = zext i1 %7 to i32
%9 = zext i1 %7 to i32
%10 = sub i32 0, %9
%11 = icmp ne i32 %10, 0
br i1 %11, label %12, label %18
12:
%13 = sub i32 0, 1
%14 = sub i32 0, %13
%15 = sub i32 0, %14
store i32 %15, i32* %1
br label %16
16:
%17 = load i32, i32* %1
call void @putint(i32 %17)
ret i32 0
18:
store i32 0, i32* %1
br label %16
}
输出样例 4:
0