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,86 @@
1
+ // Code generated by script/gen_native_isa.py from codecin/isa.py; DO NOT EDIT.
2
+ // 单一事实来源: codecin/isa.py Syscall 常量.
3
+
4
+ package compiler
5
+
6
+ // SYS 功能号 (与 isa.py Syscall 一致; 编译器以 SysXXX 引用)。
7
+ const SysSQRT = 0
8
+ const SysPOW = 1
9
+ const SysABS = 2
10
+ const SysSIN = 3
11
+ const SysCOS = 4
12
+ const SysTAN = 5
13
+ const SysFADD = 6
14
+ const SysFSUB = 7
15
+ const SysFMUL = 8
16
+ const SysFDIV = 9
17
+ const SysFCMP = 10
18
+ const SysFTOI = 11
19
+ const SysITOF = 12
20
+ const SysRAND = 13
21
+ const SysSRAND = 14
22
+ const SysTIME = 15
23
+ const SysSTRLEN = 16
24
+ const SysSTRCMP = 17
25
+ const SysSTRCPY = 18
26
+ const SysSTRCAT = 19
27
+ const SysMALLOC = 20
28
+ const SysPRINT_FLOAT = 21
29
+ const SysITOA = 22
30
+ const SysFTOA = 23
31
+ const SysPRINT_STR = 24
32
+ const SysSTR_CONCAT = 25
33
+ const SysBOOL_STR = 26
34
+ const SysABORT = 27
35
+ const SysSUBSTR = 28
36
+ const SysINDEXOF = 29
37
+ const SysTOUPPER = 30
38
+ const SysTOLOWER = 31
39
+ const SysFLOOR = 32
40
+ const SysCEIL = 33
41
+ const SysROUND = 34
42
+ const SysATOI = 35
43
+ const SysTRIM = 36
44
+ const SysLTRIM = 37
45
+ const SysRTRIM = 38
46
+ const SysAUDIOPLAY = 39
47
+ const SysAUDIOSTOP = 40
48
+ const SysAUDIOVOL = 41
49
+ const SysAUDIOWAIT = 42
50
+ const SysCANVASNEW = 43
51
+ const SysCANVASSET = 44
52
+ const SysCANVASRECT = 45
53
+ const SysCANVASCIRC = 46
54
+ const SysCANVASTEXT = 47
55
+ const SysCANVASLINE = 48
56
+ const SysCANVASSAVE = 49
57
+ const SysCANVASSHOW = 50
58
+ const SysFILEREAD = 51
59
+ const SysFILEWRITE = 52
60
+ const SysFILEAPPEND = 53
61
+ const SysFILEEXISTS = 54
62
+ const SysFILEDELETE = 55
63
+ const SysFILESIZE = 56
64
+ const SysMKDIR = 57
65
+ const SysDIRLIST = 58
66
+ const SysEXEC = 59
67
+ const SysEXECOUTPUT = 60
68
+ const SysGETENV = 61
69
+ const SysSETENV = 62
70
+ const SysOSNAME = 63
71
+ const SysHOSTNAME = 64
72
+ const SysUSERNAME = 65
73
+ const SysCWD = 66
74
+ const SysHOMEDIR = 67
75
+ const SysTERMUXAVAIL = 68
76
+ const SysTERMUXNOTIFY = 69
77
+ const SysTERMUXTOAST = 70
78
+ const SysTERMUXCLIPGET = 71
79
+ const SysTERMUXCLIPSET = 72
80
+ const SysTERMUXBATTERY = 73
81
+ const SysTERMUXVIBRATE = 74
82
+ const SysTERMUXTTS = 75
83
+ const SysTERMUXLOCATION = 76
84
+ const SysTERMUXWIFI = 77
85
+ const SysTERMUXDIALOG = 78
86
+ const SysTERMUXSMS = 79
@@ -0,0 +1,336 @@
1
+ package compiler
2
+
3
+ import (
4
+ "fmt"
5
+ "strconv"
6
+ "strings"
7
+ )
8
+
9
+ // ---------------- 词法分析 ----------------
10
+
11
+ // Token 词法单元。
12
+ type Token struct {
13
+ kind string
14
+ ival int64
15
+ fval float64
16
+ isFloat bool
17
+ sval string
18
+ line int
19
+ filename string
20
+ }
21
+
22
+ var keywords = map[string]bool{
23
+ "struct": true, "function": true, "return": true, "if": true, "else": true,
24
+ "while": true, "for": true, "do": true, "switch": true, "case": true,
25
+ "default": true, "break": true, "continue": true, "true": true, "false": true,
26
+ "int": true, "float": true, "bool": true, "string": true, "void": true,
27
+ "char": true, "short": true, "long": true, "unsigned": true,
28
+ "set": true, "add": true, "subtract": true, "multiply": true, "divide": true,
29
+ "increment": true, "decrement": true,
30
+ }
31
+
32
+ var baseTypeWords = map[string]bool{
33
+ "int": true, "float": true, "bool": true, "string": true,
34
+ "char": true, "short": true, "long": true, "unsigned": true,
35
+ }
36
+
37
+ var compoundAssign = map[string]string{
38
+ "PLUSEQ": "+=", "MINUSEQ": "-=", "STAREQ": "*=", "SLASHEQ": "/=",
39
+ "PERCENTEQ": "%=", "ANDEQ": "&=", "OREQ": "|=", "XOREQ": "^=",
40
+ "SHLEQ": "<<=", "SHREQ": ">>=",
41
+ }
42
+
43
+ var singleOps = map[byte]string{
44
+ '{': "LBRACE", '}': "RBRACE", '(': "LPAREN", ')': "RPAREN",
45
+ '[': "LBRACKET", ']': "RBRACKET", ',': "COMMA", ';': "SEMI",
46
+ '+': "PLUS", '-': "MINUS", '*': "STAR", '/': "SLASH", '%': "PERCENT",
47
+ '=': "ASSIGN", '<': "LT", '>': "GT", '!': "BANG", '.': "DOT",
48
+ '?': "QUESTION", ':': "COLON", '&': "AMP", '|': "PIPE", '^': "CARET",
49
+ '~': "TILDE",
50
+ }
51
+
52
+ var strEscapes = map[byte]byte{
53
+ 'n': '\n', 't': '\t', 'r': '\r', '"': '"', '\\': '\\', '0': 0,
54
+ }
55
+
56
+ // tokenize 把 CIN 源码切分为 token 流 (含续行处理与 BOM 容忍)。
57
+ func tokenize(source, filename string) ([]Token, error) {
58
+ source = strings.TrimPrefix(source, "\ufeff") // 容忍 UTF-8 BOM
59
+ var tokens []Token
60
+ i, line, n := 0, 1, len(source)
61
+
62
+ skipBlock := func() {
63
+ i += 2
64
+ for i < n-1 && !(source[i] == '*' && source[i+1] == '/') {
65
+ if source[i] == '\n' {
66
+ line++
67
+ }
68
+ i++
69
+ }
70
+ i += 2
71
+ }
72
+
73
+ for i < n {
74
+ c := source[i]
75
+ switch {
76
+ case c == '\n':
77
+ tokens = append(tokens, Token{kind: "NL", line: line})
78
+ line++
79
+ i++
80
+ case c == ' ' || c == '\t' || c == '\r':
81
+ i++
82
+ case c == '/' && i+1 < n && source[i+1] == '/':
83
+ for i < n && source[i] != '\n' {
84
+ i++
85
+ }
86
+ case c == '/' && i+1 < n && source[i+1] == '*':
87
+ skipBlock()
88
+ case c == '"':
89
+ startLine := line
90
+ i++
91
+ var buf strings.Builder
92
+ for i < n && source[i] != '"' {
93
+ if source[i] == '\\' && i+1 < n {
94
+ esc := source[i+1]
95
+ if b, ok := strEscapes[esc]; ok {
96
+ buf.WriteByte(b)
97
+ } else {
98
+ buf.WriteByte(esc)
99
+ }
100
+ i += 2
101
+ } else {
102
+ if source[i] == '\n' {
103
+ line++
104
+ }
105
+ buf.WriteByte(source[i])
106
+ i++
107
+ }
108
+ }
109
+ i++ // closing quote
110
+ tokens = append(tokens, Token{kind: "STRING", sval: buf.String(), line: startLine})
111
+ case c >= '0' && c <= '9' || (c == '.' && i+1 < n && source[i+1] >= '0' && source[i+1] <= '9'):
112
+ start := i
113
+ isFloat := false
114
+ if c == '0' && i+1 < n && strings.IndexByte("xXbBoO", source[i+1]) >= 0 {
115
+ baseChar := source[i+1]
116
+ var base int
117
+ var allowed string
118
+ switch baseChar {
119
+ case 'x', 'X':
120
+ base, allowed = 16, "0123456789abcdefABCDEF_"
121
+ case 'b', 'B':
122
+ base, allowed = 2, "01_"
123
+ default:
124
+ base, allowed = 8, "01234567_"
125
+ }
126
+ i += 2
127
+ dstart := i
128
+ for i < n && strings.IndexByte(allowed, source[i]) >= 0 {
129
+ i++
130
+ }
131
+ digits := source[dstart:i]
132
+ hasDigit := false
133
+ for _, ch := range digits {
134
+ if ch != '_' {
135
+ hasDigit = true
136
+ break
137
+ }
138
+ }
139
+ if i == dstart || !hasDigit {
140
+ return nil, fmt.Errorf("Malformed numeric literal at line %d", line)
141
+ }
142
+ for i < n && strings.IndexByte("uUlL", source[i]) >= 0 {
143
+ i++
144
+ }
145
+ if i < n && (source[i] == 'f' || source[i] == 'F') {
146
+ isFloat = true
147
+ i++
148
+ }
149
+ clean := strings.ReplaceAll(digits, "_", "")
150
+ v, err := strconv.ParseUint(clean, base, 64)
151
+ if err != nil {
152
+ return nil, fmt.Errorf("Malformed numeric literal at line %d", line)
153
+ }
154
+ _ = start
155
+ if isFloat {
156
+ tokens = append(tokens, Token{kind: "FLOAT", fval: float64(v), isFloat: true, line: line})
157
+ } else {
158
+ tokens = append(tokens, Token{kind: "NUMBER", ival: int64(v), line: line})
159
+ }
160
+ } else {
161
+ for i < n && (source[i] >= '0' && source[i] <= '9' || source[i] == '.' || source[i] == '_') {
162
+ if source[i] == '.' {
163
+ isFloat = true
164
+ }
165
+ i++
166
+ }
167
+ if i < n && (source[i] == 'e' || source[i] == 'E') {
168
+ isFloat = true
169
+ i++
170
+ if i < n && (source[i] == '+' || source[i] == '-') {
171
+ i++
172
+ }
173
+ for i < n && (source[i] >= '0' && source[i] <= '9' || source[i] == '_') {
174
+ i++
175
+ }
176
+ }
177
+ digits := source[start:i]
178
+ for i < n && strings.IndexByte("uUlL", source[i]) >= 0 {
179
+ i++
180
+ }
181
+ if i < n && (source[i] == 'f' || source[i] == 'F') {
182
+ isFloat = true
183
+ i++
184
+ }
185
+ text := strings.ReplaceAll(digits, "_", "")
186
+ if isFloat {
187
+ f, err := strconv.ParseFloat(text, 64)
188
+ if err != nil {
189
+ return nil, fmt.Errorf("Malformed numeric literal at line %d", line)
190
+ }
191
+ tokens = append(tokens, Token{kind: "FLOAT", fval: f, isFloat: true, line: line})
192
+ } else {
193
+ iv, err := strconv.ParseInt(text, 10, 64)
194
+ if err != nil {
195
+ return nil, fmt.Errorf("Malformed numeric literal at line %d", line)
196
+ }
197
+ tokens = append(tokens, Token{kind: "NUMBER", ival: iv, line: line})
198
+ }
199
+ }
200
+ case c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_':
201
+ start := i
202
+ for i < n && (isAlnum(source[i]) || source[i] == '_') {
203
+ i++
204
+ }
205
+ tokens = append(tokens, Token{kind: "IDENT", sval: source[start:i], line: line})
206
+ case c == '-' && i+1 < n && source[i+1] == '>':
207
+ tokens = append(tokens, Token{kind: "ARROW", sval: "->", line: line})
208
+ i += 2
209
+ case c == '\'':
210
+ startLine := line
211
+ i++
212
+ if i >= n {
213
+ return nil, fmt.Errorf("Unterminated char literal at line %d", startLine)
214
+ }
215
+ var val int64
216
+ if source[i] == '\\' && i+1 < n {
217
+ esc := source[i+1]
218
+ escMap := map[byte]int64{'n': 10, 't': 9, 'r': 13, '0': 0, 'a': 7, 'b': 8,
219
+ 'f': 12, 'v': 11, '\'': 39, '"': 34, '\\': 92}
220
+ if v, ok := escMap[esc]; ok {
221
+ val = v
222
+ } else {
223
+ val = int64(esc)
224
+ }
225
+ i += 2
226
+ } else {
227
+ val = int64(source[i])
228
+ i++
229
+ }
230
+ if i >= n || source[i] != '\'' {
231
+ return nil, fmt.Errorf("Unterminated char literal at line %d", startLine)
232
+ }
233
+ i++
234
+ tokens = append(tokens, Token{kind: "NUMBER", ival: val, line: line})
235
+ default:
236
+ if strings.IndexByte("+-*/%", c) >= 0 && i+1 < n && source[i+1] == '=' {
237
+ kindMap := map[byte]string{'+': "PLUSEQ", '-': "MINUSEQ", '*': "STAREQ",
238
+ '/': "SLASHEQ", '%': "PERCENTEQ"}
239
+ tokens = append(tokens, Token{kind: kindMap[c], sval: string(c) + "=", line: line})
240
+ i += 2
241
+ } else if strings.IndexByte("&|^", c) >= 0 && i+1 < n && source[i+1] == '=' {
242
+ kindMap := map[byte]string{'&': "ANDEQ", '|': "OREQ", '^': "XOREQ"}
243
+ tokens = append(tokens, Token{kind: kindMap[c], sval: string(c) + "=", line: line})
244
+ i += 2
245
+ } else if (c == '<' || c == '>') && i+2 < n && source[i+1] == c && source[i+2] == '=' {
246
+ k := "SHLEQ"
247
+ if c == '>' {
248
+ k = "SHREQ"
249
+ }
250
+ tokens = append(tokens, Token{kind: k, sval: string(c) + string(c) + "=", line: line})
251
+ i += 3
252
+ } else if (c == '<' || c == '>') && i+1 < n && source[i+1] == c {
253
+ k := "SHL"
254
+ if c == '>' {
255
+ k = "SHR"
256
+ }
257
+ tokens = append(tokens, Token{kind: k, sval: string(c) + string(c), line: line})
258
+ i += 2
259
+ } else if c == '+' && i+1 < n && source[i+1] == '+' {
260
+ tokens = append(tokens, Token{kind: "INC", sval: "++", line: line})
261
+ i += 2
262
+ } else if c == '-' && i+1 < n && source[i+1] == '-' {
263
+ tokens = append(tokens, Token{kind: "DEC", sval: "--", line: line})
264
+ i += 2
265
+ } else if c == '=' && i+1 < n && source[i+1] == '=' {
266
+ tokens = append(tokens, Token{kind: "EQ", sval: "==", line: line})
267
+ i += 2
268
+ } else if c == '!' && i+1 < n && source[i+1] == '=' {
269
+ tokens = append(tokens, Token{kind: "NEQ", sval: "!=", line: line})
270
+ i += 2
271
+ } else if c == '<' && i+1 < n && source[i+1] == '=' {
272
+ tokens = append(tokens, Token{kind: "LE", sval: "<=", line: line})
273
+ i += 2
274
+ } else if c == '>' && i+1 < n && source[i+1] == '=' {
275
+ tokens = append(tokens, Token{kind: "GE", sval: ">=", line: line})
276
+ i += 2
277
+ } else if c == '&' && i+1 < n && source[i+1] == '&' {
278
+ tokens = append(tokens, Token{kind: "AND", sval: "&&", line: line})
279
+ i += 2
280
+ } else if c == '|' && i+1 < n && source[i+1] == '|' {
281
+ tokens = append(tokens, Token{kind: "OR", sval: "||", line: line})
282
+ i += 2
283
+ } else if k, ok := singleOps[c]; ok {
284
+ tokens = append(tokens, Token{kind: k, sval: string(c), line: line})
285
+ i++
286
+ } else {
287
+ return nil, fmt.Errorf("Unexpected character %q at line %d", c, line)
288
+ }
289
+ }
290
+ }
291
+
292
+ // 续行处理 (圆/方括号内或行尾运算符后的 NL 丢弃)
293
+ var filtered []Token
294
+ depth := 0
295
+ openK := map[string]bool{"LPAREN": true, "LBRACKET": true}
296
+ closeK := map[string]bool{"RPAREN": true, "RBRACKET": true}
297
+ continueOps := map[string]bool{
298
+ "PLUS": true, "MINUS": true, "STAR": true, "SLASH": true, "PERCENT": true,
299
+ "ASSIGN": true, "LT": true, "GT": true, "LE": true, "GE": true, "EQ": true,
300
+ "NEQ": true, "AND": true, "OR": true, "COMMA": true, "ARROW": true, "DOT": true,
301
+ "PLUSEQ": true, "MINUSEQ": true, "STAREQ": true, "SLASHEQ": true,
302
+ "PERCENTEQ": true, "INC": true, "DEC": true, "AMP": true, "PIPE": true,
303
+ "CARET": true, "TILDE": true, "SHL": true, "SHR": true, "ANDEQ": true,
304
+ "OREQ": true, "XOREQ": true, "SHLEQ": true, "SHREQ": true,
305
+ }
306
+ for _, tok := range tokens {
307
+ if openK[tok.kind] {
308
+ depth++
309
+ } else if closeK[tok.kind] {
310
+ if depth > 0 {
311
+ depth--
312
+ }
313
+ }
314
+ if tok.kind == "NL" {
315
+ if depth > 0 {
316
+ continue
317
+ }
318
+ if len(filtered) > 0 {
319
+ prev := filtered[len(filtered)-1]
320
+ if continueOps[prev.kind] {
321
+ continue
322
+ }
323
+ if prev.kind == "NL" {
324
+ continue
325
+ }
326
+ }
327
+ }
328
+ filtered = append(filtered, tok)
329
+ }
330
+ filtered = append(filtered, Token{kind: "EOF", line: line})
331
+ return filtered, nil
332
+ }
333
+
334
+ func isAlnum(c byte) bool {
335
+ return c >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'
336
+ }
@@ -0,0 +1,213 @@
1
+ // Package compiler 是 Code CIN 语言的 Go 版编译器 (Python codecin/cin.py 的忠实移植)。
2
+ // 它将 CIN 源码编译为 ir.Program, 与 Python CINCompiler 的产物逐字节一致。
3
+ package compiler
4
+
5
+ import "codecin-native/ir"
6
+
7
+ // ---------------- 类型系统 ----------------
8
+
9
+ // TypeKind 类型类别。
10
+ type TypeKind uint8
11
+
12
+ const (
13
+ kInt TypeKind = iota
14
+ kFloat
15
+ kBool
16
+ kString
17
+ kVoid
18
+ kStruct
19
+ kArray
20
+ kPtrArray
21
+ )
22
+
23
+ // Type 表示一个 CIN 类型。等价于 Python 侧的元组表示:
24
+ //
25
+ // int/float/bool/string/void -> Kind 对应标量
26
+ // ('struct', Name) -> kStruct
27
+ // ('array', elem, size) -> kArray
28
+ // ('ptrarray', elem) -> kPtrArray
29
+ type Type struct {
30
+ Kind TypeKind
31
+ Elem *Type
32
+ Size int
33
+ Name string
34
+ }
35
+
36
+ func scalarT(k TypeKind) *Type { return &Type{Kind: k} }
37
+
38
+ func isFixedArray(t *Type) bool { return t != nil && t.Kind == kArray }
39
+ func isPtrArray(t *Type) bool { return t != nil && t.Kind == kPtrArray }
40
+ func isStruct(t *Type) bool { return t != nil && t.Kind == kStruct }
41
+ func isScalar(t *Type) bool {
42
+ return t != nil && (t.Kind == kInt || t.Kind == kFloat || t.Kind == kBool ||
43
+ t.Kind == kString || t.Kind == kVoid)
44
+ }
45
+
46
+ func typeSlots(t *Type) int {
47
+ if isFixedArray(t) {
48
+ return t.Size * typeSlots(t.Elem)
49
+ }
50
+ return 1
51
+ }
52
+
53
+ func typeName(t *Type) string {
54
+ if t == nil {
55
+ return "nil"
56
+ }
57
+ switch t.Kind {
58
+ case kInt:
59
+ return "int"
60
+ case kFloat:
61
+ return "float"
62
+ case kBool:
63
+ return "bool"
64
+ case kString:
65
+ return "string"
66
+ case kVoid:
67
+ return "void"
68
+ case kStruct:
69
+ return t.Name
70
+ case kArray:
71
+ return typeName(t.Elem) + "[]"
72
+ case kPtrArray:
73
+ return typeName(t.Elem) + "[]"
74
+ }
75
+ return "?"
76
+ }
77
+
78
+ // ---------------- AST ----------------
79
+
80
+ // Node 是 AST 节点 (等价于 Python 侧的位置元组)。
81
+ type Node struct {
82
+ Kind string // num/bool/str/var/call/binop/not/bitnot/neg/preinc/predec/postinc/postdec/cond/member/index
83
+ // block/return/if/while/for/dowhile/switch/break/continue/decl/cpu/assert/expr
84
+ // declitem/case/arraylit
85
+ Num float64
86
+ Ival int64
87
+ IsFloat bool
88
+ Bool bool
89
+ Str string
90
+ Name string
91
+ Op string
92
+ A, B, C, D *Node
93
+ List []*Node
94
+ Int int
95
+ Type *Type
96
+ Filename string
97
+ // 数组字面量: Is2D=false 时 ArrayLit[0] 为元素; Is2D=true 时 ArrayLit 为行。
98
+ ArrayLit [][]*Node
99
+ Is2D bool
100
+ // cpu 语句操作数 (kind, value) 对。
101
+ Operands [][2]string
102
+ }
103
+
104
+ // DeclItem 一条变量声明 (name, type, init, arrayLit)。
105
+ type DeclItem struct {
106
+ Name string
107
+ Type *Type
108
+ Init *Node
109
+ ArrayLit *Node
110
+ }
111
+
112
+ // SwitchBranch 一个 switch 分支 ('case', constExpr|nil, stmts)。
113
+ type SwitchBranch struct {
114
+ Const *Node // nil = default
115
+ Stmts []*Node
116
+ }
117
+
118
+ // ---------------- 编译上下文 ----------------
119
+
120
+ // compiler 持有整个编译过程的可变状态。
121
+ type compiler struct {
122
+ // 词法/语法产物
123
+ structs map[string]*StructDef
124
+ functions map[string]*FuncDef
125
+ globals []*GlobalVar
126
+
127
+ // 代码生成状态
128
+ res *ir.Program
129
+ dataPtr int
130
+ heapStr map[string]int
131
+ filename string
132
+ bounds bool
133
+
134
+ // err 是粘性的首个编译错误 (语义错误不再被静默吞掉, 由 Compile 统一返回)。
135
+ // 见 docs/SUGGESTIONS.md §3.1.4: 旧实现在语义错误分支只 return/continue,
136
+ // 会漏发射指令并带着上一次的 x0 继续生成, 产出静默错误的字节码。
137
+ err error
138
+
139
+ // 函数生成上下文
140
+ funcDef *FuncDef
141
+ locals map[string]localVar
142
+ frameBytes int
143
+ breakLbls []string
144
+ continueLbls []string
145
+ labelCounter int
146
+ globalsSym map[string]globalVar
147
+ }
148
+
149
+ type localVar struct {
150
+ t *Type
151
+ off int
152
+ isBlock bool
153
+ }
154
+
155
+ type globalVar struct {
156
+ t *Type
157
+ addr int
158
+ isBlock bool
159
+ }
160
+
161
+ // StructDef struct 定义。
162
+ type StructDef struct {
163
+ name string
164
+ fields []fieldDef
165
+ offsets map[string]int
166
+ sizeSlots int
167
+ }
168
+
169
+ type fieldDef struct {
170
+ name string
171
+ t *Type
172
+ }
173
+
174
+ // FuncDef 函数定义。
175
+ type FuncDef struct {
176
+ name string
177
+ params []paramDef
178
+ retType *Type
179
+ body []*Node
180
+ line int
181
+ }
182
+
183
+ type paramDef struct {
184
+ name string
185
+ t *Type
186
+ }
187
+
188
+ // GlobalVar 全局变量。
189
+ type GlobalVar struct {
190
+ name string
191
+ t *Type
192
+ addr int
193
+ init *Node
194
+ arrayLit *Node
195
+ }
196
+
197
+ // newCompiler 构建编译器。
198
+ func newCompiler(filename string, bounds bool) *compiler {
199
+ return &compiler{
200
+ structs: map[string]*StructDef{},
201
+ functions: map[string]*FuncDef{},
202
+ globals: []*GlobalVar{},
203
+ res: &ir.Program{
204
+ Labels: map[string]int{},
205
+ DataLabels: map[string]int{},
206
+ },
207
+ heapStr: map[string]int{},
208
+ filename: filename,
209
+ bounds: bounds,
210
+ locals: map[string]localVar{},
211
+ globalsSym: map[string]globalVar{},
212
+ }
213
+ }