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.
- codecin/__init__.py +27 -0
- codecin/aot.py +229 -0
- codecin/assembler.py +548 -0
- codecin/cache.py +71 -0
- codecin/cin.py +2558 -0
- codecin/cli.py +282 -0
- codecin/config.py +58 -0
- codecin/console.py +183 -0
- codecin/cpu.py +1654 -0
- codecin/crom.py +222 -0
- codecin/debugger.py +659 -0
- codecin/disasm.py +86 -0
- codecin/errors.py +58 -0
- codecin/isa.py +457 -0
- codecin/jit.py +270 -0
- codecin/libcodecin_native.so +0 -0
- codecin/logger.py +145 -0
- codecin/memory.py +348 -0
- codecin/native/aot/aot.go +70 -0
- codecin/native/aot/build.go +219 -0
- codecin/native/aot/stub_main.go.txt +22 -0
- codecin/native/build.ps1 +33 -0
- codecin/native/build.sh +48 -0
- codecin/native/cmd/codecin/main.go +287 -0
- codecin/native/compiler/codegen.go +1938 -0
- codecin/native/compiler/compile_test.go +164 -0
- codecin/native/compiler/parser.go +1071 -0
- codecin/native/compiler/syscalls.go +86 -0
- codecin/native/compiler/tokenizer.go +336 -0
- codecin/native/compiler/types.go +213 -0
- codecin/native/engine/audio.go +152 -0
- codecin/native/engine/audio_other.go +46 -0
- codecin/native/engine/audio_windows.go +43 -0
- codecin/native/engine/canvas.go +271 -0
- codecin/native/engine/crom.go +86 -0
- codecin/native/engine/encode.go +93 -0
- codecin/native/engine/engine_test.go +198 -0
- codecin/native/engine/isa_gen.go +445 -0
- codecin/native/engine/system.go +190 -0
- codecin/native/engine/termux.go +113 -0
- codecin/native/engine/version_gen.go +7 -0
- codecin/native/engine/vm.go +1157 -0
- codecin/native/go.mod +3 -0
- codecin/native/ir/ir.go +48 -0
- codecin/native/main.go +225 -0
- codecin/native.py +336 -0
- codecin/registers.py +130 -0
- codecin/stats.py +235 -0
- codecin-5.4.2.dist-info/METADATA +985 -0
- codecin-5.4.2.dist-info/RECORD +54 -0
- codecin-5.4.2.dist-info/WHEEL +5 -0
- codecin-5.4.2.dist-info/entry_points.txt +2 -0
- codecin-5.4.2.dist-info/licenses/LICENSE +7 -0
- 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
|
+
}
|