@@ -16,43 +16,43 @@ define i32 @main() {
16
16
17
17
如果将输入的` 1+3-2 ` 转化为` []string{"1", "+", "3", "-", "2"} ` 形式,我们则可以通过以下代码输出对应的汇编程序:
18
18
19
- ``` go
20
- func gen_asm (tokens []string ) string {
21
- var buf bytes.Buffer
22
- fmt.Fprintln (&buf, ` define i32 @main() {` )
19
+ ``` wa
23
20
24
- var idx int
21
+ func genAsm(tokens: []string) => string {
22
+ sb: strings.Builder
23
+ sb.WriteString("define i32 @main() {\n")
24
+
25
+ idx: int
25
26
for i, tok := range tokens {
26
27
if i == 0 {
27
- fmt.Fprintf (&buf, " \t %% t%d = add i32 0, %v \n " ,
28
- idx, tokens[i],
29
- )
28
+ t0 := "%t" + strconv.Itoa(idx)
29
+ sb.WriteString("\t" + t0 + " = add i32 0, " + tokens[i] + "\n")
30
30
continue
31
31
}
32
32
switch tok {
33
33
case "+":
34
34
idx++
35
- fmt. Fprintf (&buf, " \t %% t %d = add i32 %% t %d , %v \n " ,
36
- idx, idx-1 , tokens[i+ 1 ],
37
- )
35
+ t0 := "%t" + strconv.Itoa(idx)
36
+ t1 := "%t" + strconv.Itoa( idx-1)
37
+ sb.WriteString("\t" + t0 + " = add i32 " + t1 + ", " + tokens[i+1] + "\n" )
38
38
case "-":
39
39
idx++
40
- fmt. Fprintf (&buf, " \t %% t %d = sub i32 %% t %d , %v \n " ,
41
- idx, idx-1 , tokens[i+ 1 ],
42
- )
40
+ t0 := "%t" + strconv.Itoa(idx)
41
+ t1 := "%t" + strconv.Itoa( idx-1)
42
+ sb.WriteString("\t" + t0 + " = sub i32 " + t1 + ", " + tokens[i+1] + "\n" )
43
43
}
44
44
}
45
- fmt. Fprintf (&buf, " \t ret i32 %% t %d \n " , idx)
46
- fmt. Fprintln (&buf, ` }` )
45
+ sb.WriteString( "\tret i32 %t" + strconv.Itoa( idx) + "\n" )
46
+ sb.WriteString( `}`)
47
47
48
- return buf .String ()
48
+ return sb .String()
49
49
}
50
50
```
51
51
52
52
而如何将输入的字符串拆分为记号数组本质上属于词法分析的问题。我们先以最简单的方式实现:
53
53
54
- ``` go
55
- func parse_tokens (code string ) (tokens []string ) {
54
+ ``` wa
55
+ func parseTokens (code: string) => (tokens: []string) {
56
56
for code != "" {
57
57
if idx := strings.IndexAny(code, "+-"); idx >= 0 {
58
58
if idx > 0 {
@@ -74,62 +74,28 @@ func parse_tokens(code string) (tokens []string) {
74
74
75
75
然后对上个版本的compile函数稍加改造以支持加法和减法的运算表达式编译:
76
76
77
- ``` go
78
- func compile (code string ) {
79
- tokens := parse_tokens (code)
80
- output := gen_asm (tokens)
81
-
82
- os.WriteFile (" a.out.ll" , []byte (output), 0666 )
83
- exec.Command (" clang" , " -Wno-override-module" , " -o" , " a.out" , " a.out.ll" ).Run ()
84
- }
85
- ```
86
-
87
- 为了便于测试,我们再包装一个run函数:
88
-
89
- ``` go
90
- func run (code string ) int {
91
- compile (code)
92
- if err := exec.Command (" ./a.out" ).Run (); err != nil {
93
- return err.(*exec.ExitError ).ExitCode ()
94
- }
95
- return 0
77
+ ``` wa
78
+ func compile(code: string) {
79
+ tokens := parseTokens(code)
80
+ output := genAsm(tokens)
81
+ println(output)
96
82
}
97
83
```
98
84
99
- run函数将输入的表达式程序编译并运行、最后返回状态码。然后构造单元测试:
100
-
101
- ``` go
102
- func TestRun (t *testing .T ) {
103
- for i , tt := range tests {
104
- if got := run (tt.code ); got != tt.value {
105
- t.Fatalf (" %d : expect = %v , got = %v " , i, tt.value , got)
106
- }
107
- }
108
- }
109
-
110
- var tests = []struct {
111
- code string
112
- value int
113
- }{
114
- {code: " 1" , value: 1 },
115
- {code: " 1+1" , value: 2 },
116
- {code: " 1 + 3 - 2 " , value: 2 },
117
- {code: " 1+2+3+4" , value: 10 },
118
- }
119
- ```
120
85
121
- 确认单元测试没有问题后, 更新main函数:
86
+ 更新main函数:
122
87
123
- ``` go
124
- func main () {
125
- code , _ := io.ReadAll (os.Stdin )
126
- fmt.Println (run (string (code)))
88
+ ``` wa
89
+ func main {
90
+ compile(`1+2+3`)
127
91
}
128
92
```
129
93
130
94
通过以下命令执行:
131
95
132
96
```
133
- $ echo "1+2+3" | go run main.go
97
+ $ wa run main.wa > _main.ll
98
+ $ clang -Wno-override-module -o a.out _main.ll
99
+ $ ./a.out || echo $?
134
100
6
135
101
```
0 commit comments