codecin 5.4.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. codecin/__init__.py +27 -0
  2. codecin/aot.py +229 -0
  3. codecin/assembler.py +548 -0
  4. codecin/cache.py +71 -0
  5. codecin/cin.py +2558 -0
  6. codecin/cli.py +282 -0
  7. codecin/config.py +58 -0
  8. codecin/console.py +183 -0
  9. codecin/cpu.py +1654 -0
  10. codecin/crom.py +222 -0
  11. codecin/debugger.py +659 -0
  12. codecin/disasm.py +86 -0
  13. codecin/errors.py +58 -0
  14. codecin/isa.py +457 -0
  15. codecin/jit.py +270 -0
  16. codecin/libcodecin_native.so +0 -0
  17. codecin/logger.py +145 -0
  18. codecin/memory.py +348 -0
  19. codecin/native/aot/aot.go +70 -0
  20. codecin/native/aot/build.go +219 -0
  21. codecin/native/aot/stub_main.go.txt +22 -0
  22. codecin/native/build.ps1 +33 -0
  23. codecin/native/build.sh +48 -0
  24. codecin/native/cmd/codecin/main.go +287 -0
  25. codecin/native/compiler/codegen.go +1938 -0
  26. codecin/native/compiler/compile_test.go +164 -0
  27. codecin/native/compiler/parser.go +1071 -0
  28. codecin/native/compiler/syscalls.go +86 -0
  29. codecin/native/compiler/tokenizer.go +336 -0
  30. codecin/native/compiler/types.go +213 -0
  31. codecin/native/engine/audio.go +152 -0
  32. codecin/native/engine/audio_other.go +46 -0
  33. codecin/native/engine/audio_windows.go +43 -0
  34. codecin/native/engine/canvas.go +271 -0
  35. codecin/native/engine/crom.go +86 -0
  36. codecin/native/engine/encode.go +93 -0
  37. codecin/native/engine/engine_test.go +198 -0
  38. codecin/native/engine/isa_gen.go +445 -0
  39. codecin/native/engine/system.go +190 -0
  40. codecin/native/engine/termux.go +113 -0
  41. codecin/native/engine/version_gen.go +7 -0
  42. codecin/native/engine/vm.go +1157 -0
  43. codecin/native/go.mod +3 -0
  44. codecin/native/ir/ir.go +48 -0
  45. codecin/native/main.go +225 -0
  46. codecin/native.py +336 -0
  47. codecin/registers.py +130 -0
  48. codecin/stats.py +235 -0
  49. codecin-5.4.2.dist-info/METADATA +985 -0
  50. codecin-5.4.2.dist-info/RECORD +54 -0
  51. codecin-5.4.2.dist-info/WHEEL +5 -0
  52. codecin-5.4.2.dist-info/entry_points.txt +2 -0
  53. codecin-5.4.2.dist-info/licenses/LICENSE +7 -0
  54. codecin-5.4.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1938 @@
1
+ package compiler
2
+
3
+ import (
4
+ "encoding/binary"
5
+ "fmt"
6
+ "math"
7
+ "os"
8
+ "path/filepath"
9
+ "regexp"
10
+ "strings"
11
+
12
+ "codecin-native/ir"
13
+ )
14
+
15
+ // ---------------- 代码生成 ----------------
16
+
17
+ // hostBuiltin 宿主能力内建 (表驱动): 名称 -> (SYS 号, 参数个数, 返回类型)。
18
+ type hostBuiltin struct {
19
+ sysID int64
20
+ nargs int
21
+ ret TypeKind
22
+ }
23
+
24
+ var hostBuiltins = map[string]hostBuiltin{
25
+ // 联网音频
26
+ "audio_play": {SysAUDIOPLAY, 1, kInt},
27
+ "audio_stop": {SysAUDIOSTOP, 0, kVoid},
28
+ "audio_volume": {SysAUDIOVOL, 1, kVoid},
29
+ "audio_wait": {SysAUDIOWAIT, 0, kVoid},
30
+ // 2D 绘图画布
31
+ "canvas": {SysCANVASNEW, 2, kVoid},
32
+ "set_color": {SysCANVASSET, 1, kVoid},
33
+ "fill_rect": {SysCANVASRECT, 4, kVoid},
34
+ "fill_circle": {SysCANVASCIRC, 3, kVoid},
35
+ "draw_line": {SysCANVASLINE, 4, kVoid},
36
+ "draw_text": {SysCANVASTEXT, 3, kVoid},
37
+ "save_png": {SysCANVASSAVE, 1, kInt},
38
+ "show_canvas": {SysCANVASSHOW, 0, kInt},
39
+ // 系统原生交互 (跨平台)
40
+ "file_read": {SysFILEREAD, 1, kString},
41
+ "file_write": {SysFILEWRITE, 2, kInt},
42
+ "file_append": {SysFILEAPPEND, 2, kInt},
43
+ "file_exists": {SysFILEEXISTS, 1, kInt},
44
+ "file_delete": {SysFILEDELETE, 1, kInt},
45
+ "file_size": {SysFILESIZE, 1, kInt},
46
+ "mkdir": {SysMKDIR, 1, kInt},
47
+ "dir_list": {SysDIRLIST, 1, kString},
48
+ "exec": {SysEXEC, 1, kInt},
49
+ "exec_output": {SysEXECOUTPUT, 1, kString},
50
+ "getenv": {SysGETENV, 1, kString},
51
+ "setenv": {SysSETENV, 2, kInt},
52
+ "os_name": {SysOSNAME, 0, kString},
53
+ "hostname": {SysHOSTNAME, 0, kString},
54
+ "username": {SysUSERNAME, 0, kString},
55
+ "cwd": {SysCWD, 0, kString},
56
+ "home_dir": {SysHOMEDIR, 0, kString},
57
+ // Termux API
58
+ "termux_available": {SysTERMUXAVAIL, 0, kInt},
59
+ "termux_notify": {SysTERMUXNOTIFY, 2, kInt},
60
+ "termux_toast": {SysTERMUXTOAST, 1, kInt},
61
+ "termux_clipboard_get": {SysTERMUXCLIPGET, 0, kString},
62
+ "termux_clipboard_set": {SysTERMUXCLIPSET, 1, kInt},
63
+ "termux_battery": {SysTERMUXBATTERY, 0, kString},
64
+ "termux_vibrate": {SysTERMUXVIBRATE, 1, kInt},
65
+ "termux_tts": {SysTERMUXTTS, 1, kInt},
66
+ "termux_location": {SysTERMUXLOCATION, 0, kString},
67
+ "termux_wifi_info": {SysTERMUXWIFI, 0, kString},
68
+ "termux_dialog": {SysTERMUXDIALOG, 1, kString},
69
+ "termux_sms_send": {SysTERMUXSMS, 2, kInt},
70
+ }
71
+
72
+ func (c *compiler) emit(op string, args ...ir.Operand) {
73
+ c.res.Instructions = append(c.res.Instructions, ir.Instr{Op: op, Args: args})
74
+ }
75
+
76
+ // failf 记录第一条语义错误 (粘性), 由 Compile 在生成结束后统一返回。
77
+ // 错误文案与 Python 编译器 (codecin/cin.py) 保持一致, 便于差分测试断言。
78
+ func (c *compiler) failf(format string, args ...interface{}) {
79
+ if c.err == nil {
80
+ c.err = fmt.Errorf(format, args...)
81
+ }
82
+ }
83
+
84
+ func (c *compiler) label(name string) {
85
+ c.res.Labels[name] = len(c.res.Instructions)
86
+ }
87
+
88
+ func (c *compiler) newLabel(hint string) string {
89
+ c.labelCounter++
90
+ return fmt.Sprintf("_%s_%d", hint, c.labelCounter)
91
+ }
92
+
93
+ func (c *compiler) reg(n int) ir.Operand { return ir.Reg(n) }
94
+ func (c *compiler) imm(v int64) ir.Operand { return ir.Imm(v) }
95
+ func (c *compiler) lab(name string) ir.Operand { return ir.Label(name) }
96
+
97
+ // ---------------- 数据段 ----------------
98
+
99
+ func (c *compiler) allocData(nbytes, align int) int {
100
+ if align > 1 {
101
+ c.dataPtr = (c.dataPtr + align - 1) &^ (align - 1)
102
+ }
103
+ addr := c.dataPtr
104
+ c.dataPtr += nbytes
105
+ return addr
106
+ }
107
+
108
+ func (c *compiler) dataString(text string) int {
109
+ if addr, ok := c.heapStr[text]; ok {
110
+ return addr
111
+ }
112
+ data := append([]byte(text), 0)
113
+ addr := c.allocData(len(data), 1)
114
+ c.res.DataWrites = append(c.res.DataWrites, ir.DataWrite{Addr: addr, Data: data})
115
+ c.res.DataLabels[fmt.Sprintf("str_%x", addr)] = addr
116
+ c.heapStr[text] = addr
117
+ return addr
118
+ }
119
+
120
+ func (c *compiler) dataQword(value int64) int {
121
+ addr := c.allocData(8, 8)
122
+ var b [8]byte
123
+ binary.LittleEndian.PutUint64(b[:], uint64(value))
124
+ c.res.DataWrites = append(c.res.DataWrites, ir.DataWrite{Addr: addr, Data: b[:]})
125
+ return addr
126
+ }
127
+
128
+ func (c *compiler) layoutGlobals(globals []*GlobalVar) {
129
+ for _, gv := range globals {
130
+ t := gv.t
131
+ if isFixedArray(t) {
132
+ addr := c.allocData(typeSlots(t)*8, 8)
133
+ c.globalsSym[gv.name] = globalVar{t: t, addr: addr, isBlock: true}
134
+ gv.addr = addr
135
+ } else {
136
+ addr := c.allocData(8, 8)
137
+ c.globalsSym[gv.name] = globalVar{t: t, addr: addr, isBlock: false}
138
+ gv.addr = addr
139
+ if isStruct(t) {
140
+ sd := c.structs[t.Name]
141
+ block := c.allocData(sd.sizeSlots*8, 8)
142
+ var b [8]byte
143
+ binary.LittleEndian.PutUint64(b[:], uint64(block))
144
+ c.res.DataWrites = append(c.res.DataWrites, ir.DataWrite{Addr: addr, Data: b[:]})
145
+ }
146
+ }
147
+ }
148
+ }
149
+
150
+ // constValue 编译期常量求值, 返回 (类型, 原始位/地址)。
151
+ func (c *compiler) constValue(n *Node) (*Type, int64, error) {
152
+ switch n.Kind {
153
+ case "num":
154
+ if n.IsFloat {
155
+ return scalarT(kFloat), int64(math.Float64bits(n.Num)), nil
156
+ }
157
+ return scalarT(kInt), n.Ival, nil
158
+ case "bool":
159
+ v := int64(0)
160
+ if n.Bool {
161
+ v = 1
162
+ }
163
+ return scalarT(kBool), v, nil
164
+ case "str":
165
+ return scalarT(kString), int64(c.dataString(n.Str)), nil
166
+ case "neg":
167
+ inner := n.A
168
+ if inner.Kind == "num" {
169
+ if inner.IsFloat {
170
+ return scalarT(kFloat), int64(math.Float64bits(-inner.Num)), nil
171
+ }
172
+ return scalarT(kInt), -inner.Ival, nil
173
+ }
174
+ case "bitnot":
175
+ ct, raw, err := c.constValue(n.A)
176
+ if err != nil {
177
+ return nil, 0, err
178
+ }
179
+ if ct.Kind != kInt && ct.Kind != kBool {
180
+ return nil, 0, fmt.Errorf("Bitwise NOT requires integer, got: %s", typeName(ct))
181
+ }
182
+ return scalarT(kInt), ^raw, nil
183
+ }
184
+ return nil, 0, fmt.Errorf("Non-constant global initializer: %s", n.Kind)
185
+ }
186
+
187
+ func (c *compiler) emitGlobalsInit(globals []*GlobalVar) {
188
+ for _, gv := range globals {
189
+ addr := c.globalsSym[gv.name].addr
190
+ if gv.init != nil {
191
+ _, raw, err := c.constValue(gv.init)
192
+ if err == nil {
193
+ var b [8]byte
194
+ binary.LittleEndian.PutUint64(b[:], uint64(raw))
195
+ c.res.DataWrites = append(c.res.DataWrites, ir.DataWrite{Addr: addr, Data: b[:]})
196
+ }
197
+ } else if gv.arrayLit != nil {
198
+ lit := gv.arrayLit
199
+ if lit.Is2D {
200
+ for i, row := range lit.ArrayLit {
201
+ for j, elem := range row {
202
+ _, raw, err := c.constValue(elem)
203
+ if err != nil {
204
+ continue
205
+ }
206
+ var b [8]byte
207
+ binary.LittleEndian.PutUint64(b[:], uint64(raw))
208
+ off := addr + (i*len(row)+j)*8
209
+ c.res.DataWrites = append(c.res.DataWrites, ir.DataWrite{Addr: off, Data: b[:]})
210
+ }
211
+ }
212
+ } else {
213
+ for i, elem := range lit.ArrayLit[0] {
214
+ _, raw, err := c.constValue(elem)
215
+ if err != nil {
216
+ continue
217
+ }
218
+ var b [8]byte
219
+ binary.LittleEndian.PutUint64(b[:], uint64(raw))
220
+ c.res.DataWrites = append(c.res.DataWrites, ir.DataWrite{Addr: addr + i*8, Data: b[:]})
221
+ }
222
+ }
223
+ }
224
+ }
225
+ }
226
+
227
+ // ---------------- 函数生成 ----------------
228
+
229
+ // genFunctionBody 生成函数体 (locals 带名字)。
230
+ func (c *compiler) genFunctionBody(f *FuncDef) {
231
+ c.funcDef = f
232
+ c.locals = map[string]localVar{}
233
+ c.breakLbls = nil
234
+ c.continueLbls = nil
235
+
236
+ localsInfo := c.prescanLocalsWithNames(f.body)
237
+ off := 0
238
+ for _, lv := range localsInfo {
239
+ slots := typeSlots(lv.t)
240
+ c.locals[lv.name] = localVar{t: lv.t, off: -(off + slots*8), isBlock: isFixedArray(lv.t)}
241
+ off += slots * 8
242
+ }
243
+ c.frameBytes = off
244
+
245
+ nargs := len(f.params)
246
+ for k, prm := range f.params {
247
+ poff := 16 + (nargs-1-k)*8
248
+ c.locals[prm.name] = localVar{t: prm.t, off: poff, isBlock: false}
249
+ }
250
+
251
+ c.label(f.name)
252
+ c.emit("PUSH", c.reg(29))
253
+ c.emit("MOV", c.reg(29), c.reg(32))
254
+ if c.frameBytes != 0 {
255
+ c.emit("ADDI", c.reg(0), c.reg(32), c.imm(int64(-c.frameBytes)))
256
+ c.emit("MOV", c.reg(32), c.reg(0))
257
+ }
258
+
259
+ // struct 局部变量: 堆分配对象
260
+ for _, lv := range c.locals {
261
+ if isStruct(lv.t) && lv.off < 0 {
262
+ sd := c.structs[lv.t.Name]
263
+ c.emit("MOV", c.reg(0), c.imm(int64(sd.sizeSlots*8)))
264
+ c.emit("SYS", c.imm(SysMALLOC))
265
+ c.emit("MOV", c.reg(2), c.reg(0))
266
+ c.addrLocal(lv.off)
267
+ c.emit("SD", c.reg(2), ir.Mem(0, 0))
268
+ }
269
+ }
270
+
271
+ c.genStmts(f.body)
272
+ c.epilogue()
273
+ }
274
+
275
+ type namedLocal struct {
276
+ name string
277
+ t *Type
278
+ }
279
+
280
+ func (c *compiler) prescanLocalsWithNames(body []*Node) []namedLocal {
281
+ var found []namedLocal
282
+ seen := map[string]bool{}
283
+ var walk func([]*Node)
284
+ walk = func(stmts []*Node) {
285
+ for _, s := range stmts {
286
+ switch s.Kind {
287
+ case "decl":
288
+ for _, item := range s.List {
289
+ if seen[item.Name] {
290
+ continue
291
+ }
292
+ seen[item.Name] = true
293
+ found = append(found, namedLocal{name: item.Name, t: item.Type})
294
+ }
295
+ case "block":
296
+ walk(s.List)
297
+ case "if":
298
+ walk([]*Node{s.B})
299
+ if s.C != nil {
300
+ walk([]*Node{s.C})
301
+ }
302
+ case "while":
303
+ walk([]*Node{s.B})
304
+ case "dowhile":
305
+ walk([]*Node{s.A})
306
+ case "switch":
307
+ for _, br := range s.List {
308
+ walk(br.List)
309
+ }
310
+ case "for":
311
+ if s.A != nil && s.A.Kind == "decl" {
312
+ for _, item := range s.A.List {
313
+ if !seen[item.Name] {
314
+ seen[item.Name] = true
315
+ found = append(found, namedLocal{name: item.Name, t: item.Type})
316
+ }
317
+ }
318
+ }
319
+ walk([]*Node{s.D})
320
+ }
321
+ }
322
+ }
323
+ walk(body)
324
+ return found
325
+ }
326
+
327
+ func (c *compiler) epilogue() {
328
+ c.emit("MOV", c.reg(6), c.reg(29))
329
+ c.emit("MOV", c.reg(32), c.reg(6))
330
+ c.emit("POP", c.reg(29))
331
+ c.emit("RET")
332
+ }
333
+
334
+ func (c *compiler) addrLocal(off int) {
335
+ if off == 0 {
336
+ c.emit("MOV", c.reg(0), c.reg(29))
337
+ } else {
338
+ c.emit("ADDI", c.reg(0), c.reg(29), c.imm(int64(off)))
339
+ }
340
+ }
341
+
342
+ func (c *compiler) addrVar(name string) error {
343
+ if lv, ok := c.locals[name]; ok {
344
+ c.addrLocal(lv.off)
345
+ return nil
346
+ }
347
+ if gv, ok := c.globalsSym[name]; ok {
348
+ c.emit("MOV", c.reg(0), c.imm(int64(gv.addr)))
349
+ return nil
350
+ }
351
+ return fmt.Errorf("Undefined variable: %s", name)
352
+ }
353
+
354
+ // mustAddrVar 是 addrVar 的报错版本: 未定义变量不再被静默吞掉。
355
+ func (c *compiler) mustAddrVar(name string) {
356
+ if err := c.addrVar(name); err != nil {
357
+ c.failf("%v", err)
358
+ }
359
+ }
360
+
361
+ func (c *compiler) varType(name string) *Type {
362
+ if lv, ok := c.locals[name]; ok {
363
+ return lv.t
364
+ }
365
+ if gv, ok := c.globalsSym[name]; ok {
366
+ return gv.t
367
+ }
368
+ return nil
369
+ }
370
+
371
+ // ---------------- 语句 ----------------
372
+
373
+ func (c *compiler) genStmts(stmts []*Node) {
374
+ for _, s := range stmts {
375
+ c.genStmt(s)
376
+ }
377
+ }
378
+
379
+ func (c *compiler) genStmt(s *Node) {
380
+ switch s.Kind {
381
+ case "block":
382
+ c.genStmts(s.List)
383
+ case "return":
384
+ if s.A != nil {
385
+ t := c.genValue(s.A)
386
+ c.convert(t, c.funcDef.retType)
387
+ }
388
+ c.epilogue()
389
+ case "if":
390
+ c.genIf(s.A, s.B, s.C)
391
+ case "while":
392
+ c.genWhile(s.A, s.B)
393
+ case "for":
394
+ c.genFor(s.A, s.B, s.C, s.D)
395
+ case "dowhile":
396
+ c.genDowhile(s.A, s.B)
397
+ case "switch":
398
+ c.genSwitch(s.A, s.List)
399
+ case "break":
400
+ if len(c.breakLbls) == 0 {
401
+ c.failf("break outside loop")
402
+ return
403
+ }
404
+ c.emit("JMP", c.lab(c.breakLbls[len(c.breakLbls)-1]))
405
+ case "continue":
406
+ if len(c.continueLbls) == 0 {
407
+ c.failf("continue outside loop")
408
+ return
409
+ }
410
+ c.emit("JMP", c.lab(c.continueLbls[len(c.continueLbls)-1]))
411
+ case "decl":
412
+ c.genDecl(s.List)
413
+ case "cpu":
414
+ c.genCpuStmt(s.Name, s.Operands)
415
+ case "assert":
416
+ c.genAssert(s.A, s.B, s.Int, s.Filename)
417
+ case "expr":
418
+ c.genExprStmt(s.A)
419
+ }
420
+ }
421
+
422
+ func (c *compiler) genIf(cond, thenBody, elseBody *Node) {
423
+ lElse := c.newLabel("else")
424
+ lEnd := c.newLabel("endif")
425
+ target := lElse
426
+ if elseBody == nil {
427
+ target = lEnd
428
+ }
429
+ c.genCondJumpFalse(cond, target)
430
+ c.genStmt(thenBody)
431
+ if elseBody != nil {
432
+ c.emit("JMP", c.lab(lEnd))
433
+ c.label(lElse)
434
+ c.genStmt(elseBody)
435
+ }
436
+ c.label(lEnd)
437
+ }
438
+
439
+ func (c *compiler) genWhile(cond, body *Node) {
440
+ lStart := c.newLabel("while")
441
+ lEnd := c.newLabel("wend")
442
+ c.label(lStart)
443
+ c.genCondJumpFalse(cond, lEnd)
444
+ c.breakLbls = append(c.breakLbls, lEnd)
445
+ c.continueLbls = append(c.continueLbls, lStart)
446
+ c.genStmt(body)
447
+ c.emit("JMP", c.lab(lStart))
448
+ c.breakLbls = c.breakLbls[:len(c.breakLbls)-1]
449
+ c.continueLbls = c.continueLbls[:len(c.continueLbls)-1]
450
+ c.label(lEnd)
451
+ }
452
+
453
+ func (c *compiler) genFor(init, cond, update, body *Node) {
454
+ if init != nil {
455
+ c.genStmt(init)
456
+ }
457
+ lCond := c.newLabel("forc")
458
+ lUpdate := c.newLabel("foru")
459
+ lEnd := c.newLabel("fore")
460
+ c.label(lCond)
461
+ if cond != nil {
462
+ c.genCondJumpFalse(cond, lEnd)
463
+ }
464
+ c.breakLbls = append(c.breakLbls, lEnd)
465
+ c.continueLbls = append(c.continueLbls, lUpdate)
466
+ c.genStmt(body)
467
+ c.label(lUpdate)
468
+ if update != nil {
469
+ c.genStmt(update)
470
+ }
471
+ c.emit("JMP", c.lab(lCond))
472
+ c.breakLbls = c.breakLbls[:len(c.breakLbls)-1]
473
+ c.continueLbls = c.continueLbls[:len(c.continueLbls)-1]
474
+ c.label(lEnd)
475
+ }
476
+
477
+ func (c *compiler) genDowhile(body, cond *Node) {
478
+ lBody := c.newLabel("dbody")
479
+ lCond := c.newLabel("dcond")
480
+ lEnd := c.newLabel("dend")
481
+ c.label(lBody)
482
+ c.breakLbls = append(c.breakLbls, lEnd)
483
+ c.continueLbls = append(c.continueLbls, lCond)
484
+ c.genStmt(body)
485
+ c.label(lCond)
486
+ c.genCondJumpFalse(cond, lEnd)
487
+ c.emit("JMP", c.lab(lBody))
488
+ c.breakLbls = c.breakLbls[:len(c.breakLbls)-1]
489
+ c.continueLbls = c.continueLbls[:len(c.continueLbls)-1]
490
+ c.label(lEnd)
491
+ }
492
+
493
+ func (c *compiler) genSwitch(cond *Node, branches []*Node) {
494
+ selT := c.exprType(cond)
495
+ if selT == nil || (selT.Kind != kInt && selT.Kind != kBool) {
496
+ c.failf("Switch expression must be integer, got: %s", typeName(selT))
497
+ return
498
+ }
499
+ lEnd := c.newLabel("swend")
500
+ c.breakLbls = append(c.breakLbls, lEnd)
501
+ // continue 必须先把选择器弹出再跳转, 否则每轮迭代泄漏 8 字节栈直至撞堆。
502
+ // 只有在循环内 (存在外层 continue 目标) 才接管 continue, 否则保持
503
+ // "continue outside loop" 报错语义。
504
+ outerCont := ""
505
+ if n := len(c.continueLbls); n > 0 {
506
+ outerCont = c.continueLbls[n-1]
507
+ }
508
+ lCont := ""
509
+ if outerCont != "" {
510
+ lCont = c.newLabel("swcont")
511
+ c.continueLbls = append(c.continueLbls, lCont)
512
+ }
513
+ c.genValue(cond)
514
+ c.emit("PUSH", c.reg(0)) // [SP] = selector
515
+
516
+ type caseLabel struct {
517
+ raw uint64
518
+ isDefault bool
519
+ lbl string
520
+ }
521
+ // labels 与 branches 严格一一对应: 任何分支都不会被跳过 (旧实现遇到
522
+ // 非常量 case 时 continue, 导致后续 case 的标签贴到别人的语句体上)。
523
+ labels := make([]caseLabel, 0, len(branches))
524
+ defaultLbl := ""
525
+ for _, br := range branches {
526
+ if br.A == nil {
527
+ lbl := c.newLabel("swdef")
528
+ defaultLbl = lbl
529
+ labels = append(labels, caseLabel{isDefault: true, lbl: lbl})
530
+ continue
531
+ }
532
+ ct, raw, err := c.constValue(br.A)
533
+ if err != nil {
534
+ c.failf("case value must be an integer constant")
535
+ labels = append(labels, caseLabel{lbl: c.newLabel("swcase")})
536
+ continue
537
+ }
538
+ if ct.Kind != kInt && ct.Kind != kBool {
539
+ c.failf("case value must be an integer constant, got: %s", typeName(ct))
540
+ labels = append(labels, caseLabel{lbl: c.newLabel("swcase")})
541
+ continue
542
+ }
543
+ // 负数 case 按无符号位模式比较 (旧实现拿 -1 当 default 哨兵并跳过 raw < 0,
544
+ // 于是 `case -1` 永远匹配不上)。
545
+ labels = append(labels, caseLabel{raw: uint64(raw), lbl: c.newLabel("swcase")})
546
+ }
547
+
548
+ // 分派比较链
549
+ for _, l := range labels {
550
+ if l.isDefault {
551
+ continue
552
+ }
553
+ c.emit("LD", c.reg(0), ir.Mem(32, 0))
554
+ c.emit("MOV", c.reg(1), c.imm(int64(l.raw)))
555
+ c.emit("CMP", c.reg(0), c.reg(1))
556
+ c.emit("B", c.lab(l.lbl), ir.Cond("EQ"))
557
+ }
558
+ target := defaultLbl
559
+ if target == "" {
560
+ target = lEnd
561
+ }
562
+ c.emit("JMP", c.lab(target))
563
+
564
+ // case/default 体 (按文字顺序内联, C 贯穿语义)
565
+ for i, br := range branches {
566
+ c.label(labels[i].lbl)
567
+ c.genStmts(br.List)
568
+ }
569
+
570
+ // 贯穿到末尾与 break 都必须走弹出选择器的路径
571
+ c.emit("JMP", c.lab(lEnd))
572
+ if lCont != "" {
573
+ c.label(lCont)
574
+ c.emit("ADDI", c.reg(32), c.reg(32), c.imm(8))
575
+ c.emit("JMP", c.lab(outerCont))
576
+ c.continueLbls = c.continueLbls[:len(c.continueLbls)-1]
577
+ }
578
+ c.label(lEnd)
579
+ c.breakLbls = c.breakLbls[:len(c.breakLbls)-1]
580
+ c.emit("ADDI", c.reg(32), c.reg(32), c.imm(8)) // 丢 selector
581
+ }
582
+
583
+ func (c *compiler) genDecl(items []*Node) {
584
+ for _, item := range items {
585
+ if item.B != nil { // arrayLit
586
+ if item.B.Is2D {
587
+ c.genInit2dLiteral(item.Name, item.Type, item.B)
588
+ } else {
589
+ c.genInit1dLiteral(item.Name, item.Type, item.B)
590
+ }
591
+ continue
592
+ }
593
+ if item.A != nil { // init
594
+ vt := c.genValue(item.A)
595
+ c.convert(vt, item.Type)
596
+ c.emit("MOV", c.reg(2), c.reg(0))
597
+ c.mustAddrVar(item.Name)
598
+ c.emit("SD", c.reg(2), ir.Mem(0, 0))
599
+ } else if isPtrArray(item.Type) && item.Type.Elem != nil && isPtrArray(item.Type.Elem) {
600
+ c.emit("MOV", c.reg(0), c.imm(64*8))
601
+ c.emit("SYS", c.imm(SysMALLOC))
602
+ c.emit("MOV", c.reg(2), c.reg(0))
603
+ c.mustAddrVar(item.Name)
604
+ c.emit("SD", c.reg(2), ir.Mem(0, 0))
605
+ }
606
+ }
607
+ }
608
+
609
+ func (c *compiler) genInit1dLiteral(name string, t *Type, lit *Node) {
610
+ elemT := scalarT(kInt)
611
+ if isFixedArray(t) {
612
+ elemT = t.Elem
613
+ }
614
+ for i, elem := range lit.ArrayLit[0] {
615
+ vt := c.genValue(elem)
616
+ c.convert(vt, elemT)
617
+ c.emit("MOV", c.reg(2), c.reg(0))
618
+ c.mustAddrVar(name)
619
+ if i != 0 {
620
+ c.emit("ADDI", c.reg(0), c.reg(0), c.imm(int64(i*8)))
621
+ }
622
+ c.emit("SD", c.reg(2), ir.Mem(0, 0))
623
+ }
624
+ }
625
+
626
+ func (c *compiler) genInit2dLiteral(name string, t *Type, lit *Node) {
627
+ _ = t
628
+ nrows := len(lit.ArrayLit)
629
+ ncols := 0
630
+ for _, r := range lit.ArrayLit {
631
+ if len(r) > ncols {
632
+ ncols = len(r)
633
+ }
634
+ }
635
+ c.emit("MOV", c.reg(0), c.imm(int64(nrows*8)))
636
+ c.emit("SYS", c.imm(SysMALLOC))
637
+ c.emit("MOV", c.reg(4), c.reg(0))
638
+ for i, row := range lit.ArrayLit {
639
+ colCnt := ncols
640
+ if colCnt < 1 {
641
+ colCnt = 1
642
+ }
643
+ c.emit("MOV", c.reg(0), c.imm(int64(colCnt*8)))
644
+ c.emit("SYS", c.imm(SysMALLOC))
645
+ c.emit("MOV", c.reg(5), c.reg(0))
646
+ c.emit("MOV", c.reg(0), c.reg(4))
647
+ c.emit("ADDI", c.reg(0), c.reg(0), c.imm(int64(i*8)))
648
+ c.emit("SD", c.reg(5), ir.Mem(0, 0))
649
+ for j, elem := range row {
650
+ vt := c.genValue(elem)
651
+ c.convert(vt, scalarT(kInt))
652
+ c.emit("MOV", c.reg(2), c.reg(0))
653
+ c.emit("MOV", c.reg(0), c.reg(5))
654
+ if j != 0 {
655
+ c.emit("ADDI", c.reg(0), c.reg(0), c.imm(int64(j*8)))
656
+ }
657
+ c.emit("SD", c.reg(2), ir.Mem(0, 0))
658
+ }
659
+ }
660
+ c.emit("MOV", c.reg(2), c.reg(4))
661
+ c.mustAddrVar(name)
662
+ c.emit("SD", c.reg(2), ir.Mem(0, 0))
663
+ }
664
+
665
+ func (c *compiler) genCpuStmt(op string, operands [][2]string) {
666
+ operandValue := func(kind, val string) (int64, string, bool) {
667
+ if kind == "NUMBER" {
668
+ var n int64
669
+ fmt.Sscanf(val, "%d", &n)
670
+ return n, "", true
671
+ }
672
+ if kind == "IDENT" {
673
+ return 0, val, false
674
+ }
675
+ return 0, "", false
676
+ }
677
+
678
+ if op == "increment" || op == "decrement" {
679
+ varname := operands[0][1]
680
+ c.mustAddrVar(varname)
681
+ c.emit("LD", c.reg(0), ir.Mem(0, 0))
682
+ if op == "increment" {
683
+ c.emit("INC", c.reg(0))
684
+ } else {
685
+ c.emit("DEC", c.reg(0))
686
+ }
687
+ c.emit("MOV", c.reg(2), c.reg(0))
688
+ c.mustAddrVar(varname)
689
+ c.emit("SD", c.reg(2), ir.Mem(0, 0))
690
+ return
691
+ }
692
+
693
+ varname := operands[0][1]
694
+ var rhsVal int64
695
+ rhsIsVar := false
696
+ var rhsVarName string
697
+ if len(operands) > 1 {
698
+ v, name, isNum := operandValue(operands[1][0], operands[1][1])
699
+ if isNum {
700
+ rhsVal = v
701
+ } else {
702
+ rhsIsVar = true
703
+ rhsVarName = name
704
+ }
705
+ }
706
+
707
+ if op == "set" {
708
+ if rhsIsVar {
709
+ c.genValue(&Node{Kind: "var", Name: rhsVarName})
710
+ } else {
711
+ c.emit("MOV", c.reg(0), c.imm(rhsVal))
712
+ }
713
+ } else {
714
+ c.mustAddrVar(varname)
715
+ c.emit("LD", c.reg(0), ir.Mem(0, 0))
716
+ if rhsIsVar {
717
+ c.emit("MOV", c.reg(2), c.reg(0))
718
+ c.genValue(&Node{Kind: "var", Name: rhsVarName})
719
+ c.emit("MOV", c.reg(1), c.reg(0))
720
+ c.emit("MOV", c.reg(0), c.reg(2))
721
+ } else {
722
+ c.emit("MOV", c.reg(1), c.imm(rhsVal))
723
+ }
724
+ opMap := map[string]string{"add": "ADD", "subtract": "SUB",
725
+ "multiply": "MUL", "divide": "DIV"}
726
+ if m, ok := opMap[op]; ok {
727
+ c.emit(m, c.reg(0), c.reg(1))
728
+ }
729
+ }
730
+ c.emit("MOV", c.reg(2), c.reg(0))
731
+ c.mustAddrVar(varname)
732
+ c.emit("SD", c.reg(2), ir.Mem(0, 0))
733
+ }
734
+
735
+ func (c *compiler) genExprStmt(node *Node) {
736
+ c.genValue(node)
737
+ }
738
+
739
+ func (c *compiler) runtimeAbort(text string) {
740
+ addr := c.dataString(text)
741
+ c.emit("MOV", c.reg(0), c.imm(int64(addr)))
742
+ c.emit("SYS", c.imm(SysABORT))
743
+ }
744
+
745
+ func (c *compiler) genAssert(cond, msg *Node, line int, filename string) {
746
+ lOk := c.newLabel("assertok")
747
+ c.genCondJumpTrue(cond, lOk)
748
+ if msg == nil {
749
+ fn := filename
750
+ if fn == "" {
751
+ fn = c.filename
752
+ }
753
+ c.runtimeAbort(fmt.Sprintf("%s:%d: assertion failed", fn, line))
754
+ } else {
755
+ fn := filename
756
+ if fn == "" {
757
+ fn = c.filename
758
+ }
759
+ prefix := c.dataString(fmt.Sprintf("[assert %s:%d] ", fn, line))
760
+ c.emit("MOV", c.reg(0), c.imm(int64(prefix)))
761
+ c.emit("PUSH", c.reg(0))
762
+ c.genStringValue(msg)
763
+ c.emit("MOV", c.reg(1), c.reg(0))
764
+ c.emit("POP", c.reg(0))
765
+ c.emit("SYS", c.imm(SysSTR_CONCAT))
766
+ c.emit("SYS", c.imm(SysABORT))
767
+ }
768
+ c.label(lOk)
769
+ }
770
+
771
+ // ---------------- 类型转换 ----------------
772
+
773
+ func sameType(a, b *Type) bool {
774
+ if a == nil || b == nil {
775
+ return a == b
776
+ }
777
+ if a.Kind != b.Kind {
778
+ return false
779
+ }
780
+ switch a.Kind {
781
+ case kArray:
782
+ return a.Size == b.Size && sameType(a.Elem, b.Elem)
783
+ case kPtrArray:
784
+ return sameType(a.Elem, b.Elem)
785
+ case kStruct:
786
+ return a.Name == b.Name
787
+ }
788
+ return true
789
+ }
790
+
791
+ func (c *compiler) convert(from, to *Type) {
792
+ if to == nil || from == nil || sameType(from, to) {
793
+ return
794
+ }
795
+ if from.Kind == kInt && to.Kind == kFloat {
796
+ c.emit("SYS", c.imm(SysITOF))
797
+ } else if from.Kind == kFloat && to.Kind == kInt {
798
+ c.emit("SYS", c.imm(SysFTOI))
799
+ } else if from.Kind == kBool && (to.Kind == kInt || to.Kind == kFloat) {
800
+ if to.Kind == kFloat {
801
+ c.emit("SYS", c.imm(SysITOF))
802
+ }
803
+ }
804
+ // int->bool, string/struct/array 指针无需转换
805
+ }
806
+
807
+ // ---------------- 表达式 ----------------
808
+
809
+ func (c *compiler) genValue(n *Node) *Type {
810
+ switch n.Kind {
811
+ case "num":
812
+ if n.IsFloat {
813
+ bits := int64(math.Float64bits(n.Num))
814
+ c.emit("MOV", c.reg(0), c.imm(bits))
815
+ return scalarT(kFloat)
816
+ }
817
+ c.emit("MOV", c.reg(0), c.imm(n.Ival))
818
+ return scalarT(kInt)
819
+ case "bool":
820
+ v := int64(0)
821
+ if n.Bool {
822
+ v = 1
823
+ }
824
+ c.emit("MOV", c.reg(0), c.imm(v))
825
+ return scalarT(kBool)
826
+ case "str":
827
+ c.emit("MOV", c.reg(0), c.imm(int64(c.dataString(n.Str))))
828
+ return scalarT(kString)
829
+ case "var":
830
+ return c.genVarValue(n.Name)
831
+ case "member":
832
+ return c.genMember(n.A, n.Name, false)
833
+ case "index":
834
+ return c.genIndex(n.A, n.B, false)
835
+ case "call":
836
+ return c.genCall(n.Name, n.List)
837
+ case "neg":
838
+ t := c.genValue(n.A)
839
+ c.emit("MOV", c.reg(1), c.reg(0))
840
+ if t.Kind == kFloat {
841
+ c.emit("MOV", c.reg(0), c.imm(0))
842
+ c.emit("SYS", c.imm(SysITOF))
843
+ c.emit("SYS", c.imm(SysFSUB))
844
+ } else {
845
+ c.emit("MOV", c.reg(0), c.imm(0))
846
+ c.emit("SUB", c.reg(0), c.reg(1))
847
+ }
848
+ return t
849
+ case "not":
850
+ c.genValue(n.A)
851
+ c.emit("XORI", c.reg(0), c.reg(0), c.imm(1))
852
+ return scalarT(kBool)
853
+ case "bitnot":
854
+ t := c.genValue(n.A)
855
+ if t == nil || (t.Kind != kInt && t.Kind != kBool) {
856
+ c.failf("Bitwise NOT '~' requires an integer operand")
857
+ return scalarT(kInt)
858
+ }
859
+ c.emit("MVN", c.reg(0), c.reg(0))
860
+ return scalarT(kInt)
861
+ case "preinc", "predec", "postinc", "postdec":
862
+ return c.genIncdec(n.Kind, n.A)
863
+ case "cond":
864
+ return c.genTernary(n.A, n.B, n.C)
865
+ case "binop":
866
+ return c.genBinop(n.Op, n.A, n.B)
867
+ }
868
+ c.failf("Cannot generate code for expression: %s", n.Kind)
869
+ return nil
870
+ }
871
+
872
+ func (c *compiler) genVarValue(name string) *Type {
873
+ t := c.varType(name)
874
+ if t == nil {
875
+ return nil
876
+ }
877
+ isBlock := false
878
+ if lv, ok := c.locals[name]; ok {
879
+ isBlock = lv.isBlock
880
+ } else if gv, ok := c.globalsSym[name]; ok {
881
+ isBlock = gv.isBlock
882
+ }
883
+ if isBlock {
884
+ c.mustAddrVar(name)
885
+ return t
886
+ }
887
+ c.mustAddrVar(name)
888
+ c.emit("LD", c.reg(0), ir.Mem(0, 0))
889
+ return t
890
+ }
891
+
892
+ func (c *compiler) genLvalueAddr(n *Node) {
893
+ switch n.Kind {
894
+ case "var":
895
+ c.mustAddrVar(n.Name)
896
+ case "member":
897
+ c.genMember(n.A, n.Name, true)
898
+ case "index":
899
+ c.genIndex(n.A, n.B, true)
900
+ }
901
+ }
902
+
903
+ func (c *compiler) structField(structT *Type, fname string) (*Type, int, bool) {
904
+ sd := c.structs[structT.Name]
905
+ off, ok := sd.offsets[fname]
906
+ if !ok {
907
+ return nil, 0, false
908
+ }
909
+ for _, f := range sd.fields {
910
+ if f.name == fname {
911
+ return f.t, off, true
912
+ }
913
+ }
914
+ return nil, 0, false
915
+ }
916
+
917
+ func (c *compiler) decay(t *Type) *Type {
918
+ if isFixedArray(t) {
919
+ elem := t.Elem
920
+ if isFixedArray(elem) {
921
+ return &Type{Kind: kArray, Elem: elem, Size: t.Size}
922
+ }
923
+ return &Type{Kind: kPtrArray, Elem: elem}
924
+ }
925
+ return t
926
+ }
927
+
928
+ func (c *compiler) genMember(objNode *Node, fname string, lvalue bool) *Type {
929
+ objT := c.genValue(objNode)
930
+ if !isStruct(objT) {
931
+ c.failf("Member access on non-struct type: %s", typeName(objT))
932
+ return nil
933
+ }
934
+ ftype, foff, ok := c.structField(objT, fname)
935
+ if !ok {
936
+ c.failf("Struct %s has no field %s", objT.Name, fname)
937
+ return nil
938
+ }
939
+ if lvalue {
940
+ if foff != 0 {
941
+ c.emit("ADDI", c.reg(0), c.reg(0), c.imm(int64(foff*8)))
942
+ }
943
+ return nil
944
+ }
945
+ if isFixedArray(ftype) {
946
+ if foff != 0 {
947
+ c.emit("ADDI", c.reg(0), c.reg(0), c.imm(int64(foff*8)))
948
+ }
949
+ return c.decay(ftype)
950
+ }
951
+ c.emit("MOV", c.reg(1), c.reg(0))
952
+ if foff != 0 {
953
+ c.emit("ADDI", c.reg(1), c.reg(1), c.imm(int64(foff*8)))
954
+ }
955
+ c.emit("LD", c.reg(0), ir.Mem(1, 0))
956
+ return ftype
957
+ }
958
+
959
+ func (c *compiler) genIndex(baseNode, idxNode *Node, lvalue bool) *Type {
960
+ baseT := c.genValue(baseNode)
961
+ if baseT != nil && baseT.Kind == kString {
962
+ if lvalue {
963
+ c.failf("Cannot assign to string index")
964
+ return nil
965
+ }
966
+ c.emit("MOV", c.reg(3), c.reg(0))
967
+ c.genValue(idxNode)
968
+ c.emit("ADD", c.reg(0), c.reg(3))
969
+ c.emit("LB", c.reg(0), ir.Mem(0, 0))
970
+ c.emit("ANDI", c.reg(0), c.reg(0), c.imm(0xFF))
971
+ return scalarT(kInt)
972
+ }
973
+ if baseT == nil || (!isFixedArray(baseT) && !isPtrArray(baseT)) {
974
+ c.failf("Indexing non-array type: %s", typeName(baseT))
975
+ return nil
976
+ }
977
+ elemT := baseT.Elem
978
+
979
+ c.emit("MOV", c.reg(3), c.reg(0))
980
+ c.genValue(idxNode)
981
+
982
+ if c.bounds && isFixedArray(baseT) {
983
+ size := baseT.Size
984
+ lGe := c.newLabel("bndok")
985
+ c.emit("CMP", c.reg(0), c.imm(0))
986
+ c.emit("B", c.lab(lGe), ir.Cond("GE"))
987
+ c.runtimeAbort("bounds-check: negative array index")
988
+ c.label(lGe)
989
+ lLt := c.newLabel("bndok")
990
+ c.emit("CMP", c.reg(0), c.imm(int64(size)))
991
+ c.emit("B", c.lab(lLt), ir.Cond("LT"))
992
+ c.runtimeAbort(fmt.Sprintf("bounds-check: index >= length (%d)", size))
993
+ c.label(lLt)
994
+ }
995
+
996
+ scale := typeSlots(elemT) * 8
997
+ c.emit("MOV", c.reg(1), c.imm(int64(scale)))
998
+ c.emit("MUL", c.reg(0), c.reg(1))
999
+ c.emit("ADD", c.reg(0), c.reg(3))
1000
+
1001
+ if lvalue {
1002
+ return nil
1003
+ }
1004
+ if isFixedArray(elemT) {
1005
+ return elemT
1006
+ }
1007
+ if isPtrArray(elemT) {
1008
+ c.emit("MOV", c.reg(5), c.reg(0))
1009
+ c.emit("LD", c.reg(1), ir.Mem(5, 0))
1010
+ lDone := c.newLabel("rowdone")
1011
+ c.emit("CMP", c.reg(1), c.imm(0))
1012
+ c.emit("B", c.lab(lDone), ir.Cond("NE"))
1013
+ c.emit("MOV", c.reg(0), c.imm(64*8))
1014
+ c.emit("SYS", c.imm(SysMALLOC))
1015
+ c.emit("MOV", c.reg(1), c.reg(0))
1016
+ c.emit("SD", c.reg(1), ir.Mem(5, 0))
1017
+ c.label(lDone)
1018
+ c.emit("MOV", c.reg(0), c.reg(1))
1019
+ return elemT
1020
+ }
1021
+ c.emit("LD", c.reg(0), ir.Mem(0, 0))
1022
+ return elemT
1023
+ }
1024
+
1025
+ func (c *compiler) genAssign(target, valueNode *Node) *Type {
1026
+ vt := c.genValue(valueNode)
1027
+ tt := c.exprType(target)
1028
+ c.convert(vt, tt)
1029
+ c.emit("MOV", c.reg(2), c.reg(0))
1030
+ c.genLvalueAddr(target)
1031
+ c.emit("SD", c.reg(2), ir.Mem(0, 0))
1032
+ return tt
1033
+ }
1034
+
1035
+ func (c *compiler) exprType(n *Node) *Type {
1036
+ switch n.Kind {
1037
+ case "var":
1038
+ return c.varType(n.Name)
1039
+ case "member":
1040
+ objT := c.exprType(n.A)
1041
+ if isStruct(objT) {
1042
+ ft, _, _ := c.structField(objT, n.Name)
1043
+ return ft
1044
+ }
1045
+ case "index":
1046
+ baseT := c.exprType(n.A)
1047
+ if baseT != nil && baseT.Kind == kString {
1048
+ return scalarT(kInt)
1049
+ }
1050
+ if isFixedArray(baseT) || isPtrArray(baseT) {
1051
+ return baseT.Elem
1052
+ }
1053
+ case "call":
1054
+ if f, ok := c.functions[n.Name]; ok {
1055
+ return f.retType
1056
+ }
1057
+ if n.Name == "min" || n.Name == "max" {
1058
+ at := c.exprType(n.List[0])
1059
+ bt := c.exprType(n.List[1])
1060
+ if at != nil && at.Kind == kFloat || bt != nil && bt.Kind == kFloat {
1061
+ return scalarT(kFloat)
1062
+ }
1063
+ return scalarT(kInt)
1064
+ }
1065
+ return c.builtinRetType(n.Name)
1066
+ case "num":
1067
+ if n.IsFloat {
1068
+ return scalarT(kFloat)
1069
+ }
1070
+ return scalarT(kInt)
1071
+ case "bool":
1072
+ return scalarT(kBool)
1073
+ case "str":
1074
+ return scalarT(kString)
1075
+ case "binop":
1076
+ switch n.Op {
1077
+ case "+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=":
1078
+ return c.exprType(n.A)
1079
+ case "&", "|", "^", "<<", ">>":
1080
+ return scalarT(kInt)
1081
+ case "+", "-", "*", "%":
1082
+ lt := c.exprType(n.A)
1083
+ rt := c.exprType(n.B)
1084
+ if lt != nil && lt.Kind == kString || rt != nil && rt.Kind == kString {
1085
+ return scalarT(kString)
1086
+ }
1087
+ if lt != nil && lt.Kind == kFloat || rt != nil && rt.Kind == kFloat {
1088
+ return scalarT(kFloat)
1089
+ }
1090
+ return scalarT(kInt)
1091
+ case "/":
1092
+ return scalarT(kFloat)
1093
+ case "==", "!=", "<", ">", "<=", ">=", "&&", "||":
1094
+ return scalarT(kBool)
1095
+ }
1096
+ case "cond":
1097
+ lt := c.exprType(n.B)
1098
+ rt := c.exprType(n.C)
1099
+ ls := lt != nil && lt.Kind == kString
1100
+ rs := rt != nil && rt.Kind == kString
1101
+ if ls != rs {
1102
+ return scalarT(kInt)
1103
+ }
1104
+ if ls {
1105
+ return scalarT(kString)
1106
+ }
1107
+ if lt != nil && lt.Kind == kFloat || rt != nil && rt.Kind == kFloat {
1108
+ return scalarT(kFloat)
1109
+ }
1110
+ return scalarT(kInt)
1111
+ case "preinc", "predec", "postinc", "postdec":
1112
+ return c.exprType(n.A)
1113
+ case "neg":
1114
+ it := c.exprType(n.A)
1115
+ if it != nil && it.Kind == kFloat {
1116
+ return scalarT(kFloat)
1117
+ }
1118
+ return scalarT(kInt)
1119
+ case "not":
1120
+ return scalarT(kBool)
1121
+ case "bitnot":
1122
+ return scalarT(kInt)
1123
+ }
1124
+ return nil
1125
+ }
1126
+
1127
+ // ---------------- 二元运算 ----------------
1128
+
1129
+ func (c *compiler) genBinop(op string, left, right *Node) *Type {
1130
+ if op == "=" {
1131
+ return c.genAssign(left, right)
1132
+ }
1133
+ if base, ok := compoundToBase[op]; ok {
1134
+ return c.genCompound(left, base, right)
1135
+ }
1136
+ if op == "&&" || op == "||" {
1137
+ return c.genLogical(op, left, right)
1138
+ }
1139
+ if op == "&" || op == "|" || op == "^" || op == "<<" || op == ">>" {
1140
+ return c.genBitwise(op, left, right)
1141
+ }
1142
+ if op == "==" || op == "!=" || op == "<" || op == ">" || op == "<=" || op == ">=" {
1143
+ // 比较作为值表达式: 条件成立得 1, 否则 0
1144
+ lFalse := c.newLabel("cmpf")
1145
+ lEnd := c.newLabel("cmpe")
1146
+ c.genCondJumpFalse(&Node{Kind: "binop", Op: op, A: left, B: right}, lFalse)
1147
+ c.emit("MOV", c.reg(0), c.imm(1))
1148
+ c.emit("JMP", c.lab(lEnd))
1149
+ c.label(lFalse)
1150
+ c.emit("MOV", c.reg(0), c.imm(0))
1151
+ c.label(lEnd)
1152
+ return scalarT(kBool)
1153
+ }
1154
+
1155
+ lt := c.exprType(left)
1156
+ rt := c.exprType(right)
1157
+ if op == "+" && (lt != nil && lt.Kind == kString || rt != nil && rt.Kind == kString) {
1158
+ c.genStringValue(left)
1159
+ c.emit("PUSH", c.reg(0))
1160
+ c.genStringValue(right)
1161
+ c.emit("MOV", c.reg(1), c.reg(0))
1162
+ c.emit("POP", c.reg(0))
1163
+ c.emit("SYS", c.imm(SysSTR_CONCAT))
1164
+ return scalarT(kString)
1165
+ }
1166
+
1167
+ floatMode := lt != nil && lt.Kind == kFloat || rt != nil && rt.Kind == kFloat || op == "/"
1168
+ c.genValue(left)
1169
+ if floatMode && lt != nil && lt.Kind == kInt {
1170
+ c.emit("SYS", c.imm(SysITOF))
1171
+ }
1172
+ if floatMode && lt != nil && lt.Kind == kBool {
1173
+ c.emit("SYS", c.imm(SysITOF))
1174
+ }
1175
+ c.emit("PUSH", c.reg(0))
1176
+ c.genValue(right)
1177
+ if floatMode && rt != nil && (rt.Kind == kInt || rt.Kind == kBool) {
1178
+ c.emit("SYS", c.imm(SysITOF))
1179
+ }
1180
+ c.emit("MOV", c.reg(1), c.reg(0))
1181
+ c.emit("POP", c.reg(0))
1182
+
1183
+ if floatMode {
1184
+ sysMap := map[string]int64{"+": SysFADD, "-": SysFSUB, "*": SysFMUL, "/": SysFDIV}
1185
+ if op == "%" {
1186
+ c.failf("Float modulo not supported")
1187
+ return scalarT(kFloat)
1188
+ }
1189
+ c.emit("SYS", c.imm(sysMap[op]))
1190
+ return scalarT(kFloat)
1191
+ }
1192
+
1193
+ if op == "%" {
1194
+ c.emit("MOV", c.reg(2), c.reg(1))
1195
+ c.emit("PUSH", c.reg(0))
1196
+ c.emit("DIV", c.reg(0), c.reg(2))
1197
+ c.emit("MUL", c.reg(0), c.reg(2))
1198
+ c.emit("MOV", c.reg(1), c.reg(0))
1199
+ c.emit("POP", c.reg(0))
1200
+ c.emit("SUB", c.reg(0), c.reg(1))
1201
+ return scalarT(kInt)
1202
+ }
1203
+
1204
+ opMap := map[string]string{"+": "ADD", "-": "SUB", "*": "MUL"}
1205
+ if m, ok := opMap[op]; ok {
1206
+ c.emit(m, c.reg(0), c.reg(1))
1207
+ return scalarT(kInt)
1208
+ }
1209
+ c.failf("Unsupported int operator: %s", op)
1210
+ return scalarT(kInt)
1211
+ }
1212
+
1213
+ var compoundToBase = map[string]string{
1214
+ "+=": "+", "-=": "-", "*=": "*", "/=": "/", "%=": "%",
1215
+ "&=": "&", "|=": "|", "^=": "^", "<<=": "<<", ">>=": ">>",
1216
+ }
1217
+
1218
+ func (c *compiler) genLogical(op string, left, right *Node) *Type {
1219
+ lTrue := c.newLabel("lt")
1220
+ lFalse := c.newLabel("lf")
1221
+ lEnd := c.newLabel("le")
1222
+ if op == "&&" {
1223
+ c.genCondJumpFalse(left, lFalse)
1224
+ c.genCondJumpFalse(right, lFalse)
1225
+ } else {
1226
+ c.genCondJumpTrue(left, lTrue)
1227
+ c.genCondJumpTrue(right, lTrue)
1228
+ c.emit("JMP", c.lab(lFalse))
1229
+ }
1230
+ c.label(lTrue)
1231
+ c.emit("MOV", c.reg(0), c.imm(1))
1232
+ c.emit("JMP", c.lab(lEnd))
1233
+ c.label(lFalse)
1234
+ c.emit("MOV", c.reg(0), c.imm(0))
1235
+ c.label(lEnd)
1236
+ return scalarT(kBool)
1237
+ }
1238
+
1239
+ func (c *compiler) genBitwise(op string, left, right *Node) *Type {
1240
+ lt := c.exprType(left)
1241
+ rt := c.exprType(right)
1242
+ if lt != nil && (lt.Kind == kFloat || lt.Kind == kString) ||
1243
+ rt != nil && (rt.Kind == kFloat || rt.Kind == kString) {
1244
+ bad := lt
1245
+ if bad == nil || (bad.Kind != kFloat && bad.Kind != kString) {
1246
+ bad = rt
1247
+ }
1248
+ c.failf("Bitwise operator '%s' requires integer operands (got: %s)",
1249
+ op, typeName(bad))
1250
+ return scalarT(kInt)
1251
+ }
1252
+ c.genValue(left)
1253
+ c.emit("PUSH", c.reg(0))
1254
+ c.genValue(right)
1255
+ c.emit("MOV", c.reg(1), c.reg(0))
1256
+ c.emit("POP", c.reg(0))
1257
+ switch op {
1258
+ case "&":
1259
+ c.emit("AND", c.reg(0), c.reg(1))
1260
+ case "|":
1261
+ c.emit("OR", c.reg(0), c.reg(1))
1262
+ case "^":
1263
+ c.emit("XOR", c.reg(0), c.reg(1))
1264
+ case "<<":
1265
+ c.emit("SHL", c.reg(0), c.reg(1))
1266
+ case ">>":
1267
+ c.emit("ASR", c.reg(0), c.reg(0), c.reg(1))
1268
+ }
1269
+ return scalarT(kInt)
1270
+ }
1271
+
1272
+ func (c *compiler) genCompound(target *Node, op string, valueNode *Node) *Type {
1273
+ tt := c.exprType(target)
1274
+ if tt == nil || (tt.Kind != kInt && tt.Kind != kBool && tt.Kind != kFloat) {
1275
+ c.failf("Cannot apply '%s=' to type: %s", op, typeName(tt))
1276
+ return nil
1277
+ }
1278
+ if tt.Kind == kFloat && op != "+" && op != "-" && op != "*" && op != "/" {
1279
+ c.failf("Cannot apply '%s=' to float", op)
1280
+ return tt
1281
+ }
1282
+ floatMode := tt.Kind == kFloat
1283
+
1284
+ c.genLvalueAddr(target)
1285
+ c.emit("PUSH", c.reg(0))
1286
+ vt := c.genValue(valueNode)
1287
+ c.convert(vt, tt)
1288
+ c.emit("MOV", c.reg(1), c.reg(0))
1289
+ c.emit("LD", c.reg(2), ir.Mem(32, 0))
1290
+ c.emit("LD", c.reg(0), ir.Mem(2, 0))
1291
+
1292
+ if floatMode {
1293
+ fmap := map[string]int64{"+": SysFADD, "-": SysFSUB, "*": SysFMUL, "/": SysFDIV}
1294
+ c.emit("SYS", c.imm(fmap[op]))
1295
+ } else {
1296
+ switch op {
1297
+ case "+":
1298
+ c.emit("ADD", c.reg(0), c.reg(1))
1299
+ case "-":
1300
+ c.emit("SUB", c.reg(0), c.reg(1))
1301
+ case "*":
1302
+ c.emit("MUL", c.reg(0), c.reg(1))
1303
+ case "/":
1304
+ c.emit("DIV", c.reg(0), c.reg(1))
1305
+ case "%":
1306
+ c.emit("MOV", c.reg(3), c.reg(1))
1307
+ c.emit("PUSH", c.reg(0))
1308
+ c.emit("DIV", c.reg(0), c.reg(3))
1309
+ c.emit("MUL", c.reg(0), c.reg(3))
1310
+ c.emit("MOV", c.reg(1), c.reg(0))
1311
+ c.emit("POP", c.reg(0))
1312
+ c.emit("SUB", c.reg(0), c.reg(1))
1313
+ case "&":
1314
+ c.emit("AND", c.reg(0), c.reg(1))
1315
+ case "|":
1316
+ c.emit("OR", c.reg(0), c.reg(1))
1317
+ case "^":
1318
+ c.emit("XOR", c.reg(0), c.reg(1))
1319
+ case "<<":
1320
+ c.emit("SHL", c.reg(0), c.reg(1))
1321
+ case ">>":
1322
+ c.emit("ASR", c.reg(0), c.reg(0), c.reg(1))
1323
+ }
1324
+ }
1325
+
1326
+ c.emit("SD", c.reg(0), ir.Mem(2, 0))
1327
+ c.emit("ADDI", c.reg(32), c.reg(32), c.imm(8))
1328
+ return tt
1329
+ }
1330
+
1331
+ func (c *compiler) genIncdec(kind string, target *Node) *Type {
1332
+ tt := c.exprType(target)
1333
+ if tt == nil || (tt.Kind != kInt && tt.Kind != kBool && tt.Kind != kFloat) {
1334
+ return nil
1335
+ }
1336
+ op := "+"
1337
+ if kind == "predec" || kind == "postdec" {
1338
+ op = "-"
1339
+ }
1340
+ postfix := kind == "postinc" || kind == "postdec"
1341
+ floatMode := tt.Kind == kFloat
1342
+
1343
+ c.genLvalueAddr(target)
1344
+ c.emit("PUSH", c.reg(0))
1345
+ c.emit("LD", c.reg(2), ir.Mem(32, 0))
1346
+ c.emit("LD", c.reg(0), ir.Mem(2, 0))
1347
+ if postfix {
1348
+ c.emit("MOV", c.reg(5), c.reg(0))
1349
+ }
1350
+ if floatMode {
1351
+ c.emit("MOV", c.reg(0), c.imm(1))
1352
+ c.emit("SYS", c.imm(SysITOF))
1353
+ c.emit("MOV", c.reg(1), c.reg(0))
1354
+ c.emit("LD", c.reg(0), ir.Mem(2, 0))
1355
+ if op == "+" {
1356
+ c.emit("SYS", c.imm(SysFADD))
1357
+ } else {
1358
+ c.emit("SYS", c.imm(SysFSUB))
1359
+ }
1360
+ } else {
1361
+ c.emit("MOV", c.reg(1), c.imm(1))
1362
+ if op == "+" {
1363
+ c.emit("ADD", c.reg(0), c.reg(1))
1364
+ } else {
1365
+ c.emit("SUB", c.reg(0), c.reg(1))
1366
+ }
1367
+ }
1368
+ c.emit("SD", c.reg(0), ir.Mem(2, 0))
1369
+ c.emit("ADDI", c.reg(32), c.reg(32), c.imm(8))
1370
+ if postfix {
1371
+ c.emit("MOV", c.reg(0), c.reg(5))
1372
+ }
1373
+ return tt
1374
+ }
1375
+
1376
+ func (c *compiler) genMinmax(name string, args []*Node) *Type {
1377
+ at := c.exprType(args[0])
1378
+ bt := c.exprType(args[1])
1379
+ if at != nil && at.Kind == kString || bt != nil && bt.Kind == kString {
1380
+ return scalarT(kInt)
1381
+ }
1382
+ tt := scalarT(kInt)
1383
+ if at != nil && at.Kind == kFloat || bt != nil && bt.Kind == kFloat {
1384
+ tt = scalarT(kFloat)
1385
+ }
1386
+
1387
+ c.genValue(args[0])
1388
+ if tt.Kind == kFloat && at != nil && (at.Kind == kInt || at.Kind == kBool) {
1389
+ c.emit("SYS", c.imm(SysITOF))
1390
+ }
1391
+ c.emit("PUSH", c.reg(0))
1392
+ c.genValue(args[1])
1393
+ if tt.Kind == kFloat && bt != nil && (bt.Kind == kInt || bt.Kind == kBool) {
1394
+ c.emit("SYS", c.imm(SysITOF))
1395
+ }
1396
+ c.emit("MOV", c.reg(1), c.reg(0))
1397
+ c.emit("POP", c.reg(0))
1398
+
1399
+ cond := "LE"
1400
+ if name == "max" {
1401
+ cond = "GE"
1402
+ }
1403
+ if tt.Kind == kFloat {
1404
+ c.emit("MOV", c.reg(2), c.reg(0))
1405
+ c.emit("MOV", c.reg(3), c.reg(1))
1406
+ c.emit("SYS", c.imm(SysFCMP))
1407
+ c.emit("CMP", c.reg(0), c.imm(0))
1408
+ lKeep := c.newLabel("mmkeep")
1409
+ lDone := c.newLabel("mmdone")
1410
+ c.emit("B", c.lab(lKeep), ir.Cond(cond))
1411
+ c.emit("MOV", c.reg(0), c.reg(3))
1412
+ c.emit("JMP", c.lab(lDone))
1413
+ c.label(lKeep)
1414
+ c.emit("MOV", c.reg(0), c.reg(2))
1415
+ c.label(lDone)
1416
+ } else {
1417
+ c.emit("CMP", c.reg(0), c.reg(1))
1418
+ lKeep := c.newLabel("mmkeep")
1419
+ c.emit("B", c.lab(lKeep), ir.Cond(cond))
1420
+ c.emit("MOV", c.reg(0), c.reg(1))
1421
+ c.label(lKeep)
1422
+ }
1423
+ return tt
1424
+ }
1425
+
1426
+ func (c *compiler) genTernary(cond, a, b *Node) *Type {
1427
+ lt := c.exprType(a)
1428
+ rt := c.exprType(b)
1429
+ ls := lt != nil && lt.Kind == kString
1430
+ rs := rt != nil && rt.Kind == kString
1431
+ if ls != rs {
1432
+ return scalarT(kInt)
1433
+ }
1434
+ tt := scalarT(kInt)
1435
+ if ls {
1436
+ tt = scalarT(kString)
1437
+ } else if lt != nil && lt.Kind == kFloat || rt != nil && rt.Kind == kFloat {
1438
+ tt = scalarT(kFloat)
1439
+ }
1440
+ lFalse := c.newLabel("cndf")
1441
+ lEnd := c.newLabel("cnde")
1442
+ c.genCondJumpFalse(cond, lFalse)
1443
+ t1 := c.genValue(a)
1444
+ c.convert(t1, tt)
1445
+ c.emit("MOV", c.reg(6), c.reg(0))
1446
+ c.emit("JMP", c.lab(lEnd))
1447
+ c.label(lFalse)
1448
+ t2 := c.genValue(b)
1449
+ c.convert(t2, tt)
1450
+ c.emit("MOV", c.reg(6), c.reg(0))
1451
+ c.label(lEnd)
1452
+ c.emit("MOV", c.reg(0), c.reg(6))
1453
+ return tt
1454
+ }
1455
+
1456
+ // ---------------- 字符串化 ----------------
1457
+
1458
+ func (c *compiler) genStringValue(n *Node) {
1459
+ t := c.genValue(n)
1460
+ switch {
1461
+ case t != nil && t.Kind == kString:
1462
+ return
1463
+ case t != nil && t.Kind == kFloat:
1464
+ c.emit("SYS", c.imm(SysFTOA))
1465
+ case t != nil && t.Kind == kBool:
1466
+ c.emit("SYS", c.imm(SysBOOL_STR))
1467
+ default:
1468
+ c.emit("SYS", c.imm(SysITOA))
1469
+ }
1470
+ }
1471
+
1472
+ func (c *compiler) genPrint(n *Node, newline bool) {
1473
+ t := c.genValue(n)
1474
+ switch {
1475
+ case t != nil && t.Kind == kString:
1476
+ case t != nil && t.Kind == kFloat:
1477
+ c.emit("SYS", c.imm(SysFTOA))
1478
+ case t != nil && t.Kind == kBool:
1479
+ c.emit("SYS", c.imm(SysBOOL_STR))
1480
+ default:
1481
+ c.emit("SYS", c.imm(SysITOA))
1482
+ }
1483
+ c.emit("SYS", c.imm(SysPRINT_STR))
1484
+ if newline {
1485
+ c.emit("OUT", c.imm(10))
1486
+ }
1487
+ }
1488
+
1489
+ // ---------------- 函数调用 ----------------
1490
+
1491
+ func (c *compiler) builtinRetType(name string) *Type {
1492
+ if hb, ok := hostBuiltins[name]; ok {
1493
+ return scalarT(hb.ret)
1494
+ }
1495
+ switch name {
1496
+ case "sin", "cos", "tan", "sqrt", "pow", "floor", "ceil", "round":
1497
+ return scalarT(kFloat)
1498
+ case "strlen", "strcmp", "rand", "time", "abs", "input", "idiv", "atoi":
1499
+ return scalarT(kInt)
1500
+ case "strcpy", "int_to_str", "itoa", "float_to_str", "ftoa", "bool_to_str",
1501
+ "substr", "upper", "lower", "trim", "ltrim", "rtrim":
1502
+ return scalarT(kString)
1503
+ }
1504
+ return nil
1505
+ }
1506
+
1507
+ // builtinMinArgs 记录各内建函数最少参数个数, 与 Python 侧
1508
+ // codecin/cin.py: BUILTIN_MIN_ARGS 必须保持一致。
1509
+ // 缺失参数旧代码会直接索引越界 panic, 现在统一走编译错误通道。
1510
+ var builtinMinArgs = func() map[string]int {
1511
+ m := map[string]int{
1512
+ "println": 0, "print": 0,
1513
+ "sqrt": 1, "sin": 1, "cos": 1, "tan": 1,
1514
+ "floor": 1, "ceil": 1, "round": 1,
1515
+ "min": 2, "max": 2,
1516
+ "idiv": 2, "pow": 2,
1517
+ "abs": 1, "strlen": 1, "strcmp": 2, "strcpy": 1,
1518
+ "rand": 0, "srand": 1,
1519
+ "int_to_str": 1, "itoa": 1,
1520
+ "float_to_str": 1, "ftoa": 1,
1521
+ "bool_to_str": 1,
1522
+ "substr": 3, "indexof": 2,
1523
+ "upper": 1, "lower": 1,
1524
+ "trim": 1, "ltrim": 1, "rtrim": 1, "atoi": 1,
1525
+ "time": 0, "input": 0,
1526
+ }
1527
+ for name, hb := range hostBuiltins {
1528
+ m[name] = hb.nargs
1529
+ }
1530
+ return m
1531
+ }()
1532
+
1533
+ func (c *compiler) genCall(name string, args []*Node) *Type {
1534
+ if minArgs, ok := builtinMinArgs[name]; ok && len(args) < minArgs {
1535
+ c.failf("%s() expects at least %d argument(s), got %d",
1536
+ name, minArgs, len(args))
1537
+ return scalarT(kVoid)
1538
+ }
1539
+ if name == "println" || name == "print" {
1540
+ if len(args) > 0 {
1541
+ c.genPrint(args[0], name == "println")
1542
+ } else {
1543
+ c.emit("OUT", c.imm(10))
1544
+ }
1545
+ return scalarT(kVoid)
1546
+ }
1547
+
1548
+ mathUnary := map[string]int64{"sqrt": SysSQRT, "sin": SysSIN, "cos": SysCOS, "tan": SysTAN}
1549
+ if id, ok := mathUnary[name]; ok {
1550
+ at := c.genValue(args[0])
1551
+ if at.Kind == kInt {
1552
+ c.emit("SYS", c.imm(SysITOF))
1553
+ }
1554
+ c.emit("SYS", c.imm(id))
1555
+ return scalarT(kFloat)
1556
+ }
1557
+
1558
+ roundUnary := map[string]int64{"floor": SysFLOOR, "ceil": SysCEIL, "round": SysROUND}
1559
+ if id, ok := roundUnary[name]; ok {
1560
+ at := c.genValue(args[0])
1561
+ if at.Kind == kInt || at.Kind == kBool {
1562
+ c.emit("SYS", c.imm(SysITOF))
1563
+ }
1564
+ c.emit("SYS", c.imm(id))
1565
+ return scalarT(kFloat)
1566
+ }
1567
+
1568
+ if name == "min" || name == "max" {
1569
+ return c.genMinmax(name, args)
1570
+ }
1571
+
1572
+ if name == "idiv" {
1573
+ c.genValue(args[0])
1574
+ c.emit("PUSH", c.reg(0))
1575
+ c.genValue(args[1])
1576
+ c.emit("MOV", c.reg(1), c.reg(0))
1577
+ c.emit("POP", c.reg(0))
1578
+ c.emit("DIV", c.reg(0), c.reg(1))
1579
+ return scalarT(kInt)
1580
+ }
1581
+
1582
+ if name == "pow" {
1583
+ c.argFloat(args[0])
1584
+ c.emit("PUSH", c.reg(0))
1585
+ c.argFloat(args[1])
1586
+ c.emit("MOV", c.reg(1), c.reg(0))
1587
+ c.emit("POP", c.reg(0))
1588
+ c.emit("SYS", c.imm(SysPOW))
1589
+ return scalarT(kFloat)
1590
+ }
1591
+ if name == "abs" {
1592
+ c.genValue(args[0])
1593
+ c.emit("SYS", c.imm(SysABS))
1594
+ return scalarT(kInt)
1595
+ }
1596
+ if name == "strlen" {
1597
+ c.genValue(args[0])
1598
+ c.emit("SYS", c.imm(SysSTRLEN))
1599
+ return scalarT(kInt)
1600
+ }
1601
+ if name == "strcmp" {
1602
+ c.genValue(args[0])
1603
+ c.emit("PUSH", c.reg(0))
1604
+ c.genValue(args[1])
1605
+ c.emit("MOV", c.reg(1), c.reg(0))
1606
+ c.emit("POP", c.reg(0))
1607
+ c.emit("SYS", c.imm(SysSTRCMP))
1608
+ return scalarT(kInt)
1609
+ }
1610
+ if name == "strcpy" {
1611
+ c.genValue(args[0])
1612
+ c.emit("PUSH", c.reg(0))
1613
+ c.emit("MOV", c.reg(0), c.imm(int64(c.dataString(""))))
1614
+ c.emit("MOV", c.reg(1), c.reg(0))
1615
+ c.emit("POP", c.reg(0))
1616
+ c.emit("SYS", c.imm(SysSTR_CONCAT))
1617
+ return scalarT(kString)
1618
+ }
1619
+ if name == "rand" {
1620
+ c.emit("SYS", c.imm(SysRAND))
1621
+ return scalarT(kInt)
1622
+ }
1623
+ if name == "srand" {
1624
+ c.genValue(args[0])
1625
+ c.emit("SYS", c.imm(SysSRAND))
1626
+ return scalarT(kVoid)
1627
+ }
1628
+ if name == "int_to_str" || name == "itoa" {
1629
+ c.genValue(args[0])
1630
+ c.emit("SYS", c.imm(SysITOA))
1631
+ return scalarT(kString)
1632
+ }
1633
+ if name == "float_to_str" || name == "ftoa" {
1634
+ t := c.genValue(args[0])
1635
+ if t.Kind == kInt || t.Kind == kBool {
1636
+ c.emit("SYS", c.imm(SysITOF))
1637
+ }
1638
+ c.emit("SYS", c.imm(SysFTOA))
1639
+ return scalarT(kString)
1640
+ }
1641
+ if name == "bool_to_str" {
1642
+ c.genValue(args[0])
1643
+ c.emit("SYS", c.imm(SysBOOL_STR))
1644
+ return scalarT(kString)
1645
+ }
1646
+ if name == "substr" {
1647
+ c.genStringValue(args[0])
1648
+ c.emit("PUSH", c.reg(0))
1649
+ c.genValue(args[1])
1650
+ c.emit("PUSH", c.reg(0))
1651
+ c.genValue(args[2])
1652
+ c.emit("MOV", c.reg(2), c.reg(0))
1653
+ c.emit("POP", c.reg(1))
1654
+ c.emit("POP", c.reg(0))
1655
+ c.emit("SYS", c.imm(SysSUBSTR))
1656
+ return scalarT(kString)
1657
+ }
1658
+ if name == "indexof" {
1659
+ c.genStringValue(args[0])
1660
+ c.emit("PUSH", c.reg(0))
1661
+ c.genStringValue(args[1])
1662
+ c.emit("MOV", c.reg(1), c.reg(0))
1663
+ c.emit("POP", c.reg(0))
1664
+ c.emit("SYS", c.imm(SysINDEXOF))
1665
+ return scalarT(kInt)
1666
+ }
1667
+ if name == "upper" || name == "lower" {
1668
+ c.genStringValue(args[0])
1669
+ id := int64(SysTOUPPER)
1670
+ if name == "lower" {
1671
+ id = SysTOLOWER
1672
+ }
1673
+ c.emit("SYS", c.imm(id))
1674
+ return scalarT(kString)
1675
+ }
1676
+ if name == "trim" || name == "ltrim" || name == "rtrim" {
1677
+ c.genStringValue(args[0])
1678
+ id := map[string]int64{"trim": SysTRIM, "ltrim": SysLTRIM, "rtrim": SysRTRIM}[name]
1679
+ c.emit("SYS", c.imm(id))
1680
+ return scalarT(kString)
1681
+ }
1682
+ if name == "atoi" {
1683
+ c.genValue(args[0])
1684
+ c.emit("SYS", c.imm(SysATOI))
1685
+ return scalarT(kInt)
1686
+ }
1687
+
1688
+ // 宿主能力 (表驱动): 音频 / 画布 / 系统交互 / Termux API
1689
+ if hb, ok := hostBuiltins[name]; ok {
1690
+ n := hb.nargs
1691
+ if n > len(args) {
1692
+ n = len(args)
1693
+ }
1694
+ c.genHostSys(hb.sysID, args[:n])
1695
+ return scalarT(hb.ret)
1696
+ }
1697
+
1698
+ if name == "time" {
1699
+ c.emit("SYS", c.imm(SysTIME))
1700
+ return scalarT(kInt)
1701
+ }
1702
+ if name == "input" {
1703
+ c.emit("MOV", c.reg(0), c.imm(0))
1704
+ return scalarT(kInt)
1705
+ }
1706
+
1707
+ // 用户函数
1708
+ fdef := c.functions[name]
1709
+ if fdef == nil {
1710
+ c.failf("Unknown function: %s", name)
1711
+ return nil
1712
+ }
1713
+ for k, arg := range args {
1714
+ at := c.genValue(arg)
1715
+ var ptype *Type
1716
+ if k < len(fdef.params) {
1717
+ ptype = paramPromote(fdef.params[k].t)
1718
+ }
1719
+ c.convert(at, ptype)
1720
+ c.emit("PUSH", c.reg(0))
1721
+ }
1722
+ c.emit("CALL", c.lab(name))
1723
+ nargs := len(args)
1724
+ if nargs > 0 {
1725
+ c.emit("ADDI", c.reg(6), c.reg(32), c.imm(int64(nargs*8)))
1726
+ c.emit("MOV", c.reg(32), c.reg(6))
1727
+ }
1728
+ return fdef.retType
1729
+ }
1730
+
1731
+ func paramPromote(t *Type) *Type {
1732
+ if isFixedArray(t) {
1733
+ return &Type{Kind: kPtrArray, Elem: t.Elem}
1734
+ }
1735
+ return t
1736
+ }
1737
+
1738
+ func (c *compiler) argFloat(n *Node) {
1739
+ t := c.genValue(n)
1740
+ if t.Kind == kInt || t.Kind == kBool {
1741
+ c.emit("SYS", c.imm(SysITOF))
1742
+ }
1743
+ }
1744
+
1745
+ func (c *compiler) genHostSys(sysID int64, args []*Node) {
1746
+ for _, a := range args {
1747
+ c.genValue(a)
1748
+ c.emit("PUSH", c.reg(0))
1749
+ }
1750
+ for i := len(args) - 1; i >= 0; i-- {
1751
+ c.emit("POP", c.reg(i))
1752
+ }
1753
+ c.emit("SYS", c.imm(sysID))
1754
+ }
1755
+
1756
+ // ---------------- 条件跳转 ----------------
1757
+
1758
+ var condFalseJump = map[string]string{
1759
+ "==": "NE", "!=": "EQ", "<": "GE", ">": "LE", "<=": "GT", ">=": "LT",
1760
+ }
1761
+
1762
+ func (c *compiler) genCondJumpFalse(n *Node, labelFalse string) {
1763
+ switch {
1764
+ case n.Kind == "bool":
1765
+ if !n.Bool {
1766
+ c.emit("JMP", c.lab(labelFalse))
1767
+ }
1768
+ return
1769
+ case n.Kind == "binop" && n.Op == "&&":
1770
+ c.genCondJumpFalse(n.A, labelFalse)
1771
+ c.genCondJumpFalse(n.B, labelFalse)
1772
+ return
1773
+ case n.Kind == "binop" && n.Op == "||":
1774
+ lTrue := c.newLabel("ortrue")
1775
+ c.genCondJumpTrue(n.A, lTrue)
1776
+ c.genCondJumpTrue(n.B, lTrue)
1777
+ c.emit("JMP", c.lab(labelFalse))
1778
+ c.label(lTrue)
1779
+ return
1780
+ case n.Kind == "not":
1781
+ c.genCondJumpTrue(n.A, labelFalse)
1782
+ return
1783
+ case n.Kind == "binop" && condFalseJump[n.Op] != "":
1784
+ op := n.Op
1785
+ lt := c.exprType(n.A)
1786
+ rt := c.exprType(n.B)
1787
+ floatMode := lt != nil && lt.Kind == kFloat || rt != nil && rt.Kind == kFloat
1788
+ c.genValue(n.A)
1789
+ if floatMode && lt != nil && (lt.Kind == kInt || lt.Kind == kBool) {
1790
+ c.emit("SYS", c.imm(SysITOF))
1791
+ }
1792
+ c.emit("PUSH", c.reg(0))
1793
+ c.genValue(n.B)
1794
+ if floatMode && rt != nil && (rt.Kind == kInt || rt.Kind == kBool) {
1795
+ c.emit("SYS", c.imm(SysITOF))
1796
+ }
1797
+ c.emit("MOV", c.reg(1), c.reg(0))
1798
+ c.emit("POP", c.reg(0))
1799
+ if floatMode {
1800
+ c.emit("SYS", c.imm(SysFCMP))
1801
+ c.emit("CMP", c.reg(0), c.imm(0))
1802
+ } else {
1803
+ c.emit("CMP", c.reg(0), c.reg(1))
1804
+ }
1805
+ c.emit("B", c.lab(labelFalse), ir.Cond(condFalseJump[op]))
1806
+ return
1807
+ }
1808
+ c.genValue(n)
1809
+ c.emit("CMP", c.reg(0), c.imm(0))
1810
+ c.emit("JZ", c.lab(labelFalse))
1811
+ }
1812
+
1813
+ func (c *compiler) genCondJumpTrue(n *Node, labelTrue string) {
1814
+ lFalse := c.newLabel("cf")
1815
+ c.genCondJumpFalse(n, lFalse)
1816
+ c.emit("JMP", c.lab(labelTrue))
1817
+ c.label(lFalse)
1818
+ }
1819
+
1820
+ // ---------------- 入口 ----------------
1821
+
1822
+ // Compile 编译 CIN 源码字符串, 返回 IR 程序。
1823
+ func Compile(source, filename string, bounds bool) (*ir.Program, error) {
1824
+ c := newCompiler(filename, bounds)
1825
+ toks, err := tokenize(source, filename)
1826
+ if err != nil {
1827
+ return nil, err
1828
+ }
1829
+ p := &parser{toks: toks, filename: filename}
1830
+ structs, globals, functions, funcOrder, err := p.parseProgram()
1831
+ if err != nil {
1832
+ return nil, err
1833
+ }
1834
+ c.structs = structs
1835
+ c.globals = globals
1836
+ c.functions = functions
1837
+
1838
+ c.layoutGlobals(globals)
1839
+ c.emitGlobalsInit(globals)
1840
+ c.emit("CALL", c.lab("main"))
1841
+ c.emit("HALT")
1842
+ for _, name := range funcOrder {
1843
+ c.genFunctionBody(functions[name])
1844
+ }
1845
+ if c.err != nil {
1846
+ return nil, c.err
1847
+ }
1848
+ return c.res, nil
1849
+ }
1850
+
1851
+ var importRe = regexp.MustCompile(`^import\s+["']([^"']+)["']\s*;?\s*$`)
1852
+
1853
+ // CompileFile 读取 .cin 文件并展开 import, 然后编译。
1854
+ func CompileFile(path, libDir string) (*ir.Program, error) {
1855
+ source, err := loadProgramSource(path, libDir)
1856
+ if err != nil {
1857
+ return nil, err
1858
+ }
1859
+ return Compile(source, path, false)
1860
+ }
1861
+
1862
+ func loadProgramSource(path, libDir string) (string, error) {
1863
+ real, err := filepath.Abs(path)
1864
+ if err != nil {
1865
+ return "", err
1866
+ }
1867
+ real, err = filepath.EvalSymlinks(real)
1868
+ if err != nil {
1869
+ real, _ = filepath.Abs(path)
1870
+ }
1871
+ var out []string
1872
+ loaded := map[string]bool{}
1873
+ active := map[string]bool{}
1874
+ var collect func(string) error
1875
+ collect = func(rp string) error {
1876
+ key := rp
1877
+ if active[key] {
1878
+ return fmt.Errorf("Circular import: %s", rp)
1879
+ }
1880
+ if loaded[key] {
1881
+ return nil
1882
+ }
1883
+ active[key] = true
1884
+ defer delete(active, key)
1885
+ data, err := os.ReadFile(rp)
1886
+ if err != nil {
1887
+ return err
1888
+ }
1889
+ // 去掉 BOM: Windows 编辑器写出的 .cin 带 EF BB BF 时, 首行 `import ...`
1890
+ // 匹配不上 importRe, 会报与真实原因无关的解析错误。
1891
+ text := strings.TrimPrefix(strings.ReplaceAll(string(data), "\r\n", "\n"), "\ufeff")
1892
+ for _, line := range strings.Split(text, "\n") {
1893
+ m := importRe.FindStringSubmatch(line)
1894
+ if m != nil {
1895
+ target := m[1]
1896
+ var candidates []string
1897
+ candidates = append(candidates, filepath.Join(filepath.Dir(rp), target))
1898
+ if libDir != "" {
1899
+ candidates = append(candidates, filepath.Join(libDir, target))
1900
+ }
1901
+ if filepath.Base(libDir) == "lib" {
1902
+ candidates = append(candidates, filepath.Join(filepath.Dir(libDir), target))
1903
+ }
1904
+ resolved := ""
1905
+ for _, cand := range candidates {
1906
+ if fi, e := os.Stat(cand); e == nil && !fi.IsDir() {
1907
+ resolved = cand
1908
+ break
1909
+ }
1910
+ }
1911
+ if resolved == "" {
1912
+ return fmt.Errorf("Import file not found: %q", target)
1913
+ }
1914
+ rr, e := filepath.Abs(resolved)
1915
+ if e == nil {
1916
+ if r2, e2 := filepath.EvalSymlinks(rr); e2 == nil {
1917
+ rr = r2
1918
+ }
1919
+ }
1920
+ if err := collect(rr); err != nil {
1921
+ return err
1922
+ }
1923
+ continue
1924
+ }
1925
+ out = append(out, line)
1926
+ }
1927
+ loaded[key] = true
1928
+ return nil
1929
+ }
1930
+ if err := collect(real); err != nil {
1931
+ return "", err
1932
+ }
1933
+ return strings.Join(out, "\n"), nil
1934
+ }
1935
+
1936
+ // 让 unused import 不报错 (math 等)。
1937
+ var _ = math.Float64bits
1938
+ var _ = os.Stat