if 流程控制


雖然可以使用 block 來達到程式語言中 if 的效果,然而,Wat 本身就提供有 if,它與 block 同屬於區塊的一種,因此看不到區塊前對堆疊的置入的數值,可以定義結果型態,若沒有定義,那離開區塊前必須清空堆疊。

if 會從堆疊中取出一個數值,若不為 0 就執行 if 區塊,否則執行 else 區塊,因此底下顯示 10:

(module
    (import "env" "log" (func $log (param i32)))
    (func $main
        i32.const 1
        if (result i32)
            i32.const 10
        else
            i32.const 20
        end
        call $log
    )
    (start $main)
)

若不需要 else,可以省略,例如,底下先將變數 $var 設為 10,若 if 成立,將 $var 設為 20:

(module
    (import "env" "log" (func $log (param i32)))
    (func $main
        (local $var i32)
        (set_local $var (i32.const 10))
        i32.const 1
        if
            (set_local $var (i32.const 20))
        end
        get_local $var
        call $log
    )
    (start $main)
)

if 區塊也可以如同 block 一樣設定標籤,可以使用 brbr_if 來進行分支流程:

(module
    (import "env" "log" (func $log (param i32)))
    (func $main
        i32.const 1
        if $IF0
            i32.const 1
            if $IF1
                br $IF1
            else
                br $IF0
            end
            i32.const 10
            call $log
        end
        i32.const 20
        call $log
    )
    (start $main)
)

if 可以與 block 搭配:

(module
    (import "env" "log" (func $log (param i32)))
    (func $main
        block $IF0
            i32.const 1
            if $IF1
                br $IF1
            else
                br $IF0
            end
            i32.const 10
            call $log
        end
        i32.const 20
        call $log
    )
    (start $main)
)

在〈區塊與分支〉中談過,block 可以用來搭配 ifloop 等,上面是個範例,實際上區塊的語法,還可以進一步使用 S 運算式的風格來撰寫。

例如,對於底下的 C 程式:

#include <stdio.h>

int main() {
    int a = 10;
    int b = 20;
    if((a - b) == 10) {
         printf("%d", 1);
    }
    else {
        printf("%d", 0);
    }
}

要寫個對等的 Wat,中規中矩的寫法是:

(module
    (import "env" "log" (func $log (param i32)))
    (func $main
        (local $a i32) (local $b i32)
        i32.const 10
        tee_local $a
        i32.const 20
        tee_local $b
        i32.sub
        i32.const 10
        i32.eq      
        if
            i32.const 1
            call $log
        else
            i32.const 0
            call $log
        end
    )
    (start $main)
)

使用 S 運算式,搭配 block 等來寫的話可以是:

(module
    (import "env" "log" (func $log (param i32)))
    (func $main
        (local $a i32) (local $b i32)
        (set_local $a (i32.const 10))
        (set_local $b (i32.const 20))
        (if (block (result i32)
                (i32.eq 
                    (i32.sub (get_local $a) (get_local $b)) 
                    (i32.const 10)
                )   
            )
            (then
                i32.const 1
                call $log)
            (else
                i32.const 0
                call $log)
        )
    )
    (start $main)
)

可以看到 block 的另一應用,是將一組操作組織在一起,透過適當的 S 運算式排列,會比較接近高階語言的寫法,留意 if 的 S 運算式寫法,條件成立時必須寫在 then 之中,不成立時寫在 else 之中。