Part 11 continue、break 与代码回填

在 Part 11 中,你的编译器需要支持循环中的 continuebreak 语句。

continuebreak 不会出现在循环外。

你需要支持的语法规则如下(以 CompUnit 为开始符号):

CompUnit     -> Decl* 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 ]
                | 'while' '(' Cond ')' Stmt
                | 'break' ';'
                | 'continue' ';'
                | 'return' Exp ';' // [changed]
Exp          -> AddExp
Cond         -> LOrExp
LVal         -> Ident
PrimaryExp   -> '(' Exp ')' | LVal | Number
UnaryExp     -> PrimaryExp
                | Ident '(' [FuncRParams] ')'
                | UnaryOp UnaryExp
UnaryOp      -> '+' | '-' | '!'  // 保证 '!' 只出现在 Cond 中
FuncRParams  -> Exp { ',' Exp }
MulExp       -> UnaryExp
                | MulExp ('*' | '/' | '%') UnaryExp
AddExp       -> MulExp
                | AddExp ('+' | '-') MulExp
RelExp       -> AddExp
                | RelExp ('<' | '>' | '<=' | '>=') AddExp
EqExp        -> RelExp
                | EqExp ('==' | '!=') RelExp
LAndExp      -> EqExp
                | LAndExp '&&' EqExp
LOrExp       -> LAndExp
                | LOrExp '||' LAndExp

示例

示例 IR 中的基本块跳转有点乱,是历史遗留问题

样例 1

样例程序 1:

int main() {
    int n = getint();
    int i = 0, sum = 0;
    while (i < n) {
        if (i % 2 == 0) {
            i = i + 1;
            continue;
        }
        i = i + 1;
        sum = sum + i;
        putint(sum);
        putch(10);
    }
    return 0;
}

示例 IR 1:

declare i32 @getint()
declare void @putint(i32 )
declare void @putch(i32 )
define dso_local i32 @main() {
    %1 = alloca i32
    %2 = alloca i32
    %3 = alloca i32
    %4 = call i32 @getint()
    store i32 %4, i32* %3
    store i32 0, i32* %2
    store i32 0, i32* %1
    br label %5

5:
    %6 = load i32, i32* %2
    %7 = load i32, i32* %3
    %8 = icmp slt i32 %6, %7
    br i1 %8, label %14, label %13

9:
    %10 = load i32, i32* %2
    %11 = srem i32 %10, 2
    %12 = icmp eq i32 %11, 0
    br i1 %12, label %25, label %18

13:
    ret i32 0
14:
    br label %9

15:
    %16 = load i32, i32* %2
    %17 = add i32 %16, 1
    store i32 %17, i32* %2
    br label %5

18:
    %19 = load i32, i32* %2
    %20 = add i32 %19, 1
    store i32 %20, i32* %2
    %21 = load i32, i32* %1
    %22 = load i32, i32* %2
    %23 = add i32 %21, %22
    store i32 %23, i32* %1
    %24 = load i32, i32* %1
    call void @putint(i32 %24)
    call void @putch(i32 10)
    br label %5

25:
    br label %15
}

输入样例 1:

10

输出样例 1:

2
6
12
20
30

样例 2

样例程序 2:

int main() {
    const int ch = 48;
    int i = 1;
    while (i < 12) {
        int j = 0;
        while (1 == 1) {
            if (j % 3 == 1) {
                putch(ch + 1);
            } else {
                putch(ch);
            }
            j = j + 1;
            if (j >= 2 * i - 1)
                break;
        }
        putch(10);
        i = i + 1;
        continue; // something meaningless
    }
    return 0;
}

示例 IR 2:

declare void @putch(i32 )
define dso_local i32 @main() {
    %1 = alloca i32
    %2 = alloca i32
    store i32 1, i32* %2
    br label %3

3:
    %4 = load i32, i32* %2
    %5 = icmp slt i32 %4, 12
    br i1 %5, label %8, label %7

6:
    store i32 0, i32* %1
    br label %9

7:
    ret i32 0

8:
    br label %6

9:
    %10 = icmp eq i32 1, 1
    br i1 %10, label %18, label %15

11:
    %12 = load i32, i32* %1
    %13 = srem i32 %12, 3
    %14 = icmp eq i32 %13, 1
    br i1 %14, label %30, label %29

15:
    call void @putch(i32 10)
    %16 = load i32, i32* %2
    %17 = add i32 %16, 1
    store i32 %17, i32* %2
    br label %3

18:
    br label %11

19:
    %20 = add i32 48, 1
    call void @putch(i32 %20)
    br label %21

21:
    %22 = load i32, i32* %1
    %23 = add i32 %22, 1
    store i32 %23, i32* %1
    %24 = load i32, i32* %1
    %25 = load i32, i32* %2
    %26 = mul i32 2, %25
    %27 = sub i32 %26, 1
    %28 = icmp sge i32 %24, %27
    br i1 %28, label %33, label %32

29:
    call void @putch(i32 48)
    br label %21

30:
    br label %19

31:
    br label %15

32:
    br label %9

33:
    br label %31
}

输出样例 2:

0
010
01001
0100100
010010010
01001001001
0100100100100
010010010010010
01001001001001001
0100100100100100100
010010010010010010010

results matching ""

    No results matching ""